refactor: implement user management API and update dashboard users page with new data table
This commit is contained in:
@@ -1,56 +0,0 @@
|
||||
type TUsers = {
|
||||
id: number
|
||||
idTransaction: number
|
||||
date: string
|
||||
name: string
|
||||
email: string
|
||||
category: string
|
||||
status: string
|
||||
}
|
||||
export const USERS: TUsers[] = [
|
||||
{
|
||||
id: 1,
|
||||
idTransaction: 5_512_446_588,
|
||||
date: '24/10/2024',
|
||||
name: 'Ainun Wijaya',
|
||||
email: 'ainun@gmail.com',
|
||||
category: 'Pribadi',
|
||||
status: 'Baru',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
idTransaction: 5_512_446_588,
|
||||
date: '24/10/2024',
|
||||
name: 'Ainun Wijaya',
|
||||
email: 'ainun@gmail.com',
|
||||
category: 'Pribadi',
|
||||
status: 'Premium',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
idTransaction: 5_512_446_588,
|
||||
date: '24/10/2024',
|
||||
name: 'Ainun Wijaya',
|
||||
email: 'ainun@gmail.com',
|
||||
category: 'Pribadi',
|
||||
status: 'Pembayaran',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
idTransaction: 5_512_446_588,
|
||||
date: '24/10/2024',
|
||||
name: 'Ainun Wijaya',
|
||||
email: 'ainun@gmail.com',
|
||||
category: 'Pribadi',
|
||||
status: 'Premium',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
idTransaction: 5_512_446_588,
|
||||
date: '24/10/2024',
|
||||
name: 'Ainun Wijaya',
|
||||
email: 'ainun@gmail.com',
|
||||
category: 'Pribadi',
|
||||
status: 'Baru',
|
||||
},
|
||||
]
|
||||
@@ -1,110 +1,98 @@
|
||||
import { Field, Input, Label, Select } from '@headlessui/react'
|
||||
import DT, { type ConfigColumns } from 'datatables.net-dt'
|
||||
import DataTable, { type DataTableSlots } from 'datatables.net-react'
|
||||
import { useRouteLoaderData } from 'react-router'
|
||||
|
||||
import { SearchIcon } from '~/components/icons/search'
|
||||
import { Pagination } from '~/components/ui/pagination'
|
||||
import type { TUserResponse } from '~/apis/admin/get-users'
|
||||
import { UiTable } from '~/components/ui/table'
|
||||
import { TitleDashboard } from '~/components/ui/title-dashboard'
|
||||
|
||||
import { USERS } from './data'
|
||||
import type { loader } from '~/routes/_admin.lg-admin._dashboard.users._index'
|
||||
import { formatDate } from '~/utils/formatter'
|
||||
|
||||
type TColorBadge = 'Baru' | 'Premium' | 'Pembayaran'
|
||||
|
||||
const getStatusBadge = (status: TColorBadge) => {
|
||||
const statusColors = {
|
||||
Baru: 'bg-[#DFE5FF] text-[#4C5CA0]',
|
||||
Premium: 'bg-[#FFFCAF] text-[#DBCA6E]',
|
||||
Pembayaran: 'bg-[#FEC4FF] text-[#CC6EDB]',
|
||||
}
|
||||
return statusColors[status] || 'bg-gray-200 text-gray-700'
|
||||
}
|
||||
export const UsersPage = () => {
|
||||
const getStatusBadge = (status: TColorBadge) => {
|
||||
const statusColors = {
|
||||
Baru: 'bg-[#DFE5FF] text-[#4C5CA0]',
|
||||
Premium: 'bg-[#FFFCAF] text-[#DBCA6E]',
|
||||
Pembayaran: 'bg-[#FEC4FF] text-[#CC6EDB]',
|
||||
}
|
||||
return statusColors[status] || 'bg-gray-200 text-gray-700'
|
||||
const loaderData = useRouteLoaderData<typeof loader>(
|
||||
'routes/_admin.lg-admin._dashboard.users._index',
|
||||
)
|
||||
|
||||
DataTable.use(DT)
|
||||
const dataTable =
|
||||
loaderData?.usersData?.sort(
|
||||
(a, b) =>
|
||||
new Date(b.subscribe.start_date).getTime() -
|
||||
new Date(a.subscribe.start_date).getTime(),
|
||||
) || []
|
||||
|
||||
const dataColumns: ConfigColumns[] = [
|
||||
{
|
||||
title: 'No',
|
||||
render: (
|
||||
_data: unknown,
|
||||
_type: unknown,
|
||||
_row: unknown,
|
||||
meta: { row: number },
|
||||
) => {
|
||||
return meta.row + 1
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Tanggal Daftar',
|
||||
data: 'subscribe.start_date',
|
||||
},
|
||||
{
|
||||
title: 'Nama User',
|
||||
},
|
||||
{
|
||||
title: 'Email',
|
||||
data: 'email',
|
||||
},
|
||||
{
|
||||
title: 'Kategori',
|
||||
data: 'subscribe.status',
|
||||
},
|
||||
{
|
||||
title: 'Status',
|
||||
data: 'subscribe.subscribe_plan.name',
|
||||
},
|
||||
]
|
||||
const dataSlot: DataTableSlots = {
|
||||
1: (value: string) => formatDate(value),
|
||||
2: (_value: unknown, _type: unknown, data: TUserResponse) => (
|
||||
<div>
|
||||
<div>{data.phone}</div>
|
||||
<div className="text-sm text-[#7C7C7C]">ID: {data.id.slice(0, 8)}</div>
|
||||
</div>
|
||||
),
|
||||
4: (_value: string) => <span className="text-sm">Pribadi</span>,
|
||||
5: (value: TColorBadge) => (
|
||||
<span className={`rounded-lg px-2 text-sm ${getStatusBadge(value)}`}>
|
||||
{value}
|
||||
</span>
|
||||
),
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
<TitleDashboard title="Users" />
|
||||
{/* filter section */}
|
||||
|
||||
<div className="mb-8 flex items-center gap-5 rounded-lg bg-gray-50 text-[#363636]">
|
||||
<div className="w-[400px]">
|
||||
<Field>
|
||||
<Label className="mb-2 block text-sm font-medium">Cari User</Label>
|
||||
<div className="relative">
|
||||
<Input
|
||||
type="text"
|
||||
placeholder="Cari Nama"
|
||||
className="w-full rounded-lg bg-white p-2 pr-10 pl-4 shadow focus:ring-1 focus:ring-[#2E2F7C] focus:outline-none"
|
||||
/>
|
||||
<div className="absolute inset-y-0 right-0 flex items-center pr-3">
|
||||
<SearchIcon className="h-5 w-5" />
|
||||
</div>
|
||||
</div>
|
||||
</Field>
|
||||
</div>
|
||||
|
||||
<div className="w-[235px]">
|
||||
<Field>
|
||||
<Label className="mb-2 block text-sm font-medium">Status</Label>
|
||||
<Select className="w-full rounded-lg bg-white p-2 shadow focus:ring-1 focus:ring-[#2E2F7C] focus:outline-none">
|
||||
<option>Pilih Status</option>
|
||||
<option>Aktif</option>
|
||||
<option>Nonaktif</option>
|
||||
</Select>
|
||||
</Field>
|
||||
</div>
|
||||
<div className="mb-8 flex items-end justify-between gap-5">
|
||||
<div className="flex-1">{/* TODO: Filter */}</div>
|
||||
</div>
|
||||
|
||||
{/* table */}
|
||||
<div className="overflow-x-auto">
|
||||
<div className="rounded-lg bg-white px-6 py-8 shadow-sm">
|
||||
<h2 className="text-xl font-bold text-[#4C5CA0]">Daftar User</h2>
|
||||
<table className="min-w-full p-3">
|
||||
<thead className="my-5 border-b-3 border-[#C2C2C2]">
|
||||
<tr>
|
||||
<th className="p-3">No</th>
|
||||
<th>Tanggal Daftar</th>
|
||||
<th>Nama User</th>
|
||||
<th>Email</th>
|
||||
<th>Kategori</th>
|
||||
<th>Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{USERS.map((user, index) => (
|
||||
<tr
|
||||
key={user.id}
|
||||
className="border-b-1 border-gray-200 text-center"
|
||||
>
|
||||
<td className="p-4">{index + 1}</td>
|
||||
<td>{user.date}</td>
|
||||
<td>
|
||||
{user.name}
|
||||
<div className="text-sm text-gray-500">
|
||||
id: {user.idTransaction}
|
||||
</div>
|
||||
</td>
|
||||
<td>{user.email}</td>
|
||||
<td>{user.category}</td>
|
||||
<td className="">
|
||||
<span
|
||||
className={`inline-block min-w-[100px] rounded-full px-2 py-1 text-sm ${getStatusBadge(user.status as TColorBadge)}`}
|
||||
>
|
||||
{user.status}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{/* pagination */}
|
||||
<div className="float-end mt-6">
|
||||
<Pagination
|
||||
currentPage={1}
|
||||
totalPages={5}
|
||||
onPageChange={() => {}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<UiTable
|
||||
data={dataTable || []}
|
||||
columns={dataColumns}
|
||||
slots={dataSlot}
|
||||
title="Daftar Users"
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user