Files
antrean-operasi/pages/setting/hak-akses/index.vue
T
2026-02-18 08:21:58 +07:00

204 lines
6.3 KiB
Vue

<script setup lang="ts">
import TableAntrian from '@/components/pendaftaran/TableAntrian.vue';
import type { HakAkses } from '~/types/setting';
const page = ref({ title: 'Hak Akses' });
const breadcrumbs = ref([
{
text: 'Setting',
disabled: false,
href: '#'
},
{
text: 'Hak Akses',
disabled: true,
href: '#'
}
]);
const router = useRouter();
const search = ref('');
const hakAksesList = ref<HakAkses[]>([]);
const loading = ref(false);
// Snackbar state
const snackbar = ref(false);
const snackbarMessage = ref('');
const snackbarColor = ref('success');
const showSnackbar = (message: string, color: string = 'success') => {
snackbarMessage.value = message;
snackbarColor.value = color;
snackbar.value = true;
};
// Load data from API
const loadData = async () => {
loading.value = true;
try {
const response = await $fetch('/api/hak-akses');
if (response && typeof response === 'object' && 'success' in response && response.success && 'data' in response) {
hakAksesList.value = Array.isArray(response.data) ? response.data : [];
}
} catch (error) {
console.error('Error loading hak akses:', error);
showSnackbar('Gagal memuat data', 'error');
} finally {
loading.value = false;
}
};
const headers = [
{ title: 'No', key: 'no', width: '100px', align: 'center' as const },
{ title: 'Nama Hak Akses', key: 'namaHakAkses', sortable: true },
{ title: 'Status', key: 'status', sortable: true, align: 'center' as const },
{ title: 'Actions', key: 'actions', sortable: false }
];
const actions = [
{ icon: 'mdi-eye', color: 'info', tooltip: 'View', event: 'view' },
{ icon: 'mdi-pencil', color: 'primary', tooltip: 'Edit', event: 'edit' },
{ icon: 'mdi-delete', color: 'error', tooltip: 'Delete', event: 'delete' }
];
const handleView = (item: unknown) => {
const data = item as HakAkses;
router.push({
path: '/setting/hak-akses/form',
query: {
mode: 'view',
id: data.id
}
});
};
const handleEdit = (item: unknown) => {
const data = item as HakAkses;
router.push({
path: '/setting/hak-akses/form',
query: {
mode: 'edit',
id: data.id
}
});
};
const handleDelete = async (item: unknown) => {
const data = item as HakAkses;
if (confirm(`Apakah Anda yakin ingin menghapus hak akses "${data.namaHakAkses}"?`)) {
loading.value = true;
try {
const response = await $fetch(`/api/hak-akses/${data.id}`, {
method: 'DELETE'
});
if (response && typeof response === 'object' && 'success' in response && response.success) {
// Remove from list locally
const index = hakAksesList.value.findIndex(h => h.id === data.id);
if (index > -1) {
hakAksesList.value.splice(index, 1);
}
const message = 'message' in response && typeof response.message === 'string'
? response.message
: 'Hak akses berhasil dihapus';
showSnackbar(message, 'success');
} else {
const message = response && typeof response === 'object' && 'message' in response && typeof response.message === 'string'
? response.message
: 'Gagal menghapus hak akses';
showSnackbar(message, 'error');
}
} catch (error) {
console.error('Error deleting hak akses:', error);
showSnackbar('Terjadi kesalahan saat menghapus data', 'error');
} finally {
loading.value = false;
}
}
};
// Load data on mount
onMounted(() => {
loadData();
});
definePageMeta({
middleware: 'auth',
pageTitle: 'Hak Akses',
});
</script>
<template>
<v-row>
<v-col cols="12">
<v-card elevation="10">
<v-card-text>
<div class="d-flex justify-space-between align-center mb-4">
<v-text-field
v-model="search"
placeholder="Search..."
variant="outlined"
density="comfortable"
hide-details
prepend-inner-icon="mdi-magnify"
style="max-width: 400px;"
></v-text-field>
<v-btn
color="primary"
prepend-icon="mdi-plus"
to="/setting/hak-akses/form"
>
Tambah Hak Akses
</v-btn>
</div>
<TableAntrian
:headers="headers"
:items="hakAksesList"
:search="search"
:actions="actions"
:loading="loading"
min-width="900px"
@view="handleView"
@edit="handleEdit"
@delete="handleDelete"
>
<template #item.no="{ index }">
{{ index + 1 }}
</template>
<template #item.status="{ item }">
<v-chip
:color="item.status === 'aktif' ? 'success' : 'error'"
size="small"
>
{{ item.status }}
</v-chip>
</template>
</TableAntrian>
</v-card-text>
</v-card>
</v-col>
</v-row>
<!-- Snackbar for notifications -->
<v-snackbar
v-model="snackbar"
:color="snackbarColor"
:timeout="3000"
location="top"
>
{{ snackbarMessage }}
<template #actions>
<v-btn
variant="text"
@click="snackbar = false"
>
Close
</v-btn>
</template>
</v-snackbar>
</template>