feat: implement UiTable component and refactor dashboard pages to use it

This commit is contained in:
fredy.siswanto 2025-03-04 00:21:14 +07:00
parent 1538869e49
commit 120450fd7c
5 changed files with 228 additions and 109 deletions

View File

@ -0,0 +1,42 @@
import DT, { type Config, type ConfigColumns } from 'datatables.net-dt'
import DataTable from 'datatables.net-react'
import React from 'react'
export type UiTableProperties = {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
data: any[]
columns: ConfigColumns[]
slots?: any // eslint-disable-line @typescript-eslint/no-explicit-any
options?: Config
title: string
}
export const UiTable: React.FC<UiTableProperties> = ({
data,
columns,
slots,
options,
title,
}) => {
DataTable.use(DT)
return (
<div className="rounded-lg bg-white p-5 shadow-md">
<h3 className="py-1 font-semibold text-[#4C5CA0]">{title}</h3>
<div className="rounded-lg">
<DataTable
className="cell-border"
data={data}
columns={columns}
slots={slots}
options={{
paging: true,
searching: true,
ordering: true,
info: true,
...options,
}}
/>
</div>
</div>
)
}

View File

@ -1,8 +1,11 @@
import type { TNews } from '~/types/news'
type TBanner = {
id: number
urlImage: string
alt: string
link: string
status: 'active' | 'draft' | 'inactive'
createdAt?: string
}
export const DUMMY_DESCRIPTION = 'Berita Terhangat hari ini'
@ -155,18 +158,43 @@ export const KAJIAN: TNews = {
export const BANNER: TBanner[] = [
{
id: 1,
urlImage: '/images/banner.png',
alt: 'banner',
link: '/category/spotlight',
status: 'active',
createdAt: '2021-08-01',
},
{
id: 2,
urlImage: 'https://placehold.co/1000x65.png',
alt: 'banner',
status: 'draft',
link: '/#',
createdAt: '2021-08-01',
},
{
id: 3,
urlImage: 'https://placehold.co/1000x65.png',
alt: 'banner',
status: 'draft',
link: '/#',
createdAt: '2021-08-01',
},
{
id: 4,
urlImage: '/images/banner.png',
alt: 'banner',
link: '/#',
status: 'active',
createdAt: '2021-08-01',
},
{
id: 5,
urlImage: '/images/banner.png',
alt: 'banner',
link: '/#',
status: 'inactive',
createdAt: '2021-08-01',
},
]

View File

@ -1,12 +1,17 @@
import { Field, Input, Label } from '@headlessui/react'
import { useState } from 'react'
import { twMerge } from 'tailwind-merge'
import { PlusIcon } from '~/components/icons/plus'
import { UiTable } from '~/components/ui/table'
import { TitleDashboard } from '~/components/ui/title-dashboard'
import { BANNER } from '~/data/contents'
type BannerUploadProperties = {
onBannerChange?: (file: File | undefined) => void
onLinkChange?: (link: string) => void
}
type TStatusColors = 'draft' | 'active' | 'inactive'
export const AdvertisementsPage = ({
onBannerChange,
@ -27,19 +32,51 @@ export const AdvertisementsPage = ({
onLinkChange?.(newLink)
}
const dataBanner = BANNER
const dataColumns = [
{ title: 'No', data: 'id' },
{ title: 'Banner', data: 'urlImage' },
{ title: 'Link', data: 'link' },
{ title: 'Tgl Create', data: 'createdAt' },
{ title: 'Status', data: 'status' },
]
const dataSlot = {
1: (value: string) => {
return (
<div className="w-[400px] rounded-xl bg-gray-50 p-6">
{banner && (
<div className="h-[100px] w-[200px]">
<div className="mb-4">
<div>
<img
src={URL.createObjectURL(banner)}
alt="Banner Preview"
className="h-auto w-full rounded-lg"
src={value}
alt={`banner - ${value}`}
className="aspect-[15/1] h-[50px] max-w-[200px] rounded"
/>
</div>
</div>
)
},
4: (value: string) => {
const statusColors = {
draft: 'bg-gray-300',
active: 'bg-[#04D182]',
inactive: 'bg-[#F96D19]',
}
const status = value as TStatusColors
return (
<span
className={twMerge(
'rounded-md px-2 py-1 text-sm',
status ? statusColors[status] : '',
)}
>
{status}
</span>
)
},
}
return (
<div className="relative">
<TitleDashboard title="Advertisement" />
<div className="flex gap-5">
<div className="w-[400px] rounded-xl bg-gray-50 py-6">
<Field className="mb-6">
<Label className="mb-2 block text-sm font-bold text-gray-700">
Banner Design
@ -77,5 +114,24 @@ export const AdvertisementsPage = ({
/>
</Field>
</div>
{banner && (
<div className="h-[100px] w-[200px] shadow-2xl">
<div className="mb-4">
<img
src={URL.createObjectURL(banner)}
alt="Banner Preview"
className="h-max-[350px] rasio-15-1 w-full rounded-lg"
/>
</div>
</div>
)}
</div>
<UiTable
data={dataBanner}
columns={dataColumns}
slots={dataSlot}
title="Daftar Banner"
/>
</div>
)
}

View File

@ -4,13 +4,15 @@ import DataTable from 'datatables.net-react'
import { SearchIcon } from '~/components/icons/search'
import { Button } from '~/components/ui/button'
import { UiTable } from '~/components/ui/table'
import { TitleDashboard } from '~/components/ui/title-dashboard'
import { CONTENTS } from './data'
export const ContentsPage = () => {
DataTable.use(DT)
const columns = [
const dataTable = CONTENTS
const dataColumns = [
{ title: 'No', data: 'id' },
{ title: 'Tanggal Kontent', data: 'createdAt' },
{ title: 'Nama Penulis', data: 'author' },
@ -30,6 +32,27 @@ export const ContentsPage = () => {
data: 'id',
},
]
const dataSlot = {
6: (value: string | number) => {
return (
<Button
as="a"
href={`/lg-admin/contents/update/${value}`}
className="text-md rounded-md"
size="sm"
>
Lihat Detail
</Button>
)
},
}
const dataOptions = {
paging: true,
searching: true,
ordering: true,
info: true,
// scrollY: '50vh',
}
return (
<div className="relative">
@ -62,35 +85,14 @@ export const ContentsPage = () => {
</Field>
</div>
</div>
<div className="rounded-lg bg-white p-6 shadow-md">
<h3 className="py-1 font-semibold text-[#4C5CA0]">Daftar Content</h3>
<DataTable
className="cell-border"
data={CONTENTS}
columns={columns}
slots={{
6: (value: string | number) => {
return (
<Button
as="a"
href={`/lg-admin/contents/update/${value}`}
className="text-md rounded-md"
size="sm"
>
Lihat Detail
</Button>
)
},
}}
options={{
paging: true,
searching: true,
ordering: true,
info: true,
// scrollY: '50vh',
}}
></DataTable>
</div>
<UiTable
data={dataTable}
columns={dataColumns}
slots={dataSlot}
options={dataOptions}
title="Daftar Konten"
/>
</div>
)
}

View File

@ -5,6 +5,7 @@ import { useState } from 'react'
import { SearchIcon } from '~/components/icons/search'
import { Button } from '~/components/ui/button'
import { UiTable } from '~/components/ui/table'
import { TitleDashboard } from '~/components/ui/title-dashboard'
import { SUBSCRIPTIONS, SUBSETTINGS } from './data'
@ -91,13 +92,7 @@ export const SubscriptionsPage = () => {
</div>
</div>
<div className="rounded-lg bg-white p-6 shadow-md">
<h3 className="py-1 font-semibold text-[#4C5CA0]">
Daftar Subscription
</h3>
<DataTable
// className="cell-border"
<UiTable
data={SUBSCRIPTIONS}
columns={colTableSubscription}
options={{
@ -106,8 +101,8 @@ export const SubscriptionsPage = () => {
ordering: true,
info: true,
}}
></DataTable>
</div>
title="Daftar Subscription"
/>
</>
)}
@ -156,12 +151,8 @@ export const SubscriptionsPage = () => {
</Field>
</div>
</div>
<div className="rounded-lg bg-white p-6 shadow-md">
<h3 className="py-1 font-semibold text-[#4C5CA0]">
Daftar Subscription
</h3>
<DataTable
className="cell-border"
<UiTable
data={SUBSETTINGS}
columns={colTableSubSetting}
options={{
@ -170,8 +161,8 @@ export const SubscriptionsPage = () => {
ordering: true,
info: true,
}}
></DataTable>
</div>
title=" Daftar Subscription"
/>
</>
)}
</div>