feat: implement skeleton loading for DataTable component in Plans and Business Types pages
This commit is contained in:
parent
c62643f2ba
commit
ca32004d82
@ -27,6 +27,7 @@ import {
|
|||||||
TableRow,
|
TableRow,
|
||||||
} from '@/components/ui/table'
|
} from '@/components/ui/table'
|
||||||
import { valueUpdater } from '@/lib/utils'
|
import { valueUpdater } from '@/lib/utils'
|
||||||
|
import { Skeleton } from '@/components/ui/skeleton'
|
||||||
import DataTablePagination from './DataTablePagination.vue'
|
import DataTablePagination from './DataTablePagination.vue'
|
||||||
import {
|
import {
|
||||||
Empty, EmptyDescription,
|
Empty, EmptyDescription,
|
||||||
@ -36,6 +37,7 @@ import {
|
|||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
columns: ColumnDef<TData, TValue>[]
|
columns: ColumnDef<TData, TValue>[]
|
||||||
data: TData[]
|
data: TData[]
|
||||||
|
loading?: boolean
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const sorting = ref<SortingState>([])
|
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 })
|
defineExpose({ table })
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -99,7 +109,15 @@ defineExpose({ table })
|
|||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
<TableBody>
|
<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">
|
<template v-for="row in table.getRowModel().rows" :key="row.id">
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell v-for="cell in row.getVisibleCells()" :key="cell.id"
|
<TableCell v-for="cell in row.getVisibleCells()" :key="cell.id"
|
||||||
@ -131,6 +149,6 @@ defineExpose({ table })
|
|||||||
</Table>
|
</Table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<DataTablePagination :table="table" />
|
<DataTablePagination v-if="!loading" :table="table" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -222,10 +222,7 @@ watch(deleteOpen, (val) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="px-4 lg:px-6">
|
<div class="px-4 lg:px-6">
|
||||||
<div v-if="status === 'pending'" class="flex items-center justify-center h-24">
|
<DataTable ref="tableRef" :columns="columns" :data="businessTypes ?? []" :loading="status === 'pending'">
|
||||||
<p class="text-sm text-muted-foreground">Memuat data...</p>
|
|
||||||
</div>
|
|
||||||
<DataTable v-else ref="tableRef" :columns="columns" :data="businessTypes ?? []">
|
|
||||||
<template #filters="{ table }">
|
<template #filters="{ table }">
|
||||||
<div class="flex items-center gap-2 py-4">
|
<div class="flex items-center gap-2 py-4">
|
||||||
<Input class="max-w-sm" placeholder="Cari nama..."
|
<Input class="max-w-sm" placeholder="Cari nama..."
|
||||||
|
|||||||
@ -228,10 +228,7 @@ watch(deleteOpen, (val) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="px-4 lg:px-6">
|
<div class="px-4 lg:px-6">
|
||||||
<div v-if="status === 'pending'" class="flex items-center justify-center h-24">
|
<DataTable ref="tableRef" :columns="columns" :data="plans ?? []" :loading="status === 'pending'">
|
||||||
<p class="text-sm text-muted-foreground">Memuat data...</p>
|
|
||||||
</div>
|
|
||||||
<DataTable v-else ref="tableRef" :columns="columns" :data="plans ?? []">
|
|
||||||
<template #filters="{ table }">
|
<template #filters="{ table }">
|
||||||
<div class="flex items-center gap-2 py-4">
|
<div class="flex items-center gap-2 py-4">
|
||||||
<Input class="max-w-sm" placeholder="Cari nama..."
|
<Input class="max-w-sm" placeholder="Cari nama..."
|
||||||
|
|||||||
35
docs/history/2026-07-25-skeleton-loading-table.md
Normal file
35
docs/history/2026-07-25-skeleton-loading-table.md
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
# Skeleton Loading Table
|
||||||
|
|
||||||
|
**Tanggal:** 2026-07-25
|
||||||
|
**Status:** Selesai
|
||||||
|
|
||||||
|
## Tujuan
|
||||||
|
Mengganti indikator loading "Memuat data..." pada tabel di halaman Plans dan Business Types dengan skeleton loading.
|
||||||
|
|
||||||
|
## 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` 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
|
||||||
|
- Sama seperti implementasi yang sudah diterapkan di folder `core`
|
||||||
|
- Komponen `Skeleton` tersedia di `@/components/ui/skeleton`
|
||||||
Loading…
Reference in New Issue
Block a user