aril 1.0.39 → 1.0.41
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/esm2022/http/src/serviceStateMethods.mjs +6 -2
- package/esm2022/theme/layout/app/favorite-pages/favorite-pages-sidebar.component.mjs +211 -0
- package/esm2022/theme/layout/app/favorite-pages/favorite-pages.service.mjs +55 -0
- package/esm2022/theme/layout/app/favorite-pages/modals/add-edit-favorite-modal/add-edit-favorite-modal.component.mjs +129 -0
- package/esm2022/theme/layout/app/history/history-sidebar.component.mjs +128 -0
- package/esm2022/theme/layout/app/history/history.service.mjs +146 -0
- package/esm2022/theme/layout/app/layout/app.layout.component.mjs +9 -3
- package/esm2022/theme/layout/app/profileSidebar/app.profilesidebar.component.mjs +100 -8
- package/esm2022/theme/layout/app/profileSidebar/modals/change-password-modal/change-password-modal.component.mjs +142 -0
- package/esm2022/theme/layout/app/profileSidebar/modals/edit-profile-modal/edit-profile-modal.component.mjs +123 -0
- package/esm2022/theme/layout/app/profileSidebar/profile.service.mjs +42 -0
- package/esm2022/theme/layout/app/site-map/site-map-sidebar.component.mjs +161 -0
- package/esm2022/theme/layout/app/topbar/app.topbar.component.mjs +23 -5
- package/esm2022/theme/layout/service/app.layout.service.mjs +13 -1
- package/fesm2022/aril-http.mjs +5 -1
- package/fesm2022/aril-http.mjs.map +1 -1
- package/fesm2022/aril-theme-layout.mjs +1197 -75
- package/fesm2022/aril-theme-layout.mjs.map +1 -1
- package/package.json +84 -83
- package/theme/layout/app/favorite-pages/favorite-pages-sidebar.component.d.ts +42 -0
- package/theme/layout/app/favorite-pages/favorite-pages-sidebar.component.html +106 -0
- package/theme/layout/app/favorite-pages/favorite-pages-sidebar.component.scss +181 -0
- package/theme/layout/app/favorite-pages/favorite-pages-sidebar.component.ts +253 -0
- package/theme/layout/app/favorite-pages/favorite-pages.service.d.ts +54 -0
- package/theme/layout/app/favorite-pages/favorite-pages.service.ts +87 -0
- package/theme/layout/app/favorite-pages/modals/add-edit-favorite-modal/add-edit-favorite-modal.component.d.ts +36 -0
- package/theme/layout/app/favorite-pages/modals/add-edit-favorite-modal/add-edit-favorite-modal.component.html +27 -0
- package/theme/layout/app/favorite-pages/modals/add-edit-favorite-modal/add-edit-favorite-modal.component.ts +165 -0
- package/theme/layout/app/history/history-sidebar.component.d.ts +30 -0
- package/theme/layout/app/history/history-sidebar.component.html +88 -0
- package/theme/layout/app/history/history-sidebar.component.scss +191 -0
- package/theme/layout/app/history/history-sidebar.component.ts +139 -0
- package/theme/layout/app/history/history.service.d.ts +36 -0
- package/theme/layout/app/history/history.service.ts +182 -0
- package/theme/layout/app/layout/app.layout.component.html +3 -0
- package/theme/layout/app/layout/app.layout.component.ts +7 -1
- package/theme/layout/app/profileSidebar/app.profilesidebar.component.d.ts +17 -2
- package/theme/layout/app/profileSidebar/app.profilesidebar.component.html +107 -135
- package/theme/layout/app/profileSidebar/app.profilesidebar.component.scss +152 -0
- package/theme/layout/app/profileSidebar/app.profilesidebar.component.ts +114 -7
- package/theme/layout/app/profileSidebar/modals/change-password-modal/change-password-modal.component.d.ts +30 -0
- package/theme/layout/app/profileSidebar/modals/change-password-modal/change-password-modal.component.html +46 -0
- package/theme/layout/app/profileSidebar/modals/change-password-modal/change-password-modal.component.scss +28 -0
- package/theme/layout/app/profileSidebar/modals/change-password-modal/change-password-modal.component.ts +178 -0
- package/theme/layout/app/profileSidebar/modals/edit-profile-modal/edit-profile-modal.component.d.ts +27 -0
- package/theme/layout/app/profileSidebar/modals/edit-profile-modal/edit-profile-modal.component.html +76 -0
- package/theme/layout/app/profileSidebar/modals/edit-profile-modal/edit-profile-modal.component.ts +141 -0
- package/theme/layout/app/profileSidebar/profile.service.d.ts +67 -0
- package/theme/layout/app/profileSidebar/profile.service.ts +89 -0
- package/theme/layout/app/site-map/site-map-sidebar.component.d.ts +37 -0
- package/theme/layout/app/site-map/site-map-sidebar.component.html +118 -0
- package/theme/layout/app/site-map/site-map-sidebar.component.scss +189 -0
- package/theme/layout/app/site-map/site-map-sidebar.component.ts +189 -0
- package/theme/layout/app/topbar/app.topbar.component.d.ts +7 -1
- package/theme/layout/app/topbar/app.topbar.component.html +37 -17
- package/theme/layout/app/topbar/app.topbar.component.scss +188 -12
- package/theme/layout/app/topbar/app.topbar.component.ts +29 -7
- package/theme/layout/service/app.layout.service.d.ts +6 -0
- package/theme/layout/service/app.layout.service.ts +19 -1
|
@@ -2,150 +2,122 @@
|
|
|
2
2
|
[(visible)]="visible"
|
|
3
3
|
position="right"
|
|
4
4
|
[transitionOptions]="'.3s cubic-bezier(0, 0, 0.2, 1)'"
|
|
5
|
-
styleClass="layout-profile-sidebar w-full sm:w-
|
|
6
|
-
<
|
|
7
|
-
<
|
|
8
|
-
|
|
5
|
+
styleClass="layout-profile-sidebar w-full sm:w-30rem">
|
|
6
|
+
<ng-template pTemplate="header">
|
|
7
|
+
<div class="flex align-items-center gap-2" *transloco="let t; read: 'profileSidebar'">
|
|
8
|
+
<span class="font-bold">{{ t('personalInfo') }}</span>
|
|
9
|
+
</div>
|
|
10
|
+
</ng-template>
|
|
9
11
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
12
|
+
@if (userProfile()) {
|
|
13
|
+
<div class="profile-content" *transloco="let t; read: 'profileSidebar'">
|
|
14
|
+
<!-- Personal Information -->
|
|
15
|
+
<div class="info-section">
|
|
16
|
+
<div class="info-items">
|
|
17
|
+
<div class="info-item">
|
|
18
|
+
<i class="pi pi-user info-icon"></i>
|
|
19
|
+
<div class="info-content">
|
|
20
|
+
<span class="info-label">{{ t('fullName') }}</span>
|
|
21
|
+
<span class="info-value">{{ userProfile()?.firstName }} {{ userProfile()?.lastName }}</span>
|
|
22
|
+
</div>
|
|
20
23
|
</div>
|
|
21
|
-
</a>
|
|
22
|
-
</li>
|
|
23
|
-
<li>
|
|
24
|
-
<a
|
|
25
|
-
class="cursor-pointer flex surface-border mb-3 p-3 align-items-center border-1 surface-border border-round hover:surface-hover transition-colors transition-duration-150">
|
|
26
|
-
<span>
|
|
27
|
-
<i class="pi pi-user text-xl text-primary"></i>
|
|
28
|
-
</span>
|
|
29
|
-
<div class="ml-3">
|
|
30
|
-
<span class="mb-2 font-semibold">Billing</span>
|
|
31
|
-
<p class="text-color-secondary m-0">Amet mimin mıollit</p>
|
|
32
|
-
</div>
|
|
33
|
-
</a>
|
|
34
|
-
</li>
|
|
35
|
-
<li>
|
|
36
|
-
<a
|
|
37
|
-
class="cursor-pointer flex surface-border mb-3 p-3 align-items-center border-1 surface-border border-round hover:surface-hover transition-colors transition-duration-150">
|
|
38
|
-
<span>
|
|
39
|
-
<i class="pi pi-cog text-xl text-primary"></i>
|
|
40
|
-
</span>
|
|
41
|
-
<div class="ml-3">
|
|
42
|
-
<span class="mb-2 font-semibold">Settings</span>
|
|
43
|
-
<p class="text-color-secondary m-0">Exercitation veniam</p>
|
|
44
|
-
</div>
|
|
45
|
-
</a>
|
|
46
|
-
</li> -->
|
|
47
|
-
<li (click)="logout()">
|
|
48
|
-
<a
|
|
49
|
-
class="cursor-pointer flex surface-border mb-3 p-3 align-items-center border-1 surface-border border-round hover:surface-hover transition-colors transition-duration-150">
|
|
50
|
-
<span>
|
|
51
|
-
<i class="pi pi-power-off text-xl text-primary"></i>
|
|
52
|
-
</span>
|
|
53
|
-
<div class="ml-3" >
|
|
54
|
-
<span class="mb-2 font-semibold">Çıkış</span>
|
|
55
|
-
</div>
|
|
56
|
-
</a>
|
|
57
|
-
</li>
|
|
58
|
-
</ul>
|
|
59
|
-
</div>
|
|
60
24
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
<a
|
|
68
|
-
class="cursor-pointer flex surface-border mb-3 p-3 align-items-center border-1 surface-border border-round hover:surface-hover transition-colors transition-duration-150">
|
|
69
|
-
<span>
|
|
70
|
-
<i class="pi pi-comment text-xl text-primary"></i>
|
|
71
|
-
</span>
|
|
72
|
-
<div class="ml-3">
|
|
73
|
-
<span class="mb-2 font-semibold">Your post has new comments</span>
|
|
74
|
-
<p class="text-color-secondary m-0">5 min ago</p>
|
|
25
|
+
<div class="info-item">
|
|
26
|
+
<i class="pi pi-id-card info-icon"></i>
|
|
27
|
+
<div class="info-content">
|
|
28
|
+
<span class="info-label">{{ t('tcNumber') }}</span>
|
|
29
|
+
<span class="info-value">{{ userProfile()?.tckn || '' }}</span>
|
|
30
|
+
</div>
|
|
75
31
|
</div>
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
</span>
|
|
84
|
-
<div class="ml-3">
|
|
85
|
-
<span class="mb-2 font-semibold">Your post has been deleted</span>
|
|
86
|
-
<p class="text-color-secondary m-0">15min ago</p>
|
|
32
|
+
|
|
33
|
+
<div class="info-item">
|
|
34
|
+
<i class="pi pi-envelope info-icon"></i>
|
|
35
|
+
<div class="info-content">
|
|
36
|
+
<span class="info-label">{{ t('email') }}</span>
|
|
37
|
+
<span class="info-value">{{ userProfile()?.email || '' }}</span>
|
|
38
|
+
</div>
|
|
87
39
|
</div>
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
</span>
|
|
96
|
-
<div class="ml-3">
|
|
97
|
-
<span class="mb-2 font-semibold">Post has been updated</span>
|
|
98
|
-
<p class="text-color-secondary m-0">3h ago</p>
|
|
40
|
+
|
|
41
|
+
<div class="info-item">
|
|
42
|
+
<i class="pi pi-phone info-icon"></i>
|
|
43
|
+
<div class="info-content">
|
|
44
|
+
<span class="info-label">{{ t('phone') }}</span>
|
|
45
|
+
<span class="info-value">{{ userProfile()?.phone || '' }}</span>
|
|
46
|
+
</div>
|
|
99
47
|
</div>
|
|
100
|
-
</a>
|
|
101
|
-
</li>
|
|
102
|
-
</ul>
|
|
103
|
-
</div> -->
|
|
104
48
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
49
|
+
<div class="info-item">
|
|
50
|
+
<i class="pi pi-at info-icon"></i>
|
|
51
|
+
<div class="info-content">
|
|
52
|
+
<span class="info-label">{{ t('username') }}</span>
|
|
53
|
+
<span class="info-value">{{ userProfile()?.userName }}</span>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
108
56
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
<span class="mb-2 font-semibold">James Robinson</span>
|
|
118
|
-
<p class="text-color-secondary m-0">10 min ago</p>
|
|
57
|
+
<div class="info-item">
|
|
58
|
+
<i class="pi pi-check-circle info-icon"></i>
|
|
59
|
+
<div class="info-content">
|
|
60
|
+
<span class="info-label">{{ t('accountStatus') }}</span>
|
|
61
|
+
<span class="info-value status" [class.active]="userProfile()?.enabled">
|
|
62
|
+
{{ userProfile()?.enabled ? t('active') : t('inactive') }}
|
|
63
|
+
</span>
|
|
64
|
+
</div>
|
|
119
65
|
</div>
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
<div class="ml-3">
|
|
130
|
-
<span class="mb-2 font-semibold">Mary Watson</span>
|
|
131
|
-
<p class="text-color-secondary m-0">15min ago</p>
|
|
66
|
+
|
|
67
|
+
<div class="info-item">
|
|
68
|
+
<i class="pi pi-user info-icon"></i>
|
|
69
|
+
<div class="info-content">
|
|
70
|
+
<span class="info-label">{{ t('systemUser') }}</span>
|
|
71
|
+
<span class="info-value status" [class.active]="userProfile()?.systemUser">
|
|
72
|
+
{{ userProfile()?.systemUser ? t('yes') : t('no') }}
|
|
73
|
+
</span>
|
|
74
|
+
</div>
|
|
132
75
|
</div>
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
<img src="assets/demo/images/avatar/circle/avatar-f-4.png" alt="Avatar" class="w-2rem h-2rem" />
|
|
141
|
-
</span>
|
|
142
|
-
<div class="ml-3">
|
|
143
|
-
<span class="mb-2 font-semibold">Aisha Webb</span>
|
|
144
|
-
<p class="text-color-secondary m-0">3h ago</p>
|
|
76
|
+
|
|
77
|
+
<div class="info-item">
|
|
78
|
+
<i class="pi pi-building info-icon"></i>
|
|
79
|
+
<div class="info-content">
|
|
80
|
+
<span class="info-label">{{ t('clientSystemUser') }}</span>
|
|
81
|
+
<span class="info-value">{{ userProfile()?.clientOfSystemUser }}</span>
|
|
82
|
+
</div>
|
|
145
83
|
</div>
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
84
|
+
</div>
|
|
85
|
+
</div>
|
|
86
|
+
</div>
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
<!-- Fixed Action Buttons -->
|
|
90
|
+
@if (userProfile()) {
|
|
91
|
+
<div class="action-buttons-container grid p-fluid" *transloco="let t; read: 'profileSidebar'">
|
|
92
|
+
<div class="col-12 flex justify-content-between align-items-center">
|
|
93
|
+
<aril-button
|
|
94
|
+
[label]="t('editProfile')"
|
|
95
|
+
icon="USER_EDIT"
|
|
96
|
+
color="primary"
|
|
97
|
+
[outlined]="true"
|
|
98
|
+
size="sm"
|
|
99
|
+
class="col-6"
|
|
100
|
+
(clickEvent)="editProfile()">
|
|
101
|
+
</aril-button>
|
|
102
|
+
<aril-button
|
|
103
|
+
[label]="t('changePassword')"
|
|
104
|
+
icon="KEY"
|
|
105
|
+
color="secondary"
|
|
106
|
+
[outlined]="true"
|
|
107
|
+
size="sm"
|
|
108
|
+
class="col-6"
|
|
109
|
+
(clickEvent)="changePassword()">
|
|
110
|
+
</aril-button>
|
|
111
|
+
</div>
|
|
112
|
+
<aril-button
|
|
113
|
+
[label]="t('logout')"
|
|
114
|
+
icon="SIGN_OUT"
|
|
115
|
+
color="danger"
|
|
116
|
+
[outlined]="false"
|
|
117
|
+
size="sm"
|
|
118
|
+
class="col-12"
|
|
119
|
+
(clickEvent)="logout()">
|
|
120
|
+
</aril-button>
|
|
121
|
+
</div>
|
|
122
|
+
}
|
|
151
123
|
</p-sidebar>
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
// Modern Profile Sidebar - Matching App UI
|
|
2
|
+
:host {
|
|
3
|
+
.layout-profile-sidebar {
|
|
4
|
+
.p-sidebar-content {
|
|
5
|
+
padding: 0;
|
|
6
|
+
background: var(--surface-0, #ffffff);
|
|
7
|
+
color: var(--text-color, #333);
|
|
8
|
+
height: 100vh;
|
|
9
|
+
overflow-y: auto;
|
|
10
|
+
position: relative;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Content Section
|
|
15
|
+
.profile-content {
|
|
16
|
+
padding: 1rem 0.75rem;
|
|
17
|
+
padding-bottom: 12rem;
|
|
18
|
+
display: flex;
|
|
19
|
+
flex-direction: column;
|
|
20
|
+
gap: 1.25rem;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Fixed Action Buttons Container - Sadece sidebar içinde
|
|
24
|
+
.action-buttons-container {
|
|
25
|
+
width: 100%;
|
|
26
|
+
position: absolute;
|
|
27
|
+
bottom: 0;
|
|
28
|
+
left: 0;
|
|
29
|
+
right: 0;
|
|
30
|
+
background: var(--surface-0, #ffffff);
|
|
31
|
+
border-top: 1px solid var(--surface-border, #e2e8f0);
|
|
32
|
+
padding: 1rem 0.75rem;
|
|
33
|
+
z-index: 300;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Info Sections - Modern Flat Design
|
|
37
|
+
.info-section {
|
|
38
|
+
.section-title {
|
|
39
|
+
font-size: 1.25rem;
|
|
40
|
+
font-weight: 500;
|
|
41
|
+
color: var(--text-color-secondary, #64748b);
|
|
42
|
+
margin: 0 0 1rem 0;
|
|
43
|
+
padding-bottom: 0.5rem;
|
|
44
|
+
border-bottom: 1px solid var(--surface-border, #e2e8f0);
|
|
45
|
+
display: flex;
|
|
46
|
+
align-items: center;
|
|
47
|
+
gap: 0.5rem;
|
|
48
|
+
text-transform: uppercase;
|
|
49
|
+
letter-spacing: 0.5px;
|
|
50
|
+
|
|
51
|
+
i {
|
|
52
|
+
color: var(--text-color-secondary, #64748b);
|
|
53
|
+
font-size: 1rem;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.info-items {
|
|
58
|
+
display: flex;
|
|
59
|
+
flex-direction: column;
|
|
60
|
+
gap: 0;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.info-item {
|
|
64
|
+
display: flex;
|
|
65
|
+
align-items: center;
|
|
66
|
+
gap: 0.75rem;
|
|
67
|
+
padding: 0.75rem 0;
|
|
68
|
+
border-bottom: 1px solid var(--surface-border, #f1f5f9);
|
|
69
|
+
|
|
70
|
+
&:last-child {
|
|
71
|
+
border-bottom: none;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.info-icon {
|
|
75
|
+
color: var(--text-color-secondary, #64748b);
|
|
76
|
+
font-size: 1rem;
|
|
77
|
+
flex-shrink: 0;
|
|
78
|
+
width: 1.25rem;
|
|
79
|
+
text-align: center;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.info-content {
|
|
83
|
+
flex: 1;
|
|
84
|
+
display: flex;
|
|
85
|
+
flex-direction: column;
|
|
86
|
+
gap: 0.25rem;
|
|
87
|
+
|
|
88
|
+
.info-label {
|
|
89
|
+
font-size: 0.95rem;
|
|
90
|
+
color: var(--text-color-secondary, #64748b);
|
|
91
|
+
font-weight: 500;
|
|
92
|
+
line-height: 1;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.info-value {
|
|
96
|
+
font-size: 0.95rem;
|
|
97
|
+
color: var(--text-color, #1e293b);
|
|
98
|
+
font-weight: 400;
|
|
99
|
+
line-height: 1.3;
|
|
100
|
+
|
|
101
|
+
&.status {
|
|
102
|
+
display: inline-flex;
|
|
103
|
+
align-items: center;
|
|
104
|
+
padding: 0.25rem 0.75rem;
|
|
105
|
+
border-radius: 16px;
|
|
106
|
+
font-size: 0.8rem;
|
|
107
|
+
font-weight: 600;
|
|
108
|
+
text-transform: uppercase;
|
|
109
|
+
letter-spacing: 0.025em;
|
|
110
|
+
width: fit-content;
|
|
111
|
+
background: var(--red-100, #fee2e2);
|
|
112
|
+
color: var(--red-700, #b91c1c);
|
|
113
|
+
border: 1px solid var(--red-200, #fecaca);
|
|
114
|
+
|
|
115
|
+
&.active {
|
|
116
|
+
background: var(--green-100, #dcfce7);
|
|
117
|
+
color: var(--green-700, #15803d);
|
|
118
|
+
border: 1px solid var(--green-200, #bbf7d0);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Responsive Design
|
|
128
|
+
@media (max-width: 768px) {
|
|
129
|
+
.profile-content {
|
|
130
|
+
padding: 0.875rem 0.65rem;
|
|
131
|
+
padding-bottom: 11rem;
|
|
132
|
+
gap: 1rem;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.action-buttons-container {
|
|
136
|
+
padding: 0.875rem 0.65rem;
|
|
137
|
+
|
|
138
|
+
.action-buttons-vertical {
|
|
139
|
+
gap: 0.65rem;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.action-buttons-horizontal {
|
|
143
|
+
gap: 0.4rem;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.info-item {
|
|
148
|
+
padding: 0.65rem 0;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
}
|
|
@@ -1,23 +1,86 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CommonModule } from '@angular/common';
|
|
2
|
+
import { Component, OnInit, effect, signal } from '@angular/core';
|
|
3
|
+
import { toSignal } from '@angular/core/rxjs-interop';
|
|
2
4
|
|
|
5
|
+
import { AvatarModule } from 'primeng/avatar';
|
|
6
|
+
import { ButtonModule } from 'primeng/button';
|
|
7
|
+
import { ChipModule } from 'primeng/chip';
|
|
8
|
+
import { DialogService } from 'primeng/dynamicdialog';
|
|
3
9
|
import { SidebarModule } from 'primeng/sidebar';
|
|
10
|
+
import { SkeletonModule } from 'primeng/skeleton';
|
|
4
11
|
import { TagModule } from 'primeng/tag';
|
|
5
12
|
|
|
6
|
-
|
|
13
|
+
import { TranslocoModule, TranslocoService } from '@ngneat/transloco';
|
|
7
14
|
import { KeycloakService } from 'keycloak-angular';
|
|
15
|
+
import { Subject, switchMap } from 'rxjs';
|
|
16
|
+
|
|
17
|
+
import { ButtonComponent } from 'aril/ui/button';
|
|
18
|
+
|
|
8
19
|
import { LayoutService } from '../../service/app.layout.service';
|
|
20
|
+
import { ChangePasswordModalComponent } from './modals/change-password-modal/change-password-modal.component';
|
|
21
|
+
import { EditProfileModalComponent } from './modals/edit-profile-modal/edit-profile-modal.component';
|
|
22
|
+
import { GetUserRequestDTO, ProfileService, UserResponseDTO } from './profile.service';
|
|
9
23
|
|
|
10
24
|
@Component({
|
|
11
25
|
standalone: true,
|
|
12
26
|
selector: 'app-profilemenu',
|
|
13
|
-
imports: [
|
|
14
|
-
|
|
27
|
+
imports: [
|
|
28
|
+
CommonModule,
|
|
29
|
+
SidebarModule,
|
|
30
|
+
TagModule,
|
|
31
|
+
ButtonModule,
|
|
32
|
+
SkeletonModule,
|
|
33
|
+
AvatarModule,
|
|
34
|
+
ChipModule,
|
|
35
|
+
TranslocoModule,
|
|
36
|
+
ButtonComponent
|
|
37
|
+
],
|
|
38
|
+
templateUrl: './app.profilesidebar.component.html',
|
|
39
|
+
styleUrls: ['./app.profilesidebar.component.scss'],
|
|
40
|
+
providers: [DialogService]
|
|
15
41
|
})
|
|
16
|
-
export class AppProfileSidebarComponent {
|
|
42
|
+
export class AppProfileSidebarComponent implements OnInit {
|
|
17
43
|
username: string;
|
|
44
|
+
userProfile = signal<UserResponseDTO | null>(null);
|
|
45
|
+
|
|
46
|
+
private subjects = {
|
|
47
|
+
getUser: new Subject<GetUserRequestDTO>()
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
getUserService = toSignal(this.subjects.getUser.pipe(switchMap((data) => this.profileService.getUser(data))));
|
|
18
51
|
|
|
19
|
-
constructor(
|
|
52
|
+
constructor(
|
|
53
|
+
public layoutService: LayoutService,
|
|
54
|
+
private readonly keycloak: KeycloakService,
|
|
55
|
+
private readonly profileService: ProfileService,
|
|
56
|
+
private readonly dialogService: DialogService,
|
|
57
|
+
private readonly translocoService: TranslocoService
|
|
58
|
+
) {
|
|
20
59
|
this.username = this.keycloak.getUsername();
|
|
60
|
+
this.initializeEffects();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
ngOnInit(): void {
|
|
64
|
+
this.loadUserProfile();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
private initializeEffects(): void {
|
|
68
|
+
effect(
|
|
69
|
+
() => {
|
|
70
|
+
const service = this.getUserService();
|
|
71
|
+
if (service?.response) {
|
|
72
|
+
this.userProfile.set(service.response);
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
{ allowSignalWrites: true }
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
private loadUserProfile(): void {
|
|
80
|
+
const userId = this.keycloak.getKeycloakInstance().idTokenParsed?.sub;
|
|
81
|
+
if (userId) {
|
|
82
|
+
this.subjects.getUser.next({ id: userId });
|
|
83
|
+
}
|
|
21
84
|
}
|
|
22
85
|
|
|
23
86
|
get visible(): boolean {
|
|
@@ -26,9 +89,53 @@ export class AppProfileSidebarComponent {
|
|
|
26
89
|
|
|
27
90
|
set visible(_val: boolean) {
|
|
28
91
|
this.layoutService.state.profileSidebarVisible = _val;
|
|
92
|
+
if (_val && !this.userProfile()) {
|
|
93
|
+
this.loadUserProfile();
|
|
94
|
+
}
|
|
29
95
|
}
|
|
30
96
|
|
|
31
|
-
logout() {
|
|
97
|
+
logout(): void {
|
|
32
98
|
this.keycloak.logout();
|
|
33
99
|
}
|
|
100
|
+
|
|
101
|
+
editProfile(): void {
|
|
102
|
+
if (!this.userProfile()) return;
|
|
103
|
+
|
|
104
|
+
const ref = this.dialogService.open(EditProfileModalComponent, {
|
|
105
|
+
header: this.translocoService.translate('profileSidebar.editProfile'),
|
|
106
|
+
width: '600px',
|
|
107
|
+
height: 'auto',
|
|
108
|
+
modal: true,
|
|
109
|
+
maximizable: false,
|
|
110
|
+
closable: true,
|
|
111
|
+
data: {
|
|
112
|
+
userProfile: this.userProfile()
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
ref.onClose.subscribe((result) => {
|
|
117
|
+
if (result?.status === 'success') {
|
|
118
|
+
this.loadUserProfile();
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
changePassword(): void {
|
|
124
|
+
const userId = this.keycloak.getKeycloakInstance().idTokenParsed?.sub;
|
|
125
|
+
if (!userId) return;
|
|
126
|
+
|
|
127
|
+
const ref = this.dialogService.open(ChangePasswordModalComponent, {
|
|
128
|
+
header: this.translocoService.translate('profileSidebar.changePassword'),
|
|
129
|
+
width: '500px',
|
|
130
|
+
height: 'auto',
|
|
131
|
+
modal: true,
|
|
132
|
+
maximizable: false,
|
|
133
|
+
closable: true,
|
|
134
|
+
data: {
|
|
135
|
+
userId: userId
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
ref.onClose.subscribe();
|
|
140
|
+
}
|
|
34
141
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { AbstractControl, FormBuilder, FormGroup, ValidationErrors } from '@angular/forms';
|
|
2
|
+
import { MessageService } from 'primeng/api';
|
|
3
|
+
import { DynamicDialogConfig, DynamicDialogRef } from 'primeng/dynamicdialog';
|
|
4
|
+
import { TranslocoService } from '@ngneat/transloco';
|
|
5
|
+
import { ProfileService } from '../../profile.service';
|
|
6
|
+
import * as i0 from "@angular/core";
|
|
7
|
+
export declare class PasswordValidators {
|
|
8
|
+
static passwordMatchValidator: (passwordFormGroup: FormGroup) => (control: AbstractControl) => ValidationErrors | null;
|
|
9
|
+
static minLength(length: number): (control: AbstractControl) => ValidationErrors | null;
|
|
10
|
+
static required(control: AbstractControl): ValidationErrors | null;
|
|
11
|
+
}
|
|
12
|
+
export declare class ChangePasswordModalComponent {
|
|
13
|
+
private readonly formBuilder;
|
|
14
|
+
private readonly dialogRef;
|
|
15
|
+
private readonly dialogConfig;
|
|
16
|
+
private readonly profileService;
|
|
17
|
+
private readonly translocoService;
|
|
18
|
+
private readonly messageService;
|
|
19
|
+
passwordForm: FormGroup;
|
|
20
|
+
userId: string;
|
|
21
|
+
private subjects;
|
|
22
|
+
resetPasswordService: import("@angular/core").Signal<import("../../../../../../../../dist/http").ServiceResponse<any> | undefined>;
|
|
23
|
+
constructor(formBuilder: FormBuilder, dialogRef: DynamicDialogRef, dialogConfig: DynamicDialogConfig, profileService: ProfileService, translocoService: TranslocoService, messageService: MessageService);
|
|
24
|
+
initializeForm(): void;
|
|
25
|
+
getErrorMessage(controlName: string): string;
|
|
26
|
+
submit(): void;
|
|
27
|
+
cancel(): void;
|
|
28
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<ChangePasswordModalComponent, never>;
|
|
29
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<ChangePasswordModalComponent, "ng-component", never, {}, {}, never, never, true, never>;
|
|
30
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<div class="change-password-modal" *transloco="let t; read: 'profileSidebar'">
|
|
2
|
+
<aril-form [formGroup]="passwordForm">
|
|
3
|
+
<aril-field [label]="t('newPassword')" [cols]="{ xl: 12, lg: 12, md: 12, sm: 12 }" [markAsRequired]="true">
|
|
4
|
+
<p-password
|
|
5
|
+
formControlName="newPassword"
|
|
6
|
+
[placeholder]="t('newPassword')"
|
|
7
|
+
[feedback]="false"
|
|
8
|
+
[toggleMask]="true"
|
|
9
|
+
styleClass="w-full"
|
|
10
|
+
[pTooltip]="passwordForm.get('newPassword')?.invalid && passwordForm.get('newPassword')?.touched ? getErrorMessage('newPassword') : ''"
|
|
11
|
+
tooltipPosition="top"
|
|
12
|
+
tooltipStyleClass="tooltipErrorMessage">
|
|
13
|
+
</p-password>
|
|
14
|
+
</aril-field>
|
|
15
|
+
|
|
16
|
+
<aril-field [label]="t('confirmPassword')" [cols]="{ xl: 12, lg: 12, md: 12, sm: 12 }" [markAsRequired]="true">
|
|
17
|
+
<p-password
|
|
18
|
+
formControlName="confirmPassword"
|
|
19
|
+
[placeholder]="t('confirmPassword')"
|
|
20
|
+
[feedback]="false"
|
|
21
|
+
[toggleMask]="true"
|
|
22
|
+
styleClass="w-full"
|
|
23
|
+
[pTooltip]="passwordForm.get('confirmPassword')?.invalid && passwordForm.get('confirmPassword')?.touched ? getErrorMessage('confirmPassword') : ''"
|
|
24
|
+
tooltipPosition="top"
|
|
25
|
+
tooltipStyleClass="tooltipErrorMessage">
|
|
26
|
+
</p-password>
|
|
27
|
+
</aril-field>
|
|
28
|
+
|
|
29
|
+
<div class="col-12 flex justify-content-end mt-4 gap-2">
|
|
30
|
+
<aril-button
|
|
31
|
+
color="danger"
|
|
32
|
+
[label]="t('cancel')"
|
|
33
|
+
[outlined]="true"
|
|
34
|
+
icon="TIMES"
|
|
35
|
+
(clickEvent)="cancel()">
|
|
36
|
+
</aril-button>
|
|
37
|
+
<aril-button
|
|
38
|
+
color="success"
|
|
39
|
+
[label]="t('save')"
|
|
40
|
+
[raised]="false"
|
|
41
|
+
icon="CHECK"
|
|
42
|
+
(clickEvent)="submit()">
|
|
43
|
+
</aril-button>
|
|
44
|
+
</div>
|
|
45
|
+
</aril-form>
|
|
46
|
+
</div>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
.change-password-modal {
|
|
2
|
+
|
|
3
|
+
:host ::ng-deep {
|
|
4
|
+
.p-password.ng-invalid.ng-touched .p-inputtext {
|
|
5
|
+
border-color: var(--red-500, #ef4444);
|
|
6
|
+
box-shadow: 0 0 0 1px var(--red-500, #ef4444);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.p-password.ng-valid.ng-touched .p-inputtext {
|
|
10
|
+
border-color: var(--green-500, #22c55e);
|
|
11
|
+
box-shadow: 0 0 0 1px var(--green-500, #22c55e);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.tooltipErrorMessage {
|
|
15
|
+
background-color: var(--red-500, #ef4444) !important;
|
|
16
|
+
color: white !important;
|
|
17
|
+
font-size: 0.75rem !important;
|
|
18
|
+
font-weight: 500 !important;
|
|
19
|
+
border-radius: 4px !important;
|
|
20
|
+
padding: 0.5rem 0.75rem !important;
|
|
21
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1) !important;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.tooltipErrorMessage .p-tooltip-arrow {
|
|
25
|
+
border-top-color: var(--red-500, #ef4444) !important;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|