Skip to content

Commit bd59950

Browse files
committed
feat: user detail
1 parent bbfa0ed commit bd59950

10 files changed

+1764
-5
lines changed

app/components/users/UserBioPanel.vue

+249
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
<script setup lang="ts">
2+
import { avatarText, kFormatter } from '#imports'
3+
import type { UserWithRoles } from '~/stores/admin/user'
4+
5+
defineProps<{
6+
user: UserWithRoles
7+
}>()
8+
9+
const standardPlan = {
10+
plan: 'Standard',
11+
price: 99,
12+
benefits: ['10 Users', 'Up to 10GB storage', 'Basic Support'],
13+
}
14+
15+
const isUserInfoEditDialogVisible = ref(false)
16+
const isUpgradePlanDialogVisible = ref(false)
17+
18+
// 👉 Role variant resolver
19+
function resolveUserRoleVariant(role: string) {
20+
if (role === 'subscriber')
21+
return { color: 'primary', icon: 'ri-user-line' }
22+
if (role === 'author')
23+
return { color: 'warning', icon: 'ri-settings-2-line' }
24+
if (role === 'maintainer')
25+
return { color: 'success', icon: 'ri-database-2-line' }
26+
if (role === 'editor')
27+
return { color: 'info', icon: 'ri-pencil-line' }
28+
if (role === 'admin')
29+
return { color: 'error', icon: 'ri-server-line' }
30+
31+
return { color: 'primary', icon: 'ri-user-line' }
32+
}
33+
</script>
34+
35+
<template>
36+
<VRow>
37+
<!-- SECTION User Details -->
38+
<VCol cols="12">
39+
<VCard v-if="user">
40+
<VCardText class="text-center pt-12 pb-6">
41+
<!-- 👉 Avatar -->
42+
<VAvatar
43+
rounded="lg"
44+
:size="120"
45+
:color="!user.avatar_url ? 'primary' : undefined"
46+
:variant="!user.avatar_url ? 'tonal' : undefined"
47+
>
48+
<VImg
49+
v-if="user.avatar_url"
50+
:src="user.avatar_url"
51+
/>
52+
<span
53+
v-else
54+
class="text-5xl font-weight-medium"
55+
>
56+
{{ avatarText(user.full_name || 'User') }}
57+
</span>
58+
</VAvatar>
59+
60+
<!-- 👉 User fullName -->
61+
<h5 class="text-h5 mt-4">
62+
{{ user.full_name }}
63+
</h5>
64+
65+
<!-- 👉 Role chip -->
66+
<VChip
67+
:color="resolveUserRoleVariant(user.roles[0]?.role.name || '').color"
68+
size="small"
69+
class="text-capitalize mt-4"
70+
>
71+
{{ user.roles[0]?.role.name || '' }}
72+
</VChip>
73+
</VCardText>
74+
75+
<VCardText class="d-flex justify-center flex-wrap gap-6 pb-6">
76+
<!-- 👉 Done task -->
77+
<div class="d-flex align-center me-8">
78+
<VAvatar
79+
:size="40"
80+
rounded
81+
color="primary"
82+
variant="tonal"
83+
class="me-4"
84+
>
85+
<VIcon
86+
size="24"
87+
icon="ri-check-line"
88+
/>
89+
</VAvatar>
90+
91+
<div>
92+
<h5 class="text-h5">
93+
{{ kFormatter(456) }}
94+
</h5>
95+
<span>Task Done</span>
96+
</div>
97+
</div>
98+
99+
<!-- 👉 Done Project -->
100+
<div class="d-flex align-center me-4">
101+
<VAvatar
102+
:size="44"
103+
rounded
104+
color="primary"
105+
variant="tonal"
106+
class="me-4"
107+
>
108+
<VIcon
109+
size="24"
110+
icon="ri-briefcase-line"
111+
/>
112+
</VAvatar>
113+
114+
<div>
115+
<h5 class="text-h5">
116+
{{ kFormatter(123) }}
117+
</h5>
118+
<span>Project Done</span>
119+
</div>
120+
</div>
121+
</VCardText>
122+
123+
<!-- 👉 Details -->
124+
<VCardText class="pb-6">
125+
<h5 class="text-h5">
126+
Details
127+
</h5>
128+
129+
<VDivider class="my-4" />
130+
131+
<!-- 👉 User Details list -->
132+
<VList class="card-list">
133+
<VListItem>
134+
<VListItemTitle class="text-sm">
135+
<span class="font-weight-medium">Phone:</span>
136+
<span class="text-body-1">
137+
+{{ user.phone }}
138+
</span>
139+
</VListItemTitle>
140+
</VListItem>
141+
142+
<VListItem>
143+
<VListItemTitle class="text-sm">
144+
<span class="font-weight-medium">
145+
Billing Email:
146+
</span>
147+
<span class="text-body-1">{{ user.email }}</span>
148+
</VListItemTitle>
149+
</VListItem>
150+
151+
<VListItem>
152+
<VListItemTitle class="text-sm">
153+
<span class="font-weight-medium">
154+
Status:
155+
</span>
156+
<span class="text-body-1 text-capitalize">{{ user.status }}</span>
157+
</VListItemTitle>
158+
</VListItem>
159+
160+
<VListItem>
161+
<VListItemTitle class="text-sm">
162+
<span class="font-weight-medium">Role: </span>
163+
<span class="text-capitalize text-body-1">{{ user.roles[0]?.role.name || '' }}</span>
164+
</VListItemTitle>
165+
</VListItem>
166+
167+
<VListItem>
168+
<VListItemTitle class="text-sm">
169+
<span class="font-weight-medium">
170+
Country:
171+
</span>
172+
<span class="text-body-1">
173+
{{ user.country }}
174+
</span>
175+
</VListItemTitle>
176+
</VListItem>
177+
178+
<VListItem>
179+
<VListItemTitle class="text-sm">
180+
<span class="font-weight-medium">
181+
ZIP Code:
182+
</span>
183+
<span class="text-body-1">{{ user.postcode }}</span>
184+
</VListItemTitle>
185+
</VListItem>
186+
187+
<VListItem>
188+
<VListItemTitle class="text-sm">
189+
<span class="font-weight-medium">
190+
Language:
191+
</span>
192+
<span class="text-body-1">{{ user.language }}</span>
193+
</VListItemTitle>
194+
</VListItem>
195+
196+
<VListItem>
197+
<VListItemTitle class="text-sm">
198+
<span class="font-weight-medium">
199+
Country:
200+
</span>
201+
<span class="text-body-1">{{ user.country }}</span>
202+
</VListItemTitle>
203+
</VListItem>
204+
</VList>
205+
</VCardText>
206+
207+
<!-- 👉 Edit and Suspend button -->
208+
<VCardText class="d-flex justify-center">
209+
<VBtn
210+
variant="elevated"
211+
class="me-4"
212+
@click="isUserInfoEditDialogVisible = true"
213+
>
214+
Edit
215+
</VBtn>
216+
<VBtn
217+
variant="outlined"
218+
color="error"
219+
>
220+
Suspend
221+
</VBtn>
222+
</VCardText>
223+
</VCard>
224+
</VCol>
225+
</VRow>
226+
227+
<!-- 👉 Edit user info dialog -->
228+
<UserInfoEditDialog
229+
v-model:is-dialog-visible="isUserInfoEditDialogVisible"
230+
:user-data="user"
231+
/>
232+
233+
<!-- 👉 Upgrade plan dialog -->
234+
<UserUpgradePlanDialog v-model:is-dialog-visible="isUpgradePlanDialogVisible" />
235+
</template>
236+
237+
<style lang="scss" scoped>
238+
.card-list {
239+
--v-card-list-gap: 0.5rem;
240+
}
241+
242+
.current-plan {
243+
border: 2px solid rgb(var(--v-theme-primary));
244+
}
245+
246+
.text-capitalize {
247+
text-transform: capitalize !important;
248+
}
249+
</style>

0 commit comments

Comments
 (0)