feat(FE-114): integrate row selection functionality in RecordingTable and Table components

This commit is contained in:
rstubryan
2025-10-24 10:18:56 +07:00
parent 41e6848d75
commit 9cbc703a63
2 changed files with 131 additions and 136 deletions
+13
View File
@@ -48,6 +48,8 @@ export interface TableProps<TData extends object> {
sorting?: SortingState; sorting?: SortingState;
setSorting?: OnChangeFn<SortingState>; setSorting?: OnChangeFn<SortingState>;
manualSorting?: boolean; manualSorting?: boolean;
rowSelection?: Record<string, boolean>;
setRowSelection?: OnChangeFn<Record<string, boolean>>;
} }
const DUMMY_SKELETON_DATA = [{}, {}, {}, {}, {}]; const DUMMY_SKELETON_DATA = [{}, {}, {}, {}, {}];
@@ -86,6 +88,8 @@ const Table = <TData extends object>({
sorting, sorting,
setSorting, setSorting,
manualSorting = false, manualSorting = false,
rowSelection,
setRowSelection,
}: TableProps<TData>) => { }: TableProps<TData>) => {
const isServerSideTable = const isServerSideTable =
totalItems !== undefined && totalItems !== undefined &&
@@ -137,6 +141,15 @@ const Table = <TData extends object>({
}; };
} }
if (rowSelection && setRowSelection) {
tableOptions.onRowSelectionChange = setRowSelection;
tableOptions.state = {
...tableOptions.state,
rowSelection,
};
tableOptions.getRowId = (row) => (row as { id: string }).id;
}
const table = useReactTable(tableOptions); const table = useReactTable(tableOptions);
const { setPageSize } = table; const { setPageSize } = table;
@@ -9,6 +9,7 @@ import Button from '@/components/Button';
import ConfirmationModal from '@/components/modal/ConfirmationModal'; import ConfirmationModal from '@/components/modal/ConfirmationModal';
import { OptionType } from '@/components/input/SelectInput'; import { OptionType } from '@/components/input/SelectInput';
import { ROWS_OPTIONS } from '@/config/constant'; import { ROWS_OPTIONS } from '@/config/constant';
import CheckboxInput from '@/components/input/CheckboxInput';
import { TableToolbar } from '@/components/table/TableToolbar'; import { TableToolbar } from '@/components/table/TableToolbar';
import { TableRowSizeSelector } from '@/components/table/TableRowSizeSelector'; import { TableRowSizeSelector } from '@/components/table/TableRowSizeSelector';
import Table from '@/components/Table'; import Table from '@/components/Table';
@@ -117,7 +118,7 @@ const RecordingTable = () => {
const [page, setPage] = useState(1); const [page, setPage] = useState(1);
const [pageSize, setPageSize] = useState(10); const [pageSize, setPageSize] = useState(10);
const [sorting, setSorting] = useState<SortingState>([]); const [sorting, setSorting] = useState<SortingState>([]);
const [selectedRecordings, setSelectedRecordings] = useState<number[]>([]); const [rowSelection, setRowSelection] = useState<Record<string, boolean>>({});
const [, setSelectedRecording] = useState<RecordingWithRelations | undefined>(undefined); const [, setSelectedRecording] = useState<RecordingWithRelations | undefined>(undefined);
const [isDeleteLoading, setIsDeleteLoading] = useState(false); const [isDeleteLoading, setIsDeleteLoading] = useState(false);
const [isBulkApproveLoading, setIsBulkApproveLoading] = useState(false); const [isBulkApproveLoading, setIsBulkApproveLoading] = useState(false);
@@ -160,28 +161,24 @@ const RecordingTable = () => {
return filteredData.slice(start, start + pageSize); return filteredData.slice(start, start + pageSize);
}, [page, pageSize, search]); }, [page, pageSize, search]);
const selectedRowIds = Object.keys(rowSelection).map((item) => parseInt(item));
const bulkApproveHandler = async () => { const bulkApproveHandler = async () => {
setIsBulkApproveLoading(true); setIsBulkApproveLoading(true);
console.log( console.log('Approved recordings:', selectedRowIds);
'Approved recordings:',
paginatedData.filter((_, idx) => selectedRecordings.includes(idx))
);
setTimeout(() => { setTimeout(() => {
setIsBulkApproveLoading(false); setIsBulkApproveLoading(false);
setSelectedRecordings([]); setRowSelection({});
bulkApproveModal.closeModal(); bulkApproveModal.closeModal();
}, 1000); }, 1000);
}; };
const bulkRejectHandler = async () => { const bulkRejectHandler = async () => {
setIsBulkRejectLoading(true); setIsBulkRejectLoading(true);
console.log( console.log('Rejected recordings:', selectedRowIds);
'Rejected recordings:',
paginatedData.filter((_, idx) => selectedRecordings.includes(idx))
);
setTimeout(() => { setTimeout(() => {
setIsBulkRejectLoading(false); setIsBulkRejectLoading(false);
setSelectedRecordings([]); setRowSelection({});
bulkRejectModal.closeModal(); bulkRejectModal.closeModal();
}, 1000); }, 1000);
}; };
@@ -217,7 +214,7 @@ const RecordingTable = () => {
{/* Bulk action buttons */} {/* Bulk action buttons */}
<div className={'flex justify-end items-center'}> <div className={'flex justify-end items-center'}>
{selectedRecordings.length > 0 && ( {selectedRowIds.length > 0 && (
<div className='flex gap-2 mb-4'> <div className='flex gap-2 mb-4'>
<Button <Button
type='button' type='button'
@@ -230,7 +227,7 @@ const RecordingTable = () => {
width={20} width={20}
height={20} height={20}
/> />
Approve ({selectedRecordings.length}) Approve ({selectedRowIds.length})
</Button> </Button>
<Button <Button
type='button' type='button'
@@ -243,7 +240,7 @@ const RecordingTable = () => {
width={20} width={20}
height={20} height={20}
/> />
Reject ({selectedRecordings.length}) Reject ({selectedRowIds.length})
</Button> </Button>
</div> </div>
)} )}
@@ -251,7 +248,7 @@ const RecordingTable = () => {
<ConfirmationModal <ConfirmationModal
ref={bulkApproveModal.ref} ref={bulkApproveModal.ref}
type='success' type='success'
text={`Apakah anda yakin ingin menyetujui ${selectedRecordings.length} data Recording yang dipilih?`} text={`Apakah anda yakin ingin menyetujui ${selectedRowIds.length} data Recording yang dipilih?`}
secondaryButton={{ secondaryButton={{
text: 'Tidak', text: 'Tidak',
}} }}
@@ -266,7 +263,7 @@ const RecordingTable = () => {
<ConfirmationModal <ConfirmationModal
ref={bulkRejectModal.ref} ref={bulkRejectModal.ref}
type='error' type='error'
text={`Apakah anda yakin ingin menolak ${selectedRecordings.length} data Recording yang dipilih?`} text={`Apakah anda yakin ingin menolak ${selectedRowIds.length} data Recording yang dipilih?`}
secondaryButton={{ secondaryButton={{
text: 'Tidak', text: 'Tidak',
}} }}
@@ -284,43 +281,26 @@ const RecordingTable = () => {
columns={[ columns={[
{ {
id: 'select', id: 'select',
accessorKey: 'id',
header: ({ table }) => ( header: ({ table }) => (
<input <div className='w-full flex flex-row justify-center'>
type='checkbox' <CheckboxInput
className='checkbox' name='allRow'
checked={ checked={table.getIsAllRowsSelected()}
table.getRowModel().rows.length > 0 && indeterminate={table.getIsSomeRowsSelected()}
table onChange={table.getToggleAllRowsSelectedHandler()}
.getRowModel()
.rows.every((row) => selectedRecordings.includes(row.index))
}
onChange={(e) => {
if (e.target.checked) {
setSelectedRecordings(
table.getRowModel().rows.map((row) => row.index)
);
} else {
setSelectedRecordings([]);
}
}}
/> />
</div>
), ),
cell: ({ row }) => ( cell: ({ row }) => (
<input <div>
type='checkbox' <CheckboxInput
className='checkbox' name='row'
checked={selectedRecordings.includes(row.index)} checked={row.getIsSelected()}
onChange={(e) => { disabled={!row.getCanSelect()}
if (e.target.checked) { indeterminate={row.getIsSomeSelected()}
setSelectedRecordings([...selectedRecordings, row.index]); onChange={row.getToggleSelectedHandler()}
} else {
setSelectedRecordings(
selectedRecordings.filter((i) => i !== row.index)
);
}
}}
/> />
</div>
), ),
}, },
{ {
@@ -403,6 +383,8 @@ const RecordingTable = () => {
isLoading={false} isLoading={false}
sorting={sorting} sorting={sorting}
setSorting={setSorting} setSorting={setSorting}
rowSelection={rowSelection}
setRowSelection={setRowSelection}
className={{ className={{
containerClassName: cn({ containerClassName: cn({
'mb-20': paginatedData.length === 0, 'mb-20': paginatedData.length === 0,