Skip to content

Commit 0de793a

Browse files
committed
(#606) Harmonize action button theme across tables in TTL's portal
1 parent 4321d94 commit 0de793a

File tree

2 files changed

+115
-110
lines changed

2 files changed

+115
-110
lines changed

src/components/InvitationTable.tsx

Lines changed: 108 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -1,133 +1,132 @@
1-
import React, { useMemo } from "react";
2-
import {
3-
createColumnHelper,
4-
flexRender,
5-
getCoreRowModel,
6-
useReactTable,
7-
} from "@tanstack/react-table";
8-
import Pagination from "../components/InvitationDataPagination";
9-
import SkeletonTable from '../Skeletons/SkeletonTable';
1+
// @ts-nocheck
2+
import React, { useState, useEffect, useMemo } from 'react';
3+
import { useTranslation } from 'react-i18next';
4+
import { useGlobalFilter, usePagination, useSortBy, useTable } from 'react-table';
5+
import { toast } from 'react-toastify';
6+
import DataPagination from './DataPagination';
7+
import SkeletonTable from '../Skeletons/SkeletonTable';
108

11-
interface Column {
12-
accessor?: string | ((row: any) => any);
13-
header: React.ReactNode;
14-
cell: (info: any) => React.ReactNode;
15-
}
16-
17-
interface TableProps {
18-
cols: Column[];
9+
interface TableData {
1910
data: any[];
20-
loading: boolean;
21-
rowCount: number;
22-
onPaginationChange: (pagination: { pageIndex: number; pageSize: number }) => void;
23-
pagination: { pageSize: number; pageIndex: number };
11+
columns: any;
12+
error: string | null;
13+
loading?: boolean;
14+
className?: string;
2415
}
2516

26-
const columnHelper = createColumnHelper();
27-
28-
function InvitationTable({
29-
cols,
30-
data,
31-
loading,
32-
rowCount,
33-
onPaginationChange,
34-
pagination,
35-
}: TableProps) {
36-
const { pageSize, pageIndex } = pagination;
17+
function DataTableStats({ data, columns, error, loading }: TableData) {
18+
const [filterInput, setFilterInput] = useState('');
19+
const { t } = useTranslation();
20+
const [pageIndex, setPageIndex] = useState(0);
3721

38-
const totalPages = Math.ceil(rowCount / pageSize);
22+
// Memoize columns and data to prevent unnecessary re-renders
23+
const memoizedColumns = useMemo(() => [...columns], [columns]);
24+
const memoizedData = useMemo(() => [...data], [data]);
3925

40-
const tableColumns = useMemo(
41-
() =>
42-
cols.map((column) => {
43-
if (typeof column.accessor === 'string') {
44-
return columnHelper.accessor(column.accessor, {
45-
header: typeof column.header === 'string' ? column.header : column.header(),
46-
cell: column.cell,
47-
});
48-
} else if (typeof column.accessor === 'function') {
49-
return columnHelper.accessor((row) => column.accessor(row), {
50-
header: typeof column.header === 'string' ? column.header : column.header(),
51-
cell: column.cell,
52-
});
53-
} else {
54-
return columnHelper.display({
55-
header: typeof column.header === 'string' ? column.header : column.header(),
56-
cell: column.cell,
57-
});
58-
}
59-
}),
60-
[cols]
26+
// Table instance
27+
const tableInstance = useTable(
28+
{
29+
data: memoizedData,
30+
columns: memoizedColumns,
31+
initialState: { pageIndex, pageSize: 3, globalFilter: filterInput },
32+
},
33+
useGlobalFilter,
34+
useSortBy,
35+
usePagination,
6136
);
6237

63-
const tableLib = useReactTable({
64-
data,
65-
columns: tableColumns,
66-
getCoreRowModel: getCoreRowModel(),
67-
manualPagination: true,
68-
state: {
69-
pagination,
70-
},
71-
onPaginationChange,
72-
});
38+
const {
39+
getTableProps,
40+
setGlobalFilter,
41+
getTableBodyProps,
42+
page,
43+
nextPage,
44+
previousPage,
45+
canPreviousPage,
46+
canNextPage,
47+
gotoPage,
48+
pageCount,
49+
setPageSize,
50+
pageOptions,
51+
headerGroups,
52+
prepareRow,
53+
state: { pageIndex: currentPageIndex, pageSize },
54+
} = tableInstance;
55+
56+
useEffect(() => {
57+
setPageIndex(currentPageIndex);
58+
}, [currentPageIndex]);
59+
60+
const handleFilterChange = (e) => {
61+
const value = e.target.value || '';
62+
setGlobalFilter(value);
63+
setFilterInput(value);
64+
};
7365

7466
return (
75-
<section className="relative">
67+
<div className="relative">
7668
<div className="flex items-center justify-between pb-6 " />
7769
<div style={{ overflowX: 'auto' }}>
7870
{loading ? (
79-
<SkeletonTable columns={tableColumns} />
71+
<SkeletonTable columns={columns} />
8072
) : (
81-
<table className="min-w-full leading-normal">
73+
<table className="min-w-full leading-normal" {...getTableProps()}>
8274
<thead>
83-
{tableLib.getHeaderGroups().map((headerGroup) => (
84-
<tr key={headerGroup.id}>
85-
{headerGroup.headers.map((header) => (
75+
{headerGroups.map((headerGroup) => (
76+
<tr key={headerGroup.id} {...headerGroup.getHeaderGroupProps()}>
77+
{headerGroup.headers.map((column) => (
8678
<th
87-
key={header.id}
88-
className="thead"
79+
key={column.id}
80+
className={column.isSorted ? 'sort-asc thead' : ' thead'}
81+
{...column.getHeaderProps(column.getSortByToggleProps())}
8982
>
90-
{flexRender(header.column.columnDef.header, header.getContext())}
83+
{column.render('Header')}
9184
</th>
9285
))}
9386
</tr>
9487
))}
9588
</thead>
96-
<tbody>
97-
{data.length === 0 && (
89+
<tbody {...getTableBodyProps()}>
90+
{memoizedData.length === 0 && (
9891
<tr>
9992
<td
100-
colSpan={tableColumns.length}
93+
colSpan={columns.length}
10194
className="px-6 py-4 text-sm text-center text-gray-500 dark:text-gray-300"
102-
aria-label="Empty cell"
95+
aria-label="Empty cell" // Added for accessibility
10396
>
10497
&nbsp;{' '}
10598
{/* Non-breaking space to ensure it's not an empty tag */}
10699
</td>
107100
</tr>
108101
)}
109-
{tableLib.getRowModel().rows.map((row) => (
110-
<tr
111-
key={row.id}
112-
className={`border-b dark:border-gray-700 ${
113-
row.index % 2 === 0
114-
? 'bg-light-bg dark:bg-neutral-600'
115-
: 'bg-white dark:bg-dark-bg'
116-
}`}
117-
>
118-
{row.getVisibleCells().map((cell) => (
119-
<td
120-
key={cell.id}
121-
className="data-cell "
102+
{memoizedData.length > 0 &&
103+
page.map((row) => {
104+
prepareRow(row);
105+
return (
106+
<tr
107+
key={row.id}
108+
className={`border-b dark:border-gray-700 ${
109+
row.index % 2 === 0
110+
? 'bg-light-bg dark:bg-neutral-600'
111+
: 'bg-white dark:bg-dark-bg'
112+
}`}
113+
{...row.getRowProps()}
122114
>
123-
{flexRender(cell.column.columnDef.cell, cell.getContext())}
124-
</td>
125-
))}
126-
</tr>
127-
))}
128-
{!loading && data.length === 0 && (
115+
{row.cells.map((cell) => (
116+
<td
117+
key={cell.id}
118+
className="data-cell "
119+
{...cell.getCellProps()}
120+
>
121+
{cell.render('Cell')}
122+
</td>
123+
))}
124+
</tr>
125+
);
126+
})}
127+
{!loading && !error && data.length === 0 && (
129128
<tr>
130-
<td colSpan={tableColumns.length || 100} className="text-center p-4">
129+
<td colSpan={columns.length || 100} className="text-center p-4">
131130
<div className="flex flex-col items-center justify-center space-y-4">
132131
<p className="text-gray-600 dark:text-gray-400 text-lg font-medium">
133132
No records available
@@ -141,17 +140,22 @@ function InvitationTable({
141140
)}
142141
</div>
143142
<div className="px-6 py-4">
144-
<Pagination
145-
tableLib={tableLib}
146-
totalPages={totalPages}
143+
<DataPagination
144+
pageOptions={pageOptions}
145+
canNextPage={canNextPage}
146+
gotoPage={gotoPage}
147+
columnLength={columns.length}
148+
canPreviousPage={canPreviousPage}
147149
pageSize={pageSize}
150+
setPageSize={setPageSize}
151+
previousPage={previousPage}
152+
nextPage={nextPage}
153+
pageCount={pageCount}
148154
pageIndex={pageIndex}
149-
sizes={[3, 5, 10, 25, 50, 100]}
150-
loading={loading}
151155
/>
152156
</div>
153-
</section>
157+
</div>
154158
);
155159
}
156160

157-
export default InvitationTable;
161+
export default DataTableStats;

src/pages/ttlTraineeDashboard.tsx

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ import { useTraineesContext } from '../hook/useTraineesData';
2626
import { XIcon } from '@heroicons/react/solid';
2727
import { FaTimes } from 'react-icons/fa';
2828
import { log } from 'console';
29+
import { FaEye } from 'react-icons/fa';
30+
2931
const organizationToken = localStorage.getItem('orgToken');
3032
``;
3133
/* istanbul ignore next */
@@ -144,16 +146,15 @@ const TtlTraineeDashboard = () => {
144146
accessor: '',
145147
Cell: ({ row }: any) =>
146148
hasData && ( // Only render the button if there is data
147-
<Button
148-
variant="primary"
149-
size="sm"
149+
<button
150150
onClick={() => {
151151
handleClickOpen(row.original?.email);
152152
}}
153-
style="px-4 py-0 text-sm"
153+
className="text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-600"
154+
aria-label="View Details"
154155
>
155-
{t('View more')}
156-
</Button>
156+
<FaEye className="text-2xl text-[#9C6ADE]" />
157+
</button>
157158
),
158159
},
159160
];

0 commit comments

Comments
 (0)