feat(FE-170,175): enhance RecordingTable with grading completion checks and approval logic

This commit is contained in:
rstubryan
2025-11-06 22:28:31 +07:00
parent c012668340
commit 62c16bb9d1
@@ -41,12 +41,14 @@ const RowOptionsMenu = ({
deleteClickHandler,
approveClickHandler,
rejectClickHandler,
isGradingCompleted,
}: {
type: 'dropdown' | 'collapse';
props: CellContext<Recording, unknown>;
deleteClickHandler: () => void;
approveClickHandler: () => void;
rejectClickHandler: () => void;
isGradingCompleted: (recording: Recording) => boolean;
}) => {
const isLayingCategory =
props.row.original.project_flock_category === 'LAYING';
@@ -60,6 +62,7 @@ const RowOptionsMenu = ({
};
const isApproved = isRecordingApproved(props.row.original);
const isGradingDone = isGradingCompleted(props.row.original);
return (
<RowOptionsMenuWrapper type={type}>
@@ -81,7 +84,7 @@ const RowOptionsMenu = ({
<Icon icon='mdi:pencil-outline' width={16} height={16} />
Edit
</Button>
{isLayingCategory && (
{isLayingCategory && !isGradingDone && (
<Button
href={`recording/grading/add?recording_id=${props.row.original.id}`}
variant='ghost'
@@ -98,6 +101,11 @@ const RowOptionsMenu = ({
variant='ghost'
color='success'
className='justify-start text-sm'
title={
isGradingDone
? 'Recording bisa disetujui karena sudah grading'
: 'Recording bisa disetujui'
}
>
<Icon icon='material-symbols:check' width={16} height={16} />
Approve
@@ -109,6 +117,11 @@ const RowOptionsMenu = ({
variant='ghost'
color='error'
className='justify-start text-sm'
title={
isGradingDone
? 'Recording bisa ditolak karena sudah grading'
: 'Recording bisa ditolak'
}
>
<Icon icon='material-symbols:close' width={16} height={16} />
Reject
@@ -431,11 +444,28 @@ const RecordingTable = () => {
isLoadingOptions: isLoadingKandang,
} = useSelect<Kandang>(KandangApi.basePath, 'id', 'name');
const isRecordingApproved = useCallback((recording: Recording) => {
return (
recording.approval?.action === 'APPROVED' &&
recording.approval?.step_name === 'Disetujui' &&
recording.approval?.step_number === 3
const isRecordingFullyApproved = useCallback(
(recording: Recording): boolean => {
return (
recording.approval?.action === 'APPROVED' &&
recording.approval?.step_name === 'Disetujui' &&
recording.approval?.step_number === 3
);
},
[]
);
const isRecordingApproved = useCallback(
(recording: Recording) => {
return isRecordingFullyApproved(recording);
},
[isRecordingFullyApproved]
);
const isGradingCompleted = useCallback((recording: Recording): boolean => {
return !!(
recording.egg_grading_status === 'COMPLETED' ||
(recording.approval?.step_number && recording.approval.step_number >= 1)
);
}, []);
@@ -472,7 +502,7 @@ const RecordingTable = () => {
if (eligibleRowIds.length === 0) {
toast.error(
'Tidak ada recording yang bisa disetujui (sudah disetujui sebelumnya)'
'Tidak ada recording yang bisa disetujui (sudah disetujui final)'
);
setIsApproveLoading(false);
return;
@@ -505,7 +535,7 @@ const RecordingTable = () => {
if (eligibleRowIds.length === 0) {
toast.error(
'Tidak ada recording yang bisa ditolak (sudah disetujui sebelumnya)'
'Tidak ada recording yang bisa ditolak (sudah disetujui final)'
);
setIsRejectLoading(false);
return;
@@ -531,7 +561,6 @@ const RecordingTable = () => {
setIsRejectLoading(false);
};
// Filter out already approved recordings for bulk actions
const eligibleRowIds = useMemo(() => {
if (!isResponseSuccess(recordings) || !recordings.data) return [];
return selectedRowIds.filter((id) => {
@@ -564,8 +593,15 @@ const RecordingTable = () => {
setApprovalNotes('');
approveModal.openModal();
}}
disabled={selectedRowIds.length === 0}
disabled={
selectedRowIds.length === 0 || eligibleRowIds.length === 0
}
className='w-full sm:w-fit'
title={
eligibleRowIds.length === 0
? 'Tidak ada Recording yang bisa disetujui (sudah disetujui final)'
: ''
}
>
<Icon icon='material-symbols:check' width={24} height={24} />
Approve
@@ -578,8 +614,15 @@ const RecordingTable = () => {
setApprovalNotes('');
rejectModal.openModal();
}}
disabled={selectedRowIds.length === 0}
disabled={
selectedRowIds.length === 0 || eligibleRowIds.length === 0
}
className='w-full sm:w-fit'
title={
eligibleRowIds.length === 0
? 'Tidak ada Recording yang bisa ditolak (sudah disetujui final)'
: ''
}
>
<Icon icon='material-symbols:close' width={24} height={24} />
Reject
@@ -692,27 +735,46 @@ const RecordingTable = () => {
columns={[
{
id: 'select',
header: ({ table }) => (
<div className='w-full flex flex-row justify-center'>
<CheckboxInput
name='allRow'
checked={table.getIsAllRowsSelected()}
indeterminate={table.getIsSomeRowsSelected()}
onChange={table.getToggleAllRowsSelectedHandler()}
/>
</div>
),
header: ({ table }) => {
const allRows = table.getRowModel().rows;
const selectableRows = allRows.filter((row) => {
const recording = row.original;
return !isRecordingApproved(recording);
});
const hasOnlyUnselectableRows = selectableRows.length === 0;
return (
<div className='w-full flex flex-row justify-center'>
<CheckboxInput
name='allRow'
checked={table.getIsAllRowsSelected()}
indeterminate={table.getIsSomeRowsSelected()}
onChange={table.getToggleAllRowsSelectedHandler()}
disabled={hasOnlyUnselectableRows}
title={
hasOnlyUnselectableRows
? 'Tidak ada Recording yang bisa dipilih (sudah disetujui final)'
: ''
}
/>
</div>
);
},
cell: ({ row }) => {
const isApproved = isRecordingApproved(row.original);
const isDisabled = !row.getCanSelect() || isApproved;
let tooltip = '';
if (isApproved) tooltip = 'Recording sudah disetujui final';
return (
<div>
<CheckboxInput
name='row'
checked={row.getIsSelected()}
disabled={!row.getCanSelect() || isApproved}
disabled={isDisabled}
indeterminate={row.getIsSomeSelected()}
onChange={row.getToggleSelectedHandler()}
title={isApproved ? 'Recording sudah disetujui' : ''}
title={tooltip}
/>
</div>
);
@@ -887,6 +949,7 @@ const RecordingTable = () => {
deleteClickHandler={deleteClickHandler}
approveClickHandler={approveClickHandler}
rejectClickHandler={rejectClickHandler}
isGradingCompleted={isGradingCompleted}
/>
</RowDropdownOptions>
)}
@@ -899,6 +962,7 @@ const RecordingTable = () => {
deleteClickHandler={deleteClickHandler}
approveClickHandler={approveClickHandler}
rejectClickHandler={rejectClickHandler}
isGradingCompleted={isGradingCompleted}
/>
</RowCollapseOptions>
)}