first init
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
<script lang="ts" setup>
|
||||
import { onMounted } from 'vue'
|
||||
import { Search, HatGlasses } from '@lucide/vue'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Input } from '@/components/ui/input'
|
||||
import DataTable from '@/components/ui/usage/DataTable.vue'
|
||||
import type { TableHeader } from '@/components/ui/usage/DataTable.vue'
|
||||
import { useImpersonate } from '../composables/useImpersonate'
|
||||
import { useUserList } from '../composables/useUserList'
|
||||
import type { UserRole, UserListItem } from '../types/user.types'
|
||||
import { AlertRoot, AlertTitle, AlertDescription } from '@/components/ui/alert'
|
||||
|
||||
function formatUserRoles(roles: UserRole[] | undefined): string {
|
||||
return roles?.map((role) => role.name).join(', ') || '-'
|
||||
}
|
||||
|
||||
function statusBadgeVariant(status: string) {
|
||||
if (status === 'active') return 'success'
|
||||
if (status === 'inactive') return 'danger'
|
||||
return 'pending'
|
||||
}
|
||||
|
||||
const headers: TableHeader[] = [
|
||||
{ title: 'Bil.', key: '#', sortable: false },
|
||||
{ title: 'Name', key: 'name', sortable: true },
|
||||
{ title: 'Emel', key: 'email', sortable: true },
|
||||
{ title: 'Jawatan', key: 'position', sortable: true },
|
||||
{
|
||||
title: 'Peranan',
|
||||
key: 'roles',
|
||||
sortable: false,
|
||||
exportValue: (item) => formatUserRoles(item.roles),
|
||||
},
|
||||
{ title: 'Status Pengguna', key: 'status', sortable: true },
|
||||
{ title: 'Tindakan', key: 'actions', sortable: false },
|
||||
]
|
||||
|
||||
const {
|
||||
users,
|
||||
loading,
|
||||
error,
|
||||
search,
|
||||
sortBy,
|
||||
page,
|
||||
itemsPerPage,
|
||||
pagination,
|
||||
handleSortUpdate,
|
||||
} = useUserList()
|
||||
|
||||
const {
|
||||
canImpersonateUser,
|
||||
impersonating,
|
||||
loading: impersonateLoading,
|
||||
refreshImpersonationStatus,
|
||||
impersonateUser,
|
||||
} = useImpersonate()
|
||||
|
||||
onMounted(() => {
|
||||
refreshImpersonationStatus()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="w-full space-y-6">
|
||||
<AlertRoot v-if="error" class="mt-6" variant="danger">
|
||||
<AlertTitle>Error</AlertTitle>
|
||||
<AlertDescription>{{ error }}</AlertDescription>
|
||||
</AlertRoot>
|
||||
|
||||
<DataTable :headers="headers" :items="users" :loading="loading" :pagination="pagination" :current-sort="sortBy"
|
||||
show-pagination exportable export-file-name="users" v-model:page="page" v-model:items-per-page="itemsPerPage"
|
||||
@update:sort-by="handleSortUpdate">
|
||||
<template #toolbar>
|
||||
<div class="relative w-full max-w-md">
|
||||
<Search class="pointer-events-none absolute top-1/2 left-3 z-10 size-4 -translate-y-1/2 text-foreground/50"
|
||||
aria-hidden="true" />
|
||||
<Input v-model="search" type="search" placeholder="Search name, email, IC, phone, role..." class="w-full pl-9"
|
||||
aria-label="Search users" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #item.name="{ item }">
|
||||
<span class="font-medium">{{ item.name }}</span>
|
||||
</template>
|
||||
|
||||
<template #item.email="{ item }">
|
||||
<span class="lowercase">{{ item.email }}</span>
|
||||
</template>
|
||||
|
||||
<template #item.roles="{ item }">
|
||||
{{ formatUserRoles(item.roles) }}
|
||||
</template>
|
||||
|
||||
<template #item.status="{ item }">
|
||||
<Badge :variant="statusBadgeVariant(item.status)" class="capitalize">
|
||||
{{ item.status }}
|
||||
</Badge>
|
||||
</template>
|
||||
|
||||
<template #item.actions="{ item }">
|
||||
<Button v-if="canImpersonateUser(item as UserListItem)" type="button" variant="outline" size="sm"
|
||||
class="gap-1.5 bg-orange-500 text-white" :disabled="impersonateLoading || impersonating"
|
||||
:title="impersonating ? 'Anda sedang menyamar pengguna' : 'Menyamar sebagai pengguna'"
|
||||
@click="impersonateUser(item as UserListItem)">
|
||||
<HatGlasses class="size-4" aria-hidden="true" />
|
||||
</Button>
|
||||
</template>
|
||||
</DataTable>
|
||||
</div>
|
||||
</template>
|
||||
Reference in New Issue
Block a user