Add skeleton loading to DataTable component

- Introduced `loading` prop to DataTable for handling loading state
- Replaced loading text with skeleton rows during data fetch
- Updated Business Types and Plans pages to utilize the new loading prop
This commit is contained in:
Yoga Pangestu 2026-07-25 10:31:30 +07:00
parent 5c916bb87a
commit f637eebe70
4 changed files with 57 additions and 10 deletions

View File

@ -27,6 +27,7 @@ import {
TableRow,
} from '@/components/ui/table'
import { valueUpdater } from '@/lib/utils'
import { Skeleton } from '@/components/ui/skeleton'
import DataTablePagination from './DataTablePagination.vue'
import {
Empty, EmptyDescription,
@ -36,6 +37,7 @@ import {
const props = defineProps<{
columns: ColumnDef<TData, TValue>[]
data: TData[]
loading?: boolean
}>()
const sorting = ref<SortingState>([])
@ -81,6 +83,14 @@ const table = useVueTable({
},
})
function skeletonWidth(columnId: string) {
switch (columnId) {
case 'number': return 'w-6'
case 'actions': return 'w-8'
default: return 'w-full'
}
}
defineExpose({ table })
</script>
@ -99,7 +109,15 @@ defineExpose({ table })
</TableRow>
</TableHeader>
<TableBody>
<template v-if="table.getRowModel().rows?.length">
<template v-if="loading">
<TableRow v-for="i in 5" :key="i">
<TableCell v-for="col in allColumns" :key="col.id"
:class="['actions', 'number'].includes(col.id) ? 'w-0' : ''">
<Skeleton class="h-5 w-full" :class="skeletonWidth(col.id)" />
</TableCell>
</TableRow>
</template>
<template v-else-if="table.getRowModel().rows?.length">
<template v-for="row in table.getRowModel().rows" :key="row.id">
<TableRow>
<TableCell v-for="cell in row.getVisibleCells()" :key="cell.id"
@ -131,6 +149,6 @@ defineExpose({ table })
</Table>
</div>
<DataTablePagination :table="table" />
<DataTablePagination v-if="!loading" :table="table" />
</div>
</template>

View File

@ -222,10 +222,7 @@ watch(deleteOpen, (val) => {
</div>
</div>
<div class="px-4 lg:px-6">
<div v-if="status === 'pending'" class="flex items-center justify-center h-24">
<p class="text-sm text-muted-foreground">Memuat data...</p>
</div>
<DataTable v-else ref="tableRef" :columns="columns" :data="businessTypes ?? []">
<DataTable ref="tableRef" :columns="columns" :data="businessTypes ?? []" :loading="status === 'pending'">
<template #filters="{ table }">
<div class="flex items-center gap-2 py-4">
<Input class="max-w-sm" placeholder="Cari nama..."

View File

@ -228,10 +228,7 @@ watch(deleteOpen, (val) => {
</div>
</div>
<div class="px-4 lg:px-6">
<div v-if="status === 'pending'" class="flex items-center justify-center h-24">
<p class="text-sm text-muted-foreground">Memuat data...</p>
</div>
<DataTable v-else ref="tableRef" :columns="columns" :data="plans ?? []">
<DataTable ref="tableRef" :columns="columns" :data="plans ?? []" :loading="status === 'pending'">
<template #filters="{ table }">
<div class="flex items-center gap-2 py-4">
<Input class="max-w-sm" placeholder="Cari nama..."

View File

@ -0,0 +1,35 @@
# Skeleton Loading Table
**Tanggal:** 2026-07-25
**Status:** Selesai
## Tujuan
Mengganti indikator loading "Memuat data..." pada tabel dengan skeleton loading yang menampilkan struktur tabel (header + baris skeleton) saat data sedang dimuat.
## Yang Dikerjakan
### 1. Penambahan `loading` prop di DataTable.vue
- Menambahkan prop `loading` (boolean, default `false`)
- Saat `loading === true`: menampilkan 5 baris skeleton menggunakan komponen `Skeleton` dengan jumlah kolom sesuai definisi kolom
- Pagination disembunyikan saat loading
- Kolom `number` dan `actions` tetap menggunakan lebar kecil (`w-6`, `w-8`)
### 2. Perubahan halaman Plans
- Sebelum: `v-if="status === 'pending'"` menampilkan teks "Memuat data..."
- Sesudah: DataTable selalu ditampilkan dengan `:loading="status === 'pending'"`
### 3. Perubahan halaman Business Types
- Sebelum: `v-if="status === 'pending'"` menampilkan teks "Memuat data..."
- Sesudah: DataTable selalu ditampilkan dengan `:loading="status === 'pending'"`
## File yang Diubah
| File | Aksi | Detail |
|------|------|--------|
| `app/components/data-table/DataTable.vue` | Diubah | Tambah `loading` prop, `Skeleton` import, skeleton rows, `skeletonWidth` helper |
| `app/pages/admin/plans/index.vue` | Diubah | Ganti `v-if="status === 'pending'"` dengan `:loading` prop pada DataTable |
| `app/pages/admin/business-types/index.vue` | Diubah | Ganti `v-if="status === 'pending'"` dengan `:loading` prop pada DataTable |
## Notes
- Komponen `Skeleton` sudah tersedia di `@/components/ui/skeleton`
- Saat loading, DataTable header tetap terlihat + 5 baris skeleton yang menyesuaikan jumlah kolom