From 6bfa48bed88a344ec017fc3494fbd41168cf0444 Mon Sep 17 00:00:00 2001 From: Hafid Nur Date: Thu, 27 Mar 2025 17:22:04 +0700 Subject: [PATCH] feat: Change data table component dynamically - Ubah komponen DataTable agar bisa render menyesuaikan jumlah kolom dan baris pada data --- apps/backoffice/src/app/accounts/page.tsx | 47 +++++++- apps/backoffice/src/app/transactions/page.tsx | 92 ++++++++++++-- libs/ui/src/organisms/datatable/datatable.tsx | 112 ++++++++++-------- 3 files changed, 187 insertions(+), 64 deletions(-) diff --git a/apps/backoffice/src/app/accounts/page.tsx b/apps/backoffice/src/app/accounts/page.tsx index ce9aa4e..c68bbc0 100644 --- a/apps/backoffice/src/app/accounts/page.tsx +++ b/apps/backoffice/src/app/accounts/page.tsx @@ -1,11 +1,24 @@ import { FC, ReactElement, useState } from 'react'; -import { FilterOutlined, SearchOutlined } from '@ant-design/icons'; +import { + FilterOutlined, + SearchOutlined, + EditOutlined, +} from '@ant-design/icons'; import { Button, Input } from '@imphnen-frontend-service/ui/atoms'; import { Pagination } from '@imphnen-frontend-service/ui/molecules'; import { DataTable } from '@imphnen-frontend-service/ui/organisms'; +// Define account interface +interface Account { + id: number; + name: string; + email: string; + phone: string; + address: string; +} + // Mock data for demonstration -const mockData = Array.from({ length: 20 }, (_, i) => ({ +const mockData: Account[] = Array.from({ length: 20 }, (_, i) => ({ id: i + 1, name: i === 0 ? 'Ahmad Wijuana' : 'Nama Lengkap', email: 'Fullname23@gmail.com', @@ -79,7 +92,35 @@ export const Components: FC = (): ReactElement => { {/* Table */} - + index + 1 + indexOfFirstItem, + }, + { label: 'Nama Lengkap', key: 'name' }, + { label: 'Email', key: 'email' }, + { label: 'Nomor Telp', key: 'phone' }, + { label: 'Alamat Pengiriman', key: 'address' }, + { + label: 'Action', + render: (item: Account) => ( + + ), + }, + ]} + /> {/* Pagination */} ({ +// Define status type for better type safety +type TransactionStatus = 'valid' | 'invalid' | 'unchecked'; + +// Define transaction interface +interface Transaction { + id: number; + name: string; + transactionNumber: string; + status: TransactionStatus; +} + +// Mock data for transactions +const mockTransactions: Transaction[] = Array.from({ length: 20 }, (_, i) => ({ id: i + 1, name: i === 0 ? 'Ahmad Wijuana' : 'Nama Lengkap', - email: 'Fullname23@gmail.com', - phone: '081904423804', - address: 'Jl. Pantai Cibaduyut Indonesia', + transactionNumber: '25D2133Y9AFYBD', + status: (i % 3 === 0 + ? 'invalid' + : i % 5 === 0 + ? 'unchecked' + : 'valid') as TransactionStatus, })); export const Components: FC = (): ReactElement => { @@ -19,10 +37,10 @@ export const Components: FC = (): ReactElement => { const itemsPerPage = 9; // Filter data based on search query - const filteredData = mockData.filter( + const filteredData = mockTransactions.filter( (item) => item.name.toLowerCase().includes(searchQuery.toLowerCase()) || - item.email.toLowerCase().includes(searchQuery.toLowerCase()) + item.transactionNumber.toLowerCase().includes(searchQuery.toLowerCase()) ); // Paginate data @@ -30,9 +48,9 @@ export const Components: FC = (): ReactElement => { const indexOfFirstItem = indexOfLastItem - itemsPerPage; const currentItems = filteredData.slice(indexOfFirstItem, indexOfLastItem); - const handleEdit = (id: number) => { - console.log(`Edit item with id: ${id}`); - // Implement edit functionality + const handleValidate = (id: number) => { + console.log(`Validate transaction with id: ${id}`); + // Implement validation functionality }; const handlePageChange = (pageNumber: number) => { @@ -78,7 +96,57 @@ export const Components: FC = (): ReactElement => { {/* Table */} - + index + 1 + indexOfFirstItem, + }, + { label: 'Nama Lengkap', key: 'name' }, + { label: 'Nomor Transaksi', key: 'transactionNumber' }, + { + label: 'Order Valid?', + render: (item: Transaction) => { + const statusColors: Record = { + valid: 'bg-success-500 text-white', + invalid: 'bg-danger-500 text-white', + unchecked: 'bg-yellow-400 text-black', + }; + const statusText: Record = { + valid: 'Valid', + invalid: 'Invalid', + unchecked: 'Unchecked', + }; + return ( +
+ {statusText[item.status]} +
+ ); + }, + }, + { + label: 'Action', + render: (item: Transaction) => ( + + ), + }, + ]} + /> {/* Pagination */} ; - onEdit: (id: number) => void; +interface DataTableProps { + data: T[]; + headers: { + label: string; + key?: keyof T; + render?: (item: T, index: number) => ReactNode; + className?: string; + }[]; + showCheckbox?: boolean; + onRowClick?: (item: T) => void; } -export const DataTable: FC = ({ +export const DataTable = >({ data, - onEdit, -}): ReactElement => { + headers, + showCheckbox = true, + onRowClick, +}: DataTableProps): ReactElement => { return (
- - - - - - - + {showCheckbox && ( + + )} + {headers.map((header, index) => { + const isFirst = index === 0 && !showCheckbox; + const isLast = index === headers.length - 1; + return ( + + ); + })} - {data.map((item, index) => ( + {data.map((item, rowIndex) => ( onRowClick && onRowClick(item)} > - - - - - - - + {showCheckbox && ( + + )} + {headers.map((header, colIndex) => { + const isFirst = colIndex === 0 && !showCheckbox; + const isLast = colIndex === headers.length - 1; + + return ( + + ); + })} ))}
- - No.Nama LengkapEmailNomor Telp - Alamat Pengiriman - - Action - + + + {header.label} +
- - {index + 1}{item.name}{item.email}{item.phone}{item.address} - - + + + {header.render + ? header.render(item, rowIndex) + : header.key + ? item[header.key] + : null} +