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