refactor: remove unused DataTable component and clean up filter logic in FullPagePageIndex

This commit is contained in:
Firman Ramdhani
2026-07-23 16:50:09 +07:00
parent 8f2eecd8ae
commit 94e7b99712
7 changed files with 20 additions and 308 deletions
@@ -1,261 +0,0 @@
import { useState, useCallback } from 'react';
import {
Table,
Box,
Paper,
Badge,
Text,
Group,
Button,
TextInput,
Pagination,
Select,
ScrollArea,
} from '@repo/ui/components';
import { PageActions } from '@repo/ui/components';
import { useEnterpriseModuleTranslationContext, useEnterpriseModuleNavigationContext } from '@repo/ui/foundations';
import { FullPageEntity } from '../../domain/entities';
import { Edit2, Eye, Copy, Trash2, Search, Filter, CheckCircle2, Ban } from 'lucide-react';
// TODO: Replace this mock data with real API data loaded from DataService via useEnterpriseModuleDataServiceContext
const MOCK_DATA: FullPageEntity[] = Array.from({ length: 50 }).map((_, i) => ({
id: String(i + 1),
name: `Database Cluster ${i + 1}`,
code: `DB-PROD-${String(i + 1).padStart(3, '0')}`,
status: i % 7 === 0 ? 'MAINTENANCE' : i % 4 === 0 ? 'INACTIVE' : 'ACTIVE',
description: `Managed PostgreSQL cluster instance in region us-east-${(i % 3) + 1}`,
}));
export function DataTable() {
const { t } = useEnterpriseModuleTranslationContext();
const { navigateToDetail, navigateToEdit, navigateToDuplicate } = useEnterpriseModuleNavigationContext();
const [page, setPage] = useState(1);
const [pageSize, setPageSize] = useState(10);
const totalRecords = MOCK_DATA.length;
const totalPages = Math.ceil(totalRecords / pageSize);
const paginatedData = MOCK_DATA.slice((page - 1) * pageSize, page * pageSize);
const getRowActions = useCallback(
(row: FullPageEntity) => [
{
key: 'view',
label: t('common:view'),
icon: <Eye size={14} />,
onClick: () => navigateToDetail(row.id as string),
},
{
key: 'edit',
label: t('common:edit'),
icon: <Edit2 size={14} />,
onClick: () => navigateToEdit(row.id as string),
},
{
key: 'duplicate',
label: t('common:duplicate'),
icon: <Copy size={14} />,
onClick: () => navigateToDuplicate(row.id as string),
},
{
type: 'divider' as const,
key: 'div-1',
},
{
key: 'delete',
label: t('common:delete'),
icon: <Trash2 size={14} />,
intent: 'destructive' as const,
onClick: () => {
// Mock delete action
alert(`Delete ${row.name}`);
},
},
],
[t, navigateToDetail, navigateToEdit, navigateToDuplicate],
);
const rows = paginatedData.map((item) => (
<Table.Tr key={item.id}>
<Table.Td>
<Text
size="sm"
fw={600}
style={{ color: 'light-dark(var(--mantine-color-gray-8), var(--mantine-color-dark-0))' }}
>
{item.code}
</Text>
</Table.Td>
<Table.Td>
<Text size="sm" fw={500}>
{item.name}
</Text>
</Table.Td>
<Table.Td>
<Badge
variant={item.status === 'ACTIVE' ? 'light' : item.status === 'MAINTENANCE' ? 'outline' : 'dot'}
color={item.status === 'ACTIVE' ? 'teal' : item.status === 'MAINTENANCE' ? 'orange' : 'gray'}
size="sm"
radius="sm"
fw={600}
>
{item.status}
</Badge>
</Table.Td>
<Table.Td>
<Text size="sm" c="dimmed">
{item.description}
</Text>
</Table.Td>
<Table.Td ta="right">
<PageActions actions={getRowActions(item)} />
</Table.Td>
</Table.Tr>
));
return (
<Paper withBorder shadow="sm" radius="md" style={{ overflow: 'hidden' }}>
{/* --- TABLE TOOLBAR --- */}
<Box
p="md"
style={{ borderBottom: '1px solid light-dark(var(--mantine-color-gray-2), var(--mantine-color-dark-7))' }}
>
<Group justify="space-between" wrap="nowrap">
<Group gap="sm" wrap="nowrap">
<TextInput
placeholder="Search items..."
leftSection={<Search size={16} strokeWidth={2} style={{ color: 'var(--mantine-color-dimmed)' }} />}
size="sm"
radius="md"
w={280}
/>
<Button
variant="default"
size="sm"
radius="md"
leftSection={<Filter size={16} strokeWidth={2} style={{ color: 'var(--mantine-color-dimmed)' }} />}
>
Filters
</Button>
</Group>
<Group gap="sm" wrap="nowrap">
<Group gap="xs">
<Button
variant="light"
color="teal"
size="sm"
radius="md"
leftSection={<CheckCircle2 size={14} strokeWidth={2.5} />}
>
Activate
</Button>
<Button
variant="light"
color="gray"
size="sm"
radius="md"
leftSection={<Ban size={14} strokeWidth={2.5} />}
>
Deactivate
</Button>
<Button
variant="light"
color="red"
size="sm"
radius="md"
leftSection={<Trash2 size={14} strokeWidth={2.5} />}
>
Delete
</Button>
</Group>
</Group>
</Group>
</Box>
{/* --- END TABLE TOOLBAR --- */}
<ScrollArea.Autosize mah="calc(100vh - 350px)" offsetScrollbars>
<Table
stickyHeader
stickyHeaderOffset={-1}
striped
highlightOnHover
verticalSpacing="sm"
horizontalSpacing="md"
>
<Table.Thead bg="light-dark(var(--mantine-color-gray-0), var(--mantine-color-dark-8))">
<Table.Tr>
<Table.Th fw={700} style={{ letterSpacing: '0.5px', textTransform: 'uppercase' }} fz="xs" c="dimmed">
{t('fields.code')}
</Table.Th>
<Table.Th fw={700} style={{ letterSpacing: '0.5px', textTransform: 'uppercase' }} fz="xs" c="dimmed">
{t('fields.name')}
</Table.Th>
<Table.Th fw={700} style={{ letterSpacing: '0.5px', textTransform: 'uppercase' }} fz="xs" c="dimmed">
{t('fields.status')}
</Table.Th>
<Table.Th fw={700} style={{ letterSpacing: '0.5px', textTransform: 'uppercase' }} fz="xs" c="dimmed">
{t('fields.description')}
</Table.Th>
<Table.Th
fw={700}
style={{ letterSpacing: '0.5px', textTransform: 'uppercase' }}
fz="xs"
c="dimmed"
w={80}
ta="right"
>
Actions
</Table.Th>
</Table.Tr>
</Table.Thead>
<Table.Tbody>{rows}</Table.Tbody>
</Table>
</ScrollArea.Autosize>
{/* --- PAGINATION FOOTER --- */}
<Box
p="md"
style={{ borderTop: '1px solid light-dark(var(--mantine-color-gray-2), var(--mantine-color-dark-7))' }}
>
<Group justify="space-between" align="center">
<Text size="sm" c="dimmed" fw={500}>
Showing{' '}
<Text span fw={600} c="var(--mantine-color-text)">
{(page - 1) * pageSize + 1}
</Text>{' '}
to{' '}
<Text span fw={600} c="var(--mantine-color-text)">
{Math.min(page * pageSize, totalRecords)}
</Text>{' '}
of{' '}
<Text span fw={600} c="var(--mantine-color-text)">
{totalRecords}
</Text>{' '}
entries
</Text>
<Group gap="md">
<Group gap="xs">
<Text size="sm" c="dimmed" fw={500}>
Rows per page:
</Text>
<Select
size="sm"
radius="md"
data={['10', '20', '50']}
value={String(pageSize)}
onChange={(val) => {
setPageSize(Number(val));
setPage(1);
}}
w={75}
/>
</Group>
<Pagination total={totalPages} value={page} onChange={setPage} size="sm" radius="md" color="indigo" />
</Group>
</Group>
</Box>
{/* --- END PAGINATION FOOTER --- */}
</Paper>
);
}
@@ -1,21 +1,8 @@
import { useEffect } from 'react';
import { SimpleGrid } from '@repo/ui/components';
import { FieldTextInput } from '@repo/ui/form';
import { UseFormReturn, useWatch } from 'react-hook-form';
import { UseFormReturn } from 'react-hook-form';
export const FilterFormContent = ({ form, t }: { form: UseFormReturn<any>; t: any }) => {
const codeValue = useWatch({
control: form.control,
name: 'code',
});
useEffect(() => {
if (!codeValue) {
form.setValue('name', '');
form.clearErrors('name');
}
}, [codeValue, form]);
return (
<SimpleGrid cols={{ base: 1, sm: 2 }} spacing="md">
<FieldTextInput
@@ -30,7 +17,6 @@ export const FilterFormContent = ({ form, t }: { form: UseFormReturn<any>; t: an
name="name"
label={t('fields.name')}
placeholder={`Enter ${t('fields.name')}`}
disabled={!codeValue}
/>
</SimpleGrid>
);
@@ -4,28 +4,12 @@ import {
EnterpriseDataTable,
} from '@repo/ui/foundations';
import { ColDef } from '@repo/ui/components';
import { z } from 'zod';
import { Trans } from '@repo/core-i18n';
import { Text } from '@repo/ui/components';
import { LayoutDashboard } from 'lucide-react';
import { useMemo } from 'react';
import { FilterFormContent } from '../components/filter-content';
const filterSchema = z
.object({
code: z.string().optional(),
name: z.string().optional(),
})
.superRefine((data, ctx) => {
if (data.code && !data.name) {
ctx.addIssue({
path: ['name'],
code: z.ZodIssueCode.custom,
message: 'Name is required when code is provided',
});
}
});
export default function FullPagePageIndex() {
const { t } = useEnterpriseModuleTranslationContext();
@@ -38,7 +22,6 @@ export default function FullPagePageIndex() {
const filterConfig = useMemo(() => {
return {
schema: filterSchema,
renderBody: (form: any) => {
if (!form) return null;
return <FilterFormContent form={form} t={t} />;
@@ -40,7 +40,7 @@
"collapseAll": "Collapse all menu",
"searchMenu": "Search menu",
"searchData": "Search data",
"searchPlaceholder": "Type to search & press Enter...",
"searchPlaceholder": "Type to search & press enter...",
"collapse": "Collapse",
"expandSidebar": "Expand Sidebar",
"filterTitle": "Filter {{module}}",
@@ -40,7 +40,7 @@
"collapseAll": "Tutup semua menu",
"searchMenu": "Cari menu",
"searchData": "Cari data",
"searchPlaceholder": "Ketik pencarian & tekan Enter...",
"searchPlaceholder": "Ketik pencarian & tekan enter...",
"collapse": "Tutup",
"expandSidebar": "Perluas Bilah Sisi",
"filterTitle": "Filter {{module}}",
@@ -13,7 +13,11 @@ import {
} from 'ag-grid-community';
import { Box, Group, TextInput, Indicator, CloseButton } from '@mantine/core';
import { useDisclosure } from '@mantine/hooks';
import { Search, Filter, Settings } from 'lucide-react';
import {
Search,
Filter,
// Settings
} from 'lucide-react';
import { DataGrid, StatusBadge, PageActions } from '../../../../components';
import type { PageActionProps } from '../../../../components';
@@ -205,7 +209,7 @@ export function EnterpriseDataTable<E extends BaseEntity>(props: EnterpriseDataT
// Local UI State
// ---------------------------------------------------------------------------
const [openedFilter, { open: openFilter, close: closeFilter }] = useDisclosure(false);
const [openedSetting, { open: openSetting, close: closeSetting }] = useDisclosure(false);
// const [openedSetting, { open: openSetting, close: closeSetting }] = useDisclosure(false);
const moduleTitle = config.tabTitle || t(`${config.translationNamespace}:title`);
// Reference to the AG Grid API for programmatic interaction
@@ -829,14 +833,14 @@ export function EnterpriseDataTable<E extends BaseEntity>(props: EnterpriseDataT
tooltipLabel: t('common:actions.filter'),
onClick: openFilter,
},
{
key: 'setting',
icon: <Settings size={16} />,
variant: 'default',
showLabel: false,
tooltipLabel: t('common:actions.setting'),
onClick: openSetting,
},
// {
// key: 'setting',
// icon: <Settings size={16} />,
// variant: 'default',
// showLabel: false,
// tooltipLabel: t('common:actions.setting'),
// onClick: openSetting,
// },
]}
/>
</Group>
@@ -907,11 +911,11 @@ export function EnterpriseDataTable<E extends BaseEntity>(props: EnterpriseDataT
onFilter={handleFilterApply}
/>
<TableSettingDrawer
{/* <TableSettingDrawer
opened={openedSetting}
onClose={closeSetting}
title={t('common:tableSettingTitle', { module: moduleTitle })}
/>
/> */}
</Box>
);
}
@@ -631,7 +631,7 @@ export function EnterpriseDetailPageProvider<E extends BaseEntity = BaseEntity>(
style: { fontSize: 12 },
};
}}
actions={pageActions}
actions={detailData ? pageActions : []}
{...pageHeaderPropsValue}
moduleKey={moduleKey}
titleProps={{