@corp-products/ui-components 3.5.8 → 3.6.0
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/.storybook/main.ts +12 -0
- package/debug-storybook.log +53 -0
- package/ng-package.json +7 -0
- package/package.json +25 -36
- package/src/enums/date-formatter.ts +22 -0
- package/src/helper/date-handler.ts +142 -0
- package/src/lib/alert-dialog/alert-dialog.component.html +22 -0
- package/src/lib/alert-dialog/alert-dialog.component.scss +0 -0
- package/src/lib/alert-dialog/alert-dialog.component.spec.ts +22 -0
- package/src/lib/alert-dialog/alert-dialog.component.ts +44 -0
- package/src/lib/alert-dialog/alert-dialog.interface.ts +6 -0
- package/src/lib/alert-dialog/alert-dialog.service.ts +33 -0
- package/src/lib/app-accordion/app-accordion.component.html +15 -0
- package/src/lib/app-accordion/app-accordion.component.scss +0 -0
- package/src/lib/app-accordion/app-accordion.component.spec.ts +21 -0
- package/src/lib/app-accordion/app-accordion.component.ts +21 -0
- package/src/lib/app-accordion/index.ts +2 -0
- package/src/lib/app-breadcrumb/app-breadcrumb.component.html +7 -0
- package/src/lib/app-breadcrumb/app-breadcrumb.component.scss +25 -0
- package/src/lib/app-breadcrumb/app-breadcrumb.component.ts +140 -0
- package/src/lib/app-breadcrumb/app-breadcrumb.interface.ts +15 -0
- package/src/lib/app-button/app-button.component.html +7 -0
- package/src/lib/app-button/app-button.component.scss +0 -0
- package/src/lib/app-button/app-button.component.ts +14 -0
- package/src/lib/app-button/app-button.ts +15 -0
- package/src/lib/app-button/index.ts +2 -0
- package/src/lib/app-dropdown-menu/app-dropdown-menu.component.html +22 -0
- package/src/lib/app-dropdown-menu/app-dropdown-menu.component.scss +39 -0
- package/src/lib/app-dropdown-menu/app-dropdown-menu.component.spec.ts +21 -0
- package/src/lib/app-dropdown-menu/app-dropdown-menu.component.ts +43 -0
- package/src/lib/app-dropdown-menu/app-dropdown-menu.ts +17 -0
- package/src/lib/app-dropdown-menu/index.ts +2 -0
- package/src/lib/app-dropdown-menu/menu-popup.pipe.ts +18 -0
- package/src/lib/app-header/app-header.component.html +26 -0
- package/src/lib/app-header/app-header.component.scss +0 -0
- package/src/lib/app-header/app-header.component.ts +43 -0
- package/src/lib/app-side-menu/app-side-menu.component.html +20 -0
- package/src/lib/app-side-menu/app-side-menu.component.ts +28 -0
- package/src/lib/app-side-menu/routes-names.ts +28 -0
- package/src/lib/app-side-menu/side-menu-items.ts +45 -0
- package/src/lib/app-side-menu/side-menu.ts +12 -0
- package/src/lib/app-tabs/app-tab.interface.ts +27 -0
- package/src/lib/app-tabs/app-tabs.component.html +37 -0
- package/src/lib/app-tabs/app-tabs.component.scss +103 -0
- package/src/lib/app-tabs/app-tabs.component.spec.ts +21 -0
- package/src/lib/app-tabs/app-tabs.component.ts +67 -0
- package/src/lib/app-tabs/index.ts +2 -0
- package/src/lib/bottom-sheet/bottom-sheet.component.html +18 -0
- package/src/lib/bottom-sheet/bottom-sheet.component.scss +31 -0
- package/src/lib/bottom-sheet/bottom-sheet.component.ts +26 -0
- package/src/lib/confirmation-dialog/confirmation-dialog.component.html +37 -0
- package/src/lib/confirmation-dialog/confirmation-dialog.component.scss +0 -0
- package/src/lib/confirmation-dialog/confirmation-dialog.component.spec.ts +22 -0
- package/src/lib/confirmation-dialog/confirmation-dialog.component.ts +64 -0
- package/src/lib/confirmation-dialog/confirmation-dialog.interface.ts +13 -0
- package/src/lib/confirmation-dialog/confirmation-dialog.service.ts +34 -0
- package/src/lib/dual-calender/date-picker-switcher/date-picker-switcher.component.html +27 -0
- package/src/lib/dual-calender/date-picker-switcher/date-picker-switcher.component.scss +22 -0
- package/src/lib/dual-calender/date-picker-switcher/date-picker-switcher.component.ts +64 -0
- package/src/lib/dual-calender/dual-calendar.component.html +30 -0
- package/src/lib/dual-calender/dual-calendar.component.scss +265 -0
- package/src/lib/dual-calender/dual-calendar.component.ts +157 -0
- package/src/lib/dual-calender/gregorian-calendar/gregorian-calendar.component.html +21 -0
- package/src/lib/dual-calender/gregorian-calendar/gregorian-calendar.component.scss +0 -0
- package/src/lib/dual-calender/gregorian-calendar/gregorian-calendar.component.spec.ts +21 -0
- package/src/lib/dual-calender/gregorian-calendar/gregorian-calendar.component.ts +65 -0
- package/src/lib/dual-calender/hijri-calendar/hijri-calendar.component.html +10 -0
- package/src/lib/dual-calender/hijri-calendar/hijri-calendar.component.scss +0 -0
- package/src/lib/dual-calender/hijri-calendar/hijri-calendar.component.spec.ts +21 -0
- package/src/lib/dual-calender/hijri-calendar/hijri-calendar.component.ts +66 -0
- package/src/lib/dual-calender/services/gregorian-i18n.service.ts +123 -0
- package/src/lib/dual-calender/services/islamic-i18n.service.ts +119 -0
- package/src/lib/dual-calender/utils/date-i18n.utils.ts +58 -0
- package/src/lib/dynamic-form/dynamic-form.component.html +84 -0
- package/src/lib/dynamic-form/dynamic-form.component.scss +0 -0
- package/src/lib/dynamic-form/dynamic-form.component.spec.ts +21 -0
- package/src/lib/dynamic-form/dynamic-form.component.ts +58 -0
- package/src/lib/dynamic-form/dynamic-form.interface.ts +96 -0
- package/src/lib/dynamic-side-bar-v2/dynamic-sidebar.component.html +32 -0
- package/src/lib/dynamic-side-bar-v2/dynamic-sidebar.component.scss +3 -0
- package/src/lib/dynamic-side-bar-v2/dynamic-sidebar.component.ts +82 -0
- package/src/lib/dynamic-side-bar-v2/dynamic-sidebar.config.ts +31 -0
- package/src/lib/dynamic-side-bar-v2/dynamic-sidebar.service.ts +41 -0
- package/src/lib/form-components/@utils/form-utils.ts +12 -0
- package/src/lib/form-components/@utils/validations/error-keys.enum.ts +25 -0
- package/src/lib/form-components/@utils/validations/form-validation.service.ts +68 -0
- package/src/lib/form-components/@utils/validations/index.ts +4 -0
- package/src/lib/form-components/@utils/validations/numbers-only.validator.ts +10 -0
- package/src/lib/form-components/@utils/validations/validation-message.pipe.ts +24 -0
- package/src/lib/form-components/components/auto-complete/auto-complete.component.html +35 -0
- package/src/lib/form-components/components/auto-complete/auto-complete.component.scss +12 -0
- package/src/lib/form-components/components/auto-complete/auto-complete.component.spec.ts +21 -0
- package/src/lib/form-components/components/auto-complete/auto-complete.component.ts +82 -0
- package/src/lib/form-components/components/base-input.component.ts +35 -0
- package/src/lib/form-components/components/date-picker/date-picker.component.html +40 -0
- package/src/lib/form-components/components/date-picker/date-picker.component.scss +32 -0
- package/src/lib/form-components/components/date-picker/date-picker.component.spec.ts +21 -0
- package/src/lib/form-components/components/date-picker/date-picker.component.ts +81 -0
- package/src/lib/form-components/components/date-picker/date-picker.validator.ts +38 -0
- package/src/lib/form-components/components/input/input.component.html +80 -0
- package/src/lib/form-components/components/input/input.component.scss +46 -0
- package/src/lib/form-components/components/input/input.component.spec.ts +21 -0
- package/src/lib/form-components/components/input/input.component.ts +56 -0
- package/src/lib/form-components/components/select/select.component.html +123 -0
- package/src/lib/form-components/components/select/select.component.scss +53 -0
- package/src/lib/form-components/components/select/select.component.spec.ts +21 -0
- package/src/lib/form-components/components/select/select.component.ts +87 -0
- package/src/lib/form-components/components/select-button/select-button.component.html +21 -0
- package/src/lib/form-components/components/select-button/select-button.component.scss +0 -0
- package/src/lib/form-components/components/select-button/select-button.component.spec.ts +21 -0
- package/src/lib/form-components/components/select-button/select-button.component.ts +22 -0
- package/src/lib/form-components/components/switcher/switch.component.html +5 -0
- package/src/lib/form-components/components/switcher/switch.component.scss +0 -0
- package/src/lib/form-components/components/switcher/switch.component.spec.ts +21 -0
- package/src/lib/form-components/components/switcher/switch.component.ts +25 -0
- package/src/lib/form-components/index.ts +9 -0
- package/src/lib/form-components/interfaces/index.ts +1 -0
- package/src/lib/form-components/interfaces/label-value.ts +4 -0
- package/src/lib/ico-moon-icon/ico-moon-icon.component.ts +23 -0
- package/src/lib/read-more/read-more.component.html +17 -0
- package/src/lib/read-more/read-more.component.scss +0 -0
- package/src/lib/read-more/read-more.component.spec.ts +21 -0
- package/src/lib/read-more/read-more.component.ts +21 -0
- package/src/lib/side-bar/side-bar.component.html +24 -0
- package/src/lib/side-bar/side-bar.component.scss +22 -0
- package/src/lib/side-bar/side-bar.component.spec.ts +21 -0
- package/src/lib/side-bar/side-bar.component.ts +33 -0
- package/src/lib/side-bar-dynamic/data-injector.pipe.ts +15 -0
- package/src/lib/side-bar-dynamic/dynamic-sidebar.service.ts +116 -0
- package/src/lib/side-bar-dynamic/side-bar-dynamic.component.html +42 -0
- package/src/lib/side-bar-dynamic/side-bar-dynamic.component.scss +5 -0
- package/src/lib/side-bar-dynamic/side-bar-dynamic.component.spec.ts +21 -0
- package/src/lib/side-bar-dynamic/side-bar-dynamic.component.ts +37 -0
- package/src/lib/side-bar-dynamic/side-bar-utils.ts +30 -0
- package/src/lib/side-bar-dynamic/sidebar-config.ts +48 -0
- package/src/lib/user-autocomplete-card/user-autocomplete-card.component.html +20 -0
- package/src/lib/user-autocomplete-card/user-autocomplete-card.component.scss +0 -0
- package/src/lib/user-autocomplete-card/user-autocomplete-card.component.spec.ts +21 -0
- package/src/lib/user-autocomplete-card/user-autocomplete-card.component.ts +21 -0
- package/src/lib/user-info/user-info.component.html +10 -0
- package/src/lib/user-info/user-info.component.ts +11 -0
- package/src/public-api.ts +29 -0
- package/tsconfig.lib.json +18 -0
- package/tsconfig.lib.prod.json +11 -0
- package/tsconfig.spec.json +14 -0
- package/fesm2022/corp-products-ui-components.mjs +0 -2252
- package/fesm2022/corp-products-ui-components.mjs.map +0 -1
- package/index.d.ts +0 -720
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { CommonModule } from '@angular/common';
|
|
2
|
+
import { Component, Input, OnInit, ViewEncapsulation } from '@angular/core';
|
|
3
|
+
import { ActivatedRoute, NavigationEnd, Router, RouterModule } from '@angular/router';
|
|
4
|
+
import { MenuItem } from 'primeng/api';
|
|
5
|
+
import { Breadcrumb } from 'primeng/breadcrumb';
|
|
6
|
+
import { filter } from 'rxjs';
|
|
7
|
+
import { BreadCrumbExtraData, BreadcrumbItem } from './app-breadcrumb.interface';
|
|
8
|
+
|
|
9
|
+
@Component({
|
|
10
|
+
selector: 'app-breadcrumb',
|
|
11
|
+
templateUrl: './app-breadcrumb.component.html',
|
|
12
|
+
styleUrl: './app-breadcrumb.component.scss',
|
|
13
|
+
standalone: true,
|
|
14
|
+
imports: [CommonModule, Breadcrumb, RouterModule],
|
|
15
|
+
encapsulation: ViewEncapsulation.None,
|
|
16
|
+
})
|
|
17
|
+
export class AppBreadcrumbComponent implements OnInit {
|
|
18
|
+
@Input() items: BreadcrumbItem[] | undefined;
|
|
19
|
+
isShown: boolean;
|
|
20
|
+
|
|
21
|
+
constructor(private activatedRoute: ActivatedRoute, private router: Router) {}
|
|
22
|
+
|
|
23
|
+
ngOnInit(): void {
|
|
24
|
+
if (this.items) {
|
|
25
|
+
this.isShown = true;
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
this.router.events.pipe(filter((event) => event instanceof NavigationEnd)).subscribe((e) => {
|
|
29
|
+
// remove duplicates
|
|
30
|
+
this.items = (this._createBreadcrumbs(this.activatedRoute.root) as BreadcrumbItem[]).filter(
|
|
31
|
+
(item, index, self) =>
|
|
32
|
+
index ===
|
|
33
|
+
self.findIndex((t) => t.label === item.label && t.routerLink === item.routerLink)
|
|
34
|
+
);
|
|
35
|
+
this._checkHiddenBreadcrumb();
|
|
36
|
+
this._checkEmpty();
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
private _checkHiddenBreadcrumb() {
|
|
41
|
+
const activeBreadcrumb = this.items?.find((item) => {
|
|
42
|
+
return item.routerLink === this.router.url;
|
|
43
|
+
});
|
|
44
|
+
this.isShown = !!activeBreadcrumb?.isShown;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
private _createBreadcrumbs(
|
|
48
|
+
activatedRoute: ActivatedRoute,
|
|
49
|
+
routerLink = '',
|
|
50
|
+
breadcrumbs: MenuItem[] = []
|
|
51
|
+
): any {
|
|
52
|
+
const children: ActivatedRoute[] = activatedRoute.children;
|
|
53
|
+
|
|
54
|
+
if (children.length === 0) {
|
|
55
|
+
return breadcrumbs;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
for (const child of children) {
|
|
59
|
+
const routeURL: string = child.snapshot.url.map((segment) => segment.path).join('/');
|
|
60
|
+
if (routeURL !== '') {
|
|
61
|
+
routerLink += `/${routeURL}`;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
let label = child.snapshot.data['breadcrumb'];
|
|
65
|
+
const notClickableBreadcrumb = !!child.snapshot.data['notClickableBreadcrumb'];
|
|
66
|
+
const isShown = !!child.snapshot.data['isShown'];
|
|
67
|
+
const extraBreadcrumbs: BreadCrumbExtraData[] = child.snapshot.data['extraBreadcrumbs'] || [];
|
|
68
|
+
if (!(typeof label === 'undefined' || label === null)) {
|
|
69
|
+
const data = activatedRoute.snapshot.firstChild?.data || {};
|
|
70
|
+
// Resolve dynamic breadcrumb label
|
|
71
|
+
if (label && label.startsWith('[') && label.endsWith(']')) {
|
|
72
|
+
label = this._getRecursiveKey(data, label.slice(1, -1).split('.'));
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Resolve dynamic URL parts
|
|
76
|
+
const resolveDynamicUrl = (route: string): string => {
|
|
77
|
+
return route.replace(
|
|
78
|
+
/\[([^\]]+)]/g,
|
|
79
|
+
(_, key) => this._getRecursiveKey(data, key.split('.')) || ''
|
|
80
|
+
);
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const mainBreadcrumb: MenuItem = {
|
|
84
|
+
label,
|
|
85
|
+
routerLink,
|
|
86
|
+
data,
|
|
87
|
+
notClickableBreadcrumb,
|
|
88
|
+
isShown,
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
// Process extra breadcrumbs
|
|
92
|
+
const beforeBreadcrumbs: MenuItem[] = [];
|
|
93
|
+
const afterBreadcrumbs: MenuItem[] = [];
|
|
94
|
+
|
|
95
|
+
extraBreadcrumbs.forEach((extra) => {
|
|
96
|
+
let extraLabel = extra.label || '';
|
|
97
|
+
if (extraLabel.startsWith('[') && extraLabel.endsWith(']')) {
|
|
98
|
+
extraLabel = this._getRecursiveKey(data, extraLabel.slice(1, -1).split('.'));
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const extraUrl = resolveDynamicUrl(extra.routerLink || '');
|
|
102
|
+
|
|
103
|
+
const extraBreadcrumb: MenuItem = { ...extra, label: extraLabel, routerLink: extraUrl };
|
|
104
|
+
|
|
105
|
+
if (extra.position === 'before') {
|
|
106
|
+
beforeBreadcrumbs.push(extraBreadcrumb);
|
|
107
|
+
} else {
|
|
108
|
+
afterBreadcrumbs.push(extraBreadcrumb);
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
// Merge breadcrumbs
|
|
113
|
+
breadcrumbs.push(...beforeBreadcrumbs, mainBreadcrumb, ...afterBreadcrumbs);
|
|
114
|
+
}
|
|
115
|
+
return this._createBreadcrumbs(child, routerLink, breadcrumbs);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
private _checkEmpty() {
|
|
120
|
+
if (!this.items) return;
|
|
121
|
+
const lastBreadcrumbVisibility = this.items[this.items.length - 1].isShown;
|
|
122
|
+
this.items = this.items.filter((b) => b.label !== '');
|
|
123
|
+
this.items[this.items.length - 1].isShown = lastBreadcrumbVisibility;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
private _getRecursiveKey(obj: Record<string, any>, keys: string[]): any | undefined {
|
|
127
|
+
if (keys.length === 0) {
|
|
128
|
+
return undefined;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const [currentKey, ...remainingKeys] = keys;
|
|
132
|
+
if (currentKey in obj) {
|
|
133
|
+
if (remainingKeys.length > 0) {
|
|
134
|
+
return this._getRecursiveKey(obj[currentKey], remainingKeys);
|
|
135
|
+
}
|
|
136
|
+
return obj[currentKey];
|
|
137
|
+
}
|
|
138
|
+
return undefined;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { MenuItem } from 'primeng/api';
|
|
2
|
+
|
|
3
|
+
export interface BreadcrumbItem {
|
|
4
|
+
notClickable: boolean;
|
|
5
|
+
label: string;
|
|
6
|
+
routerLink: string;
|
|
7
|
+
isShown: boolean;
|
|
8
|
+
extraBreadcrumbs?: BreadCrumbExtraData[];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface BreadCrumbPosition {
|
|
12
|
+
position: 'before' | 'after';
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type BreadCrumbExtraData = MenuItem & BreadCrumbPosition;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<p-button (onFocus)="onFocus.emit()" (onBlur)="onBlur.emit()" (onClick)="onClick.emit()" [size]="size"
|
|
2
|
+
[loadingIcon]="loadingIcon" [disabled]="disabled" [iconPos]="iconPos" [icon]="icon" [label]="label"
|
|
3
|
+
[rounded]="rounded" [severity]="severity" [styleClass]="styleClass" [text]="text" [variant]="variant"
|
|
4
|
+
[loading]="loading" [autofocus]="autofocus" [link]="link" [plain]="plain" [raised]="raised"
|
|
5
|
+
[loadingIcon]="loadingIcon" [style]="style" [outlined]="outlined">
|
|
6
|
+
<ng-content></ng-content>
|
|
7
|
+
</p-button>
|
|
File without changes
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Component, Input, ViewEncapsulation } from '@angular/core';
|
|
2
|
+
import { Button, ButtonModule, ButtonStyle } from 'primeng/button';
|
|
3
|
+
|
|
4
|
+
@Component({
|
|
5
|
+
imports: [ButtonModule],
|
|
6
|
+
selector: 'app-button',
|
|
7
|
+
standalone: true,
|
|
8
|
+
encapsulation: ViewEncapsulation.None,
|
|
9
|
+
styleUrl: './app-button.component.scss',
|
|
10
|
+
templateUrl: './app-button.component.html',
|
|
11
|
+
providers: [ButtonStyle],
|
|
12
|
+
})
|
|
13
|
+
export class AppButtonComponent extends Button {
|
|
14
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type AppButtonSeverity =
|
|
2
|
+
| 'success'
|
|
3
|
+
| 'info'
|
|
4
|
+
| 'warn'
|
|
5
|
+
| 'danger'
|
|
6
|
+
| 'help'
|
|
7
|
+
| 'primary'
|
|
8
|
+
| 'secondary'
|
|
9
|
+
| 'contrast';
|
|
10
|
+
|
|
11
|
+
export type AppButtonSize = 'large' | 'small';
|
|
12
|
+
|
|
13
|
+
export type AppButtonIconPos = 'left' | 'right' | 'top' | 'bottom';
|
|
14
|
+
|
|
15
|
+
export type AppButtonVariant = 'outlined' | 'text' | undefined;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
@if (showMenu) {
|
|
2
|
+
<app-button (click)="op.toggle($event)" [class]="buttonClass" [iconPos]="buttonIconPosition" [icon]="buttonIcon"
|
|
3
|
+
[label]="buttonTitle" [styleClass]="buttonStyle" [severity]="buttonSeverity" />
|
|
4
|
+
}
|
|
5
|
+
<p-popover #op [styleClass]="popupMenuStyle === 'white' ? 'white-menu' : 'purple-menu'">
|
|
6
|
+
<div class="flex flex-col gap-4 text-sm md:text-xs">
|
|
7
|
+
<ul>
|
|
8
|
+
@for (item of menuItems; track $index) {
|
|
9
|
+
@if (item.show) {
|
|
10
|
+
<li [ngClass]="{'flex-row-reverse': item.iconPosition === 'right'}"
|
|
11
|
+
[class]="'flex justify-between min-w-[130px] gap-1 items-center cursor-pointer text-sm ' + (item.textColor | popupTextColorClass)"
|
|
12
|
+
(click)="onMenuItemClick(item)">
|
|
13
|
+
{{ item.title | translate }}
|
|
14
|
+
@if (item.icon) {
|
|
15
|
+
<i [class]="item.icon"></i>
|
|
16
|
+
}
|
|
17
|
+
</li>
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
</ul>
|
|
21
|
+
</div>
|
|
22
|
+
</p-popover>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
.p-popover {
|
|
2
|
+
box-shadow: none;
|
|
3
|
+
&:is(.purple-menu) {
|
|
4
|
+
@apply bg-primary text-white text-sm mt-2;
|
|
5
|
+
li:not(:last-child) {
|
|
6
|
+
@apply border-b-2 border-purple-700;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
&:is(.white-menu) {
|
|
10
|
+
li:not(:last-child) {
|
|
11
|
+
@apply border-b;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
border-radius: 3px;
|
|
15
|
+
margin-top: 13px;
|
|
16
|
+
&::before, &::after {
|
|
17
|
+
display: none;
|
|
18
|
+
}
|
|
19
|
+
.p-popover-content {
|
|
20
|
+
width: auto;
|
|
21
|
+
min-width: unset;
|
|
22
|
+
|
|
23
|
+
ul {
|
|
24
|
+
li {
|
|
25
|
+
@apply py-3;
|
|
26
|
+
&:hover {
|
|
27
|
+
opacity: 0.7;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
li:first-child {
|
|
31
|
+
@apply pt-0
|
|
32
|
+
}
|
|
33
|
+
li:last-child {
|
|
34
|
+
@apply pb-0
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
2
|
+
import { AppDropdownMenuComponent } from './app-dropdown-menu.component';
|
|
3
|
+
|
|
4
|
+
describe('AppDropdownMenuComponent', () => {
|
|
5
|
+
let component: AppDropdownMenuComponent;
|
|
6
|
+
let fixture: ComponentFixture<AppDropdownMenuComponent>;
|
|
7
|
+
|
|
8
|
+
beforeEach(async () => {
|
|
9
|
+
await TestBed.configureTestingModule({
|
|
10
|
+
imports: [AppDropdownMenuComponent],
|
|
11
|
+
}).compileComponents();
|
|
12
|
+
|
|
13
|
+
fixture = TestBed.createComponent(AppDropdownMenuComponent);
|
|
14
|
+
component = fixture.componentInstance;
|
|
15
|
+
fixture.detectChanges();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('should create', () => {
|
|
19
|
+
expect(component).toBeTruthy();
|
|
20
|
+
});
|
|
21
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import {Component, inject, Input, OnInit, ViewEncapsulation} from '@angular/core';
|
|
2
|
+
import { AppButtonComponent } from '../app-button';
|
|
3
|
+
import { Popover } from 'primeng/popover';
|
|
4
|
+
import { DropdownMenuItem } from './app-dropdown-menu';
|
|
5
|
+
import {Router} from '@angular/router';
|
|
6
|
+
import {AppButtonIconPos, AppButtonSeverity} from '../app-button';
|
|
7
|
+
import { TranslateModule } from '@ngx-translate/core';
|
|
8
|
+
import {NgClass} from "@angular/common";
|
|
9
|
+
import {MenuPopupTextColorPipe} from "./menu-popup.pipe";
|
|
10
|
+
|
|
11
|
+
@Component({
|
|
12
|
+
selector: "app-dropdown-menu",
|
|
13
|
+
standalone: true,
|
|
14
|
+
imports: [AppButtonComponent, Popover, TranslateModule, NgClass, MenuPopupTextColorPipe],
|
|
15
|
+
templateUrl: "./app-dropdown-menu.component.html",
|
|
16
|
+
styleUrl: "./app-dropdown-menu.component.scss",
|
|
17
|
+
encapsulation: ViewEncapsulation.None
|
|
18
|
+
})
|
|
19
|
+
export class AppDropdownMenuComponent implements OnInit {
|
|
20
|
+
@Input({ required: true }) buttonTitle: string;
|
|
21
|
+
@Input({ required: true }) menuItems: DropdownMenuItem[] = [];
|
|
22
|
+
@Input() popupMenuStyle: "white" | "purple" = "purple";
|
|
23
|
+
@Input() buttonIcon = "font-icon-plus";
|
|
24
|
+
@Input() buttonClass: string;
|
|
25
|
+
@Input() buttonStyle: string;
|
|
26
|
+
@Input() buttonSeverity: AppButtonSeverity;
|
|
27
|
+
@Input() buttonIconPosition: AppButtonIconPos = "left";
|
|
28
|
+
router = inject(Router);
|
|
29
|
+
|
|
30
|
+
showMenu: boolean;
|
|
31
|
+
ngOnInit() {
|
|
32
|
+
this.showMenu = this.menuItems.some((item) => {
|
|
33
|
+
return item.show;
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
onMenuItemClick(item: DropdownMenuItem): void {
|
|
37
|
+
if (item.callback) {
|
|
38
|
+
item.callback();
|
|
39
|
+
} else if (item.routerLink) {
|
|
40
|
+
this.router.navigate(Array.isArray(item.routerLink) ? item.routerLink : [item.routerLink], { queryParams: item.queryParams || {} });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import {Params} from "@angular/router";
|
|
2
|
+
import {AppButtonIconPos} from "../app-button";
|
|
3
|
+
|
|
4
|
+
export interface DropdownMenuItem {
|
|
5
|
+
title: string;
|
|
6
|
+
routerLink?: string;
|
|
7
|
+
queryParams?: Params;
|
|
8
|
+
callback?: () => void;
|
|
9
|
+
icon?: string;
|
|
10
|
+
show?: boolean;
|
|
11
|
+
// TODO: add type
|
|
12
|
+
permissionKey?: string;
|
|
13
|
+
permissionAction?: string;
|
|
14
|
+
iconPosition?: AppButtonIconPos;
|
|
15
|
+
textColor?: DropdownTextColor;
|
|
16
|
+
}
|
|
17
|
+
export type DropdownTextColor = 'white' | 'purple' | 'green';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Pipe, PipeTransform } from '@angular/core';
|
|
2
|
+
import {DropdownTextColor} from "./app-dropdown-menu";
|
|
3
|
+
|
|
4
|
+
@Pipe({
|
|
5
|
+
name: 'popupTextColorClass',
|
|
6
|
+
standalone: true,
|
|
7
|
+
pure: true
|
|
8
|
+
})
|
|
9
|
+
export class MenuPopupTextColorPipe implements PipeTransform {
|
|
10
|
+
transform(color?: DropdownTextColor): string {
|
|
11
|
+
switch (color) {
|
|
12
|
+
case 'white': return 'text-white';
|
|
13
|
+
case 'purple': return 'text-purple-500';
|
|
14
|
+
case 'green': return 'text-green-500';
|
|
15
|
+
default: return 'text-white';
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<div class="px-10 flex justify-between items-center bg-white shadow-md py-3 h-16">
|
|
2
|
+
<div class="d-flex md:hidden w-fit">
|
|
3
|
+
<!-- Burger Icon for Mobile -->
|
|
4
|
+
<app-button icon="font-icon-burger-icon text-[25px]" size="large" variant="text"
|
|
5
|
+
(clickEmitter)="toggleMenu.emit()"/>
|
|
6
|
+
</div>
|
|
7
|
+
<div class="d-flex items-center justify-content-between gap-1">
|
|
8
|
+
<app-button
|
|
9
|
+
*hasPermissions="[PermissionsActions.CREATE];key: UserPermissionsEnum.BOD"
|
|
10
|
+
iconPos="right" icon="font-icon-plus" (clickEmitter)="createButtonClicked.emit()"
|
|
11
|
+
[title]="'actions.create' | translate"/>
|
|
12
|
+
</div>
|
|
13
|
+
|
|
14
|
+
<div class="flex items-center gap-1">
|
|
15
|
+
@if (userInfo) {
|
|
16
|
+
<div class="flex flex-col items-end justify-center">
|
|
17
|
+
<p class="text-sm">{{ userInfo.userName }}</p>
|
|
18
|
+
<p class="text-gray-500 mb-0 text-[10px]">{{ userInfo.email }}</p>
|
|
19
|
+
</div>
|
|
20
|
+
|
|
21
|
+
<img src="assets/images/user-placeholder.jpg" class="w-9 h-9 object-cover rounded-full" alt=""/>
|
|
22
|
+
}
|
|
23
|
+
<p-menu #menu [model]="items" [popup]="true"></p-menu>
|
|
24
|
+
<button (click)="menu.toggle($event)" class="mb-2"><i class="font-icon-Vector text-[6px]"></i></button>
|
|
25
|
+
</div>
|
|
26
|
+
</div>
|
|
File without changes
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Component, EventEmitter, Input, Output, ViewEncapsulation } from '@angular/core';
|
|
2
|
+
import { RouterModule } from '@angular/router';
|
|
3
|
+
import { TranslatePipe } from '@ngx-translate/core';
|
|
4
|
+
import { MenuItem } from 'primeng/api';
|
|
5
|
+
import { Menu } from 'primeng/menu';
|
|
6
|
+
import { AppButtonComponent } from '../app-button';
|
|
7
|
+
|
|
8
|
+
@Component({
|
|
9
|
+
selector: 'app-header',
|
|
10
|
+
templateUrl: './app-header.component.html',
|
|
11
|
+
styleUrl: './app-header.component.scss',
|
|
12
|
+
standalone: true,
|
|
13
|
+
imports: [RouterModule, AppButtonComponent, Menu, TranslatePipe],
|
|
14
|
+
encapsulation: ViewEncapsulation.None,
|
|
15
|
+
})
|
|
16
|
+
export class AppHeaderComponent {
|
|
17
|
+
@Output() createButtonClicked = new EventEmitter();
|
|
18
|
+
@Output() toggleMenu = new EventEmitter<boolean>();
|
|
19
|
+
@Input() userInfo: any;
|
|
20
|
+
items: MenuItem[] | undefined = [
|
|
21
|
+
{
|
|
22
|
+
items: [
|
|
23
|
+
{
|
|
24
|
+
label: 'خــــروج',
|
|
25
|
+
command: () => this.logout(),
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
},
|
|
29
|
+
];
|
|
30
|
+
// UserPermissionsEnum = UserPermissionsEnum;
|
|
31
|
+
// PermissionsActions = PermissionsActions;
|
|
32
|
+
|
|
33
|
+
logout(): void {
|
|
34
|
+
// this.authService
|
|
35
|
+
// .logoutFromSSO()
|
|
36
|
+
// .pipe(
|
|
37
|
+
// finalize(() => {
|
|
38
|
+
// this.authService.clearAuth();
|
|
39
|
+
// })
|
|
40
|
+
// )
|
|
41
|
+
// .subscribe();
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<nav
|
|
2
|
+
[ngClass]="{ 'max-w-0 md:max-w-[500px]': !isOpen, 'max-w-[500px]': isOpen }"
|
|
3
|
+
class="md:flex h-100 bg-primary flex text-white flex-col py-2 text-center gap-y-10 transition-all w-24 hover:md:w-48 duration-500">
|
|
4
|
+
<a [routerLink]="'/'"><i class="font-icon-STC-Logo text-[20px] pt-4 block px-4"></i></a>
|
|
5
|
+
<ul class="flex flex-col flex-grow">
|
|
6
|
+
@for (item of filteredMenu; track $index) {
|
|
7
|
+
<li>
|
|
8
|
+
<a
|
|
9
|
+
[routerLinkActive]="'bg-primary_dark border-secondary'"
|
|
10
|
+
[routerLink]="item.link"
|
|
11
|
+
class="flex flex-col py-3 px-4 border-r-2 border-primary transition-all hover:bg-primary_dark hover:border-secondary">
|
|
12
|
+
<i [class]="item.icon + ' text-[17px] mb-1'"></i>
|
|
13
|
+
<span class="text-[10px] truncate">{{ item.label }}</span>
|
|
14
|
+
</a>
|
|
15
|
+
</li>
|
|
16
|
+
}
|
|
17
|
+
</ul>
|
|
18
|
+
|
|
19
|
+
<a href="#"><i class="font-icon-setting text-[20px] pb-4 block px-4"></i></a>
|
|
20
|
+
</nav>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Component, inject, Input, OnInit, ViewEncapsulation } from "@angular/core";
|
|
2
|
+
import { RouterModule } from "@angular/router";
|
|
3
|
+
import { SideMenuItem } from "./side-menu";
|
|
4
|
+
import { BASE_SIDE_MENU_ITEMS } from "./side-menu-items";
|
|
5
|
+
import { NgClass } from "@angular/common";
|
|
6
|
+
@Component({
|
|
7
|
+
selector: "app-side-menu",
|
|
8
|
+
standalone: true,
|
|
9
|
+
imports: [RouterModule, NgClass],
|
|
10
|
+
templateUrl: "./app-side-menu.component.html",
|
|
11
|
+
encapsulation: ViewEncapsulation.None
|
|
12
|
+
})
|
|
13
|
+
export class AppSideMenuComponent implements OnInit {
|
|
14
|
+
@Input() isOpen!: boolean;
|
|
15
|
+
menuItems: SideMenuItem[] = BASE_SIDE_MENU_ITEMS;
|
|
16
|
+
//permissionsService = inject(PermissionsService);
|
|
17
|
+
filteredMenu: SideMenuItem[];
|
|
18
|
+
|
|
19
|
+
ngOnInit(): void {
|
|
20
|
+
this.filteredMenu = this.menuItems.filter((item) => {
|
|
21
|
+
if (!item.permissionKey) {
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
// return this.permissionsService.checkKeyHasPermission(item.permissionKey as UserPermissionsEnum, PermissionsActions.VIEW);
|
|
25
|
+
return;
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { RouteNameItem } from "./side-menu";
|
|
2
|
+
|
|
3
|
+
export const ROUTES_NAME: RouteNameItem = {
|
|
4
|
+
board: {
|
|
5
|
+
name: '/board-page',
|
|
6
|
+
},
|
|
7
|
+
users: {
|
|
8
|
+
name: '/users',
|
|
9
|
+
},
|
|
10
|
+
// reports: {
|
|
11
|
+
// name: '/reports',
|
|
12
|
+
// },
|
|
13
|
+
meetings: {
|
|
14
|
+
name: '/meeting-page',
|
|
15
|
+
},
|
|
16
|
+
// tasks: {
|
|
17
|
+
// name: '/tasks',
|
|
18
|
+
// },
|
|
19
|
+
// imported: {
|
|
20
|
+
// name: '/imported',
|
|
21
|
+
// },
|
|
22
|
+
// exported: {
|
|
23
|
+
// name: '/exported',
|
|
24
|
+
// },
|
|
25
|
+
// board: {
|
|
26
|
+
// name: '/board',
|
|
27
|
+
// },
|
|
28
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { ROUTES_NAME } from './routes-names';
|
|
2
|
+
import { SideMenuItem } from './side-menu';
|
|
3
|
+
|
|
4
|
+
export const BASE_SIDE_MENU_ITEMS: SideMenuItem[] = [
|
|
5
|
+
{
|
|
6
|
+
label: 'الإجتماعات',
|
|
7
|
+
icon: 'font-icon-menu-board',
|
|
8
|
+
link: ROUTES_NAME['meetings'].name
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
label: 'اللجان و المجالس',
|
|
12
|
+
icon: 'font-icon-people',
|
|
13
|
+
link: ROUTES_NAME['board'].name
|
|
14
|
+
},
|
|
15
|
+
// {
|
|
16
|
+
// label: 'المستخدمين',
|
|
17
|
+
// icon: 'font-icon-profile-2user',
|
|
18
|
+
// link: ROUTES_NAME['users'].name,
|
|
19
|
+
// },
|
|
20
|
+
// {
|
|
21
|
+
// label: 'الإجتماعات',
|
|
22
|
+
// icon: 'font-icon-menu-board',
|
|
23
|
+
// link: ROUTES_NAME['meetings'].name,
|
|
24
|
+
// },
|
|
25
|
+
// {
|
|
26
|
+
// label: 'مهامي',
|
|
27
|
+
// icon: 'font-icon-task-square',
|
|
28
|
+
// link: ROUTES_NAME['tasks'].name,
|
|
29
|
+
// },
|
|
30
|
+
// {
|
|
31
|
+
// label: 'الوارد',
|
|
32
|
+
// icon: 'font-icon-directbox-receive',
|
|
33
|
+
// link: ROUTES_NAME['imported'].name,
|
|
34
|
+
// },
|
|
35
|
+
// {
|
|
36
|
+
// label: 'الصادر',
|
|
37
|
+
// icon: 'font-icon-directbox-send',
|
|
38
|
+
// link: ROUTES_NAME['exported'].name,
|
|
39
|
+
// },
|
|
40
|
+
// {
|
|
41
|
+
// label: 'التقارير',
|
|
42
|
+
// icon: 'font-icon-status-up',
|
|
43
|
+
// link: ROUTES_NAME['reports'].name,
|
|
44
|
+
// },
|
|
45
|
+
];
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { TemplateRef } from "@angular/core";
|
|
2
|
+
|
|
3
|
+
interface Tab {
|
|
4
|
+
title: string;
|
|
5
|
+
iconName?: string;
|
|
6
|
+
iconPathCount?: number;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
count?: number;
|
|
9
|
+
permissionKey?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface RoutedTab extends Tab {
|
|
13
|
+
link: string;
|
|
14
|
+
}
|
|
15
|
+
export interface TemplateTab<T = unknown> extends Tab {
|
|
16
|
+
contentTemplate: TemplateRef<unknown>;
|
|
17
|
+
queryParamValue?: T;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
export type AppTabs = ({
|
|
22
|
+
isRouted: true;
|
|
23
|
+
items: RoutedTab[];
|
|
24
|
+
} | {
|
|
25
|
+
isRouted: false;
|
|
26
|
+
items: TemplateTab[];
|
|
27
|
+
})
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
@if (tabs && tabs.items.length) {
|
|
2
|
+
<div [class]="tabsStyle + (responsive ? ' full-width' : '') + ' tabs-container'">
|
|
3
|
+
<p-tabs [value]="selectedTabIndex() || activeTabIndex" scrollable>
|
|
4
|
+
<p-tablist>
|
|
5
|
+
|
|
6
|
+
@for (tab of tabs.items; let i = $index; track i) {
|
|
7
|
+
<p-tab [value]="i" [routerLink]="tabs.isRouted ? $any(tab).link : null" [disabled]="tab.disabled"
|
|
8
|
+
(click)="onTabChange(i)">
|
|
9
|
+
@if (tab.iconName) {
|
|
10
|
+
<app-ico-moon-card [iconClass]="'text-[17px]'" [iconName]="tab.iconName"
|
|
11
|
+
[iconPathCount]="tab.iconPathCount || 0" />
|
|
12
|
+
}
|
|
13
|
+
<span>{{ tab.title | translate }}
|
|
14
|
+
@if (tab.count || tab.count === 0) {
|
|
15
|
+
<p-badge [value]="getTabCount(tab.count)" severity="secondary" />
|
|
16
|
+
}
|
|
17
|
+
</span>
|
|
18
|
+
</p-tab>
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
</p-tablist>
|
|
22
|
+
|
|
23
|
+
<p-tabpanels>
|
|
24
|
+
@if (tabs.isRouted) {
|
|
25
|
+
<router-outlet></router-outlet>
|
|
26
|
+
} @else {
|
|
27
|
+
@for (tab of tabs.items; let i = $index; track i) {
|
|
28
|
+
<p-tabpanel [value]="i">
|
|
29
|
+
<ng-container [ngTemplateOutlet]="tab.contentTemplate"></ng-container>
|
|
30
|
+
</p-tabpanel>
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
</p-tabpanels>
|
|
35
|
+
</p-tabs>
|
|
36
|
+
</div>
|
|
37
|
+
}
|