mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-23 14:55:44 +00:00
refactor(FE): Add transition restrictions for recording operations
This commit is contained in:
@@ -21,6 +21,7 @@ import SelectInput, { useSelect } from '@/components/input/SelectInput';
|
|||||||
import DebouncedTextInput from '@/components/input/DebouncedTextInput';
|
import DebouncedTextInput from '@/components/input/DebouncedTextInput';
|
||||||
import PopoverButton from '@/components/popover/PopoverButton';
|
import PopoverButton from '@/components/popover/PopoverButton';
|
||||||
import PopoverContent from '@/components/popover/PopoverContent';
|
import PopoverContent from '@/components/popover/PopoverContent';
|
||||||
|
import Tooltip from '@/components/Tooltip';
|
||||||
import { useFormik } from 'formik';
|
import { useFormik } from 'formik';
|
||||||
import { AreaApi } from '@/services/api/master-data';
|
import { AreaApi } from '@/services/api/master-data';
|
||||||
import { LocationApi } from '@/services/api/master-data';
|
import { LocationApi } from '@/services/api/master-data';
|
||||||
@@ -36,6 +37,7 @@ import {
|
|||||||
import RecordingTableSkeleton from '@/components/pages/production/recording/skeleton/RecordingTableSkeleton';
|
import RecordingTableSkeleton from '@/components/pages/production/recording/skeleton/RecordingTableSkeleton';
|
||||||
import Table from '@/components/Table';
|
import Table from '@/components/Table';
|
||||||
import { type Recording } from '@/types/api/production/recording';
|
import { type Recording } from '@/types/api/production/recording';
|
||||||
|
import { getRecordingRestriction } from './recording-utils';
|
||||||
import { RecordingApi } from '@/services/api/production';
|
import { RecordingApi } from '@/services/api/production';
|
||||||
import { isResponseSuccess } from '@/lib/api-helper';
|
import { isResponseSuccess } from '@/lib/api-helper';
|
||||||
import { useTableFilter } from '@/services/hooks/useTableFilter';
|
import { useTableFilter } from '@/services/hooks/useTableFilter';
|
||||||
@@ -105,30 +107,57 @@ const RowOptionsMenu = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const isRecordingEditable = (recording: Recording) => {
|
const isRecordingEditable = (recording: Recording) => {
|
||||||
if (
|
const category = recording.project_flock?.project_flock_category;
|
||||||
recording.executed_at &&
|
const isTransition = recording.is_transition;
|
||||||
recording.project_flock?.project_flock_category === 'GROWING'
|
|
||||||
) {
|
const restriction = getRecordingRestriction(
|
||||||
|
category || 'GROWING',
|
||||||
|
isTransition
|
||||||
|
);
|
||||||
|
|
||||||
|
if (restriction.isLocked) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getRecordingRestrictionInfo = (recording: Recording) => {
|
||||||
|
const category = recording.project_flock?.project_flock_category;
|
||||||
|
const isTransition = recording.is_transition;
|
||||||
|
|
||||||
|
return getRecordingRestriction(category || 'GROWING', isTransition);
|
||||||
|
};
|
||||||
|
|
||||||
const isApproved = isRecordingApproved(props.row.original);
|
const isApproved = isRecordingApproved(props.row.original);
|
||||||
const isRejected = isRecordingRejected(props.row.original);
|
const isRejected = isRecordingRejected(props.row.original);
|
||||||
const isEditable = isRecordingEditable(props.row.original);
|
const isEditable = isRecordingEditable(props.row.original);
|
||||||
|
const restrictionInfo = getRecordingRestrictionInfo(props.row.original);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='relative'>
|
<div className='relative'>
|
||||||
<PopoverButton
|
<Tooltip
|
||||||
tabIndex={0}
|
content={restrictionInfo.isLocked ? restrictionInfo.lockReason : ''}
|
||||||
variant='ghost'
|
position='top'
|
||||||
color='none'
|
|
||||||
popoverTarget={popoverId}
|
|
||||||
anchorName={popoverAnchorName}
|
|
||||||
>
|
>
|
||||||
<Icon icon='material-symbols:more-vert' width={16} height={16} />
|
<PopoverButton
|
||||||
</PopoverButton>
|
tabIndex={0}
|
||||||
|
variant='ghost'
|
||||||
|
color='none'
|
||||||
|
popoverTarget={popoverId}
|
||||||
|
anchorName={popoverAnchorName}
|
||||||
|
className={restrictionInfo.isLocked ? 'text-error' : ''}
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
icon={
|
||||||
|
restrictionInfo.isLocked
|
||||||
|
? 'material-symbols:lock-outline'
|
||||||
|
: 'material-symbols:more-vert'
|
||||||
|
}
|
||||||
|
width={16}
|
||||||
|
height={16}
|
||||||
|
/>
|
||||||
|
</PopoverButton>
|
||||||
|
</Tooltip>
|
||||||
|
|
||||||
<PopoverContent
|
<PopoverContent
|
||||||
id={popoverId}
|
id={popoverId}
|
||||||
@@ -763,9 +792,19 @@ const RecordingTable = () => {
|
|||||||
cell: (props) => {
|
cell: (props) => {
|
||||||
const category =
|
const category =
|
||||||
props.row.original.project_flock?.project_flock_category;
|
props.row.original.project_flock?.project_flock_category;
|
||||||
|
const isTransition = props.row.original.is_transition;
|
||||||
if (!category) return '-';
|
if (!category) return '-';
|
||||||
const color = category === 'LAYING' ? 'info' : 'warning';
|
const color = category === 'LAYING' ? 'info' : 'warning';
|
||||||
return <StatusBadge color={color} text={formatTitleCase(category)} />;
|
return (
|
||||||
|
<div className='flex flex-col gap-1'>
|
||||||
|
<StatusBadge color={color} text={formatTitleCase(category)} />
|
||||||
|
{isTransition && (
|
||||||
|
<span className='text-xs text-warning font-medium'>
|
||||||
|
(Transisi)
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ import {
|
|||||||
} from '@/components/pages/production/recording/form/RecordingForm.schema';
|
} from '@/components/pages/production/recording/form/RecordingForm.schema';
|
||||||
|
|
||||||
import { isResponseSuccess, isResponseError } from '@/lib/api-helper';
|
import { isResponseSuccess, isResponseError } from '@/lib/api-helper';
|
||||||
import { formatDate, formatNumber } from '@/lib/helper';
|
import { formatDate, formatNumber, cn } from '@/lib/helper';
|
||||||
import toast from 'react-hot-toast';
|
import toast from 'react-hot-toast';
|
||||||
import ApprovalSteps, {
|
import ApprovalSteps, {
|
||||||
useApprovalSteps,
|
useApprovalSteps,
|
||||||
@@ -80,6 +80,7 @@ import {
|
|||||||
LAYING_RECORDING_APPROVAL_LINE,
|
LAYING_RECORDING_APPROVAL_LINE,
|
||||||
} from '@/config/approval-line';
|
} from '@/config/approval-line';
|
||||||
import { useFormikErrorList } from '@/services/hooks/useFormikErrorList';
|
import { useFormikErrorList } from '@/services/hooks/useFormikErrorList';
|
||||||
|
import { getRecordingRestriction } from '../recording-utils';
|
||||||
|
|
||||||
interface RecordingFormProps {
|
interface RecordingFormProps {
|
||||||
type?: 'add' | 'edit' | 'detail';
|
type?: 'add' | 'edit' | 'detail';
|
||||||
@@ -272,16 +273,6 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
|||||||
return recording?.approval?.action === 'REJECTED';
|
return recording?.approval?.action === 'REJECTED';
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const isRecordingEditable = useCallback((recording?: Recording) => {
|
|
||||||
if (
|
|
||||||
recording?.executed_at &&
|
|
||||||
recording?.project_flock?.project_flock_category === 'GROWING'
|
|
||||||
) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// ===== PAYLOAD CREATION HELPERS =====
|
// ===== PAYLOAD CREATION HELPERS =====
|
||||||
const createGrowingPayload = useCallback(
|
const createGrowingPayload = useCallback(
|
||||||
(values: RecordingGrowingFormValues) => {
|
(values: RecordingGrowingFormValues) => {
|
||||||
@@ -476,6 +467,60 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
|||||||
? projectFlockKandangDetailData.data
|
? projectFlockKandangDetailData.data
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
|
// ===== TRANSITION RESTRICTION LOGIC =====
|
||||||
|
const isTransitionPeriod = useMemo(() => {
|
||||||
|
return initialValues?.is_transition ?? false;
|
||||||
|
}, [initialValues]);
|
||||||
|
|
||||||
|
const recordingRestriction = useMemo(() => {
|
||||||
|
const category =
|
||||||
|
initialValues?.project_flock?.project_flock_category ||
|
||||||
|
projectFlockKandangLookup?.project_flock?.category ||
|
||||||
|
projectFlockKandangDetail?.project_flock?.category ||
|
||||||
|
'GROWING';
|
||||||
|
|
||||||
|
const isTransition = initialValues?.is_transition ?? false;
|
||||||
|
|
||||||
|
const currentFlockCategory = projectFlockKandangDetail?.project_flock
|
||||||
|
?.category as 'GROWING' | 'LAYING' | undefined;
|
||||||
|
|
||||||
|
return getRecordingRestriction(
|
||||||
|
category as 'GROWING' | 'LAYING',
|
||||||
|
isTransition,
|
||||||
|
type === 'edit' ? currentFlockCategory : undefined
|
||||||
|
);
|
||||||
|
}, [
|
||||||
|
initialValues,
|
||||||
|
projectFlockKandangLookup,
|
||||||
|
projectFlockKandangDetail,
|
||||||
|
type,
|
||||||
|
]);
|
||||||
|
|
||||||
|
const isRecordingEditable = useCallback(
|
||||||
|
(recording?: Recording) => {
|
||||||
|
if (!recording) return true;
|
||||||
|
|
||||||
|
const category = recording.project_flock?.project_flock_category;
|
||||||
|
const isTransition = recording.is_transition;
|
||||||
|
|
||||||
|
const currentFlockCategory = projectFlockKandangDetail?.project_flock
|
||||||
|
?.category as 'GROWING' | 'LAYING' | undefined;
|
||||||
|
|
||||||
|
const restriction = getRecordingRestriction(
|
||||||
|
category || 'GROWING',
|
||||||
|
isTransition,
|
||||||
|
currentFlockCategory
|
||||||
|
);
|
||||||
|
|
||||||
|
if (restriction.isLocked) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
[projectFlockKandangDetail]
|
||||||
|
);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
options: stockProductOptions,
|
options: stockProductOptions,
|
||||||
rawData: stockProducts,
|
rawData: stockProducts,
|
||||||
@@ -2324,6 +2369,7 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
|||||||
setSelectedStocks([]);
|
setSelectedStocks([]);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
disabled={!recordingRestriction.canEditStock}
|
||||||
classNames={{
|
classNames={{
|
||||||
wrapper: 'flex justify-center',
|
wrapper: 'flex justify-center',
|
||||||
checkbox: 'checkbox checkbox-sm',
|
checkbox: 'checkbox checkbox-sm',
|
||||||
@@ -2373,6 +2419,7 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
disabled={!recordingRestriction.canEditStock}
|
||||||
classNames={{
|
classNames={{
|
||||||
wrapper: 'flex justify-center',
|
wrapper: 'flex justify-center',
|
||||||
checkbox: 'checkbox checkbox-sm',
|
checkbox: 'checkbox checkbox-sm',
|
||||||
@@ -2425,7 +2472,8 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
|||||||
isSearchable
|
isSearchable
|
||||||
isDisabled={
|
isDisabled={
|
||||||
type === 'detail' ||
|
type === 'detail' ||
|
||||||
!formik.values.project_flock_kandang_id
|
!formik.values.project_flock_kandang_id ||
|
||||||
|
!recordingRestriction.canEditStock
|
||||||
}
|
}
|
||||||
isClearable={type !== 'detail'}
|
isClearable={type !== 'detail'}
|
||||||
inputPrefix={
|
inputPrefix={
|
||||||
@@ -2472,7 +2520,10 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
|||||||
)
|
)
|
||||||
: null
|
: null
|
||||||
}
|
}
|
||||||
disabled={type === 'detail'}
|
disabled={
|
||||||
|
type === 'detail' ||
|
||||||
|
!recordingRestriction.canEditStock
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
{getStockUsageAdornment(idx)}
|
{getStockUsageAdornment(idx)}
|
||||||
</div>
|
</div>
|
||||||
@@ -2484,6 +2535,7 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
|||||||
type='button'
|
type='button'
|
||||||
color='error'
|
color='error'
|
||||||
onClick={() => removeStock(idx)}
|
onClick={() => removeStock(idx)}
|
||||||
|
disabled={!recordingRestriction.canEditStock}
|
||||||
>
|
>
|
||||||
<Icon
|
<Icon
|
||||||
icon='mdi:trash-can'
|
icon='mdi:trash-can'
|
||||||
@@ -2501,38 +2553,81 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
|||||||
</div>
|
</div>
|
||||||
{(type as 'add' | 'edit' | 'detail') !== 'detail' && (
|
{(type as 'add' | 'edit' | 'detail') !== 'detail' && (
|
||||||
<div className='flex justify-center items-center mt-4 gap-4'>
|
<div className='flex justify-center items-center mt-4 gap-4'>
|
||||||
{selectedStocks.length > 0 && (
|
{selectedStocks.length > 0 &&
|
||||||
|
recordingRestriction.canEditStock && (
|
||||||
|
<Button
|
||||||
|
type='button'
|
||||||
|
color='error'
|
||||||
|
onClick={removeSelectedStocks}
|
||||||
|
disabled={selectedStocks.length === 0}
|
||||||
|
className='w-fit'
|
||||||
|
>
|
||||||
|
<Icon icon='mdi:trash-can' width={24} height={24} />
|
||||||
|
Hapus Terpilih ({selectedStocks.length})
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
<Tooltip
|
||||||
|
content={
|
||||||
|
!recordingRestriction.canEditStock
|
||||||
|
? 'Stock tidak dapat ditambahkan pada masa transisi Laying'
|
||||||
|
: ''
|
||||||
|
}
|
||||||
|
position='top'
|
||||||
|
>
|
||||||
<Button
|
<Button
|
||||||
type='button'
|
type='button'
|
||||||
color='error'
|
color='success'
|
||||||
onClick={removeSelectedStocks}
|
onClick={addStock}
|
||||||
disabled={selectedStocks.length === 0}
|
|
||||||
className='w-fit'
|
className='w-fit'
|
||||||
|
disabled={!recordingRestriction.canEditStock}
|
||||||
>
|
>
|
||||||
<Icon icon='mdi:trash-can' width={24} height={24} />
|
<Icon icon='ic:round-plus' width={24} height={24} />
|
||||||
Hapus Terpilih ({selectedStocks.length})
|
Tambah Stok
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
</Tooltip>
|
||||||
<Button
|
|
||||||
type='button'
|
|
||||||
color='success'
|
|
||||||
onClick={addStock}
|
|
||||||
className='w-fit'
|
|
||||||
>
|
|
||||||
<Icon icon='ic:round-plus' width={24} height={24} />
|
|
||||||
Tambah Stok
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
|
{/* Transition Warning Banner -- MOVED UP -- */}
|
||||||
|
{isTransitionPeriod && (
|
||||||
|
<div className='alert alert-warning mb-4'>
|
||||||
|
<Icon
|
||||||
|
icon='material-symbols:warning-outline'
|
||||||
|
width={24}
|
||||||
|
height={24}
|
||||||
|
/>
|
||||||
|
<span>
|
||||||
|
{isLayingCategory
|
||||||
|
? 'Masa Transisi Laying: Hanya Deplesi yang dapat diisi. Stock (Pakan/OVK) tidak dapat diinput.'
|
||||||
|
: 'Masa Transisi Growing: Hanya Stock (Pakan/OVK) yang dapat diisi. Deplesi tidak dapat diinput.'}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Locked Recording Warning */}
|
||||||
|
{recordingRestriction.isLocked && (
|
||||||
|
<div className='alert alert-error mb-4'>
|
||||||
|
<Icon
|
||||||
|
icon='material-symbols:lock-outline'
|
||||||
|
width={24}
|
||||||
|
height={24}
|
||||||
|
/>
|
||||||
|
<span>{recordingRestriction.lockReason}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Depletions Table */}
|
{/* Depletions Table */}
|
||||||
{((type as 'add' | 'edit' | 'detail') !== 'detail' ||
|
{((type as 'add' | 'edit' | 'detail') !== 'detail' ||
|
||||||
(formik.values.depletions?.length ?? 0) > 0) && (
|
(formik.values.depletions?.length ?? 0) > 0) && (
|
||||||
<Card
|
<Card
|
||||||
title='Deplesi'
|
title='Deplesi'
|
||||||
className={{
|
className={{
|
||||||
wrapper: 'w-full mb-4 shadow',
|
wrapper: cn('w-full mb-4 shadow', {
|
||||||
|
'opacity-60':
|
||||||
|
!recordingRestriction.canEditDepletion &&
|
||||||
|
(type as 'add' | 'edit' | 'detail') !== 'detail',
|
||||||
|
}),
|
||||||
title: 'mb-4',
|
title: 'mb-4',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -2562,6 +2657,7 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
|||||||
setSelectedDepletions([]);
|
setSelectedDepletions([]);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
disabled={!recordingRestriction.canEditDepletion}
|
||||||
classNames={{
|
classNames={{
|
||||||
wrapper: 'flex justify-center',
|
wrapper: 'flex justify-center',
|
||||||
checkbox: 'checkbox checkbox-sm',
|
checkbox: 'checkbox checkbox-sm',
|
||||||
@@ -2598,6 +2694,7 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
disabled={!recordingRestriction.canEditDepletion}
|
||||||
classNames={{
|
classNames={{
|
||||||
wrapper: 'flex justify-center',
|
wrapper: 'flex justify-center',
|
||||||
checkbox: 'checkbox checkbox-sm',
|
checkbox: 'checkbox checkbox-sm',
|
||||||
@@ -2640,7 +2737,10 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
|||||||
idx
|
idx
|
||||||
).errorMessage
|
).errorMessage
|
||||||
}
|
}
|
||||||
isDisabled={type === 'detail'}
|
isDisabled={
|
||||||
|
type === 'detail' ||
|
||||||
|
!recordingRestriction.canEditDepletion
|
||||||
|
}
|
||||||
className={{
|
className={{
|
||||||
wrapper: 'w-full min-w-48',
|
wrapper: 'w-full min-w-48',
|
||||||
}}
|
}}
|
||||||
@@ -2679,7 +2779,10 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
|||||||
)
|
)
|
||||||
: null
|
: null
|
||||||
}
|
}
|
||||||
disabled={type === 'detail'}
|
disabled={
|
||||||
|
type === 'detail' ||
|
||||||
|
!recordingRestriction.canEditDepletion
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
{(type as 'add' | 'edit' | 'detail') !== 'detail' && (
|
{(type as 'add' | 'edit' | 'detail') !== 'detail' && (
|
||||||
@@ -2689,6 +2792,9 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
|||||||
type='button'
|
type='button'
|
||||||
color='error'
|
color='error'
|
||||||
onClick={() => removeDepletion(idx)}
|
onClick={() => removeDepletion(idx)}
|
||||||
|
disabled={
|
||||||
|
!recordingRestriction.canEditDepletion
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<Icon
|
<Icon
|
||||||
icon='mdi:trash-can'
|
icon='mdi:trash-can'
|
||||||
@@ -2706,27 +2812,38 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
|||||||
</div>
|
</div>
|
||||||
{(type as 'add' | 'edit' | 'detail') !== 'detail' && (
|
{(type as 'add' | 'edit' | 'detail') !== 'detail' && (
|
||||||
<div className='flex justify-center items-center mt-4 gap-4'>
|
<div className='flex justify-center items-center mt-4 gap-4'>
|
||||||
{selectedDepletions.length > 0 && (
|
{selectedDepletions.length > 0 &&
|
||||||
|
recordingRestriction.canEditDepletion && (
|
||||||
|
<Button
|
||||||
|
type='button'
|
||||||
|
color='error'
|
||||||
|
onClick={removeSelectedDepletions}
|
||||||
|
disabled={selectedDepletions.length === 0}
|
||||||
|
className='w-fit'
|
||||||
|
>
|
||||||
|
<Icon icon='mdi:trash-can' width={24} height={24} />
|
||||||
|
Hapus Terpilih ({selectedDepletions.length})
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
<Tooltip
|
||||||
|
content={
|
||||||
|
!recordingRestriction.canEditDepletion
|
||||||
|
? 'Deplesi tidak dapat ditambahkan pada masa transisi Growing'
|
||||||
|
: ''
|
||||||
|
}
|
||||||
|
position='top'
|
||||||
|
>
|
||||||
<Button
|
<Button
|
||||||
type='button'
|
type='button'
|
||||||
color='error'
|
color='success'
|
||||||
onClick={removeSelectedDepletions}
|
onClick={addDepletion}
|
||||||
disabled={selectedDepletions.length === 0}
|
|
||||||
className='w-fit'
|
className='w-fit'
|
||||||
|
disabled={!recordingRestriction.canEditDepletion}
|
||||||
>
|
>
|
||||||
<Icon icon='mdi:trash-can' width={24} height={24} />
|
<Icon icon='ic:round-plus' width={24} height={24} />
|
||||||
Hapus Terpilih ({selectedDepletions.length})
|
Tambah Depletion
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
</Tooltip>
|
||||||
<Button
|
|
||||||
type='button'
|
|
||||||
color='success'
|
|
||||||
onClick={addDepletion}
|
|
||||||
className='w-fit'
|
|
||||||
>
|
|
||||||
<Icon icon='ic:round-plus' width={24} height={24} />
|
|
||||||
Tambah Depletion
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
export type RecordingRestriction = {
|
||||||
|
canEditStock: boolean;
|
||||||
|
canEditDepletion: boolean;
|
||||||
|
canEditEgg: boolean;
|
||||||
|
isLocked: boolean;
|
||||||
|
lockReason?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getRecordingRestriction = (
|
||||||
|
category: 'GROWING' | 'LAYING',
|
||||||
|
isTransition: boolean,
|
||||||
|
currentCategory?: 'GROWING' | 'LAYING'
|
||||||
|
): RecordingRestriction => {
|
||||||
|
if (currentCategory === 'LAYING' && category === 'GROWING') {
|
||||||
|
return {
|
||||||
|
canEditStock: false,
|
||||||
|
canEditDepletion: false,
|
||||||
|
canEditEgg: false,
|
||||||
|
isLocked: true,
|
||||||
|
lockReason:
|
||||||
|
'Recording Growing telah terkunci karena Project Flock sudah masuk fase Laying',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (category === 'GROWING') {
|
||||||
|
if (isTransition) {
|
||||||
|
return {
|
||||||
|
canEditStock: true,
|
||||||
|
canEditDepletion: false,
|
||||||
|
canEditEgg: false,
|
||||||
|
isLocked: false,
|
||||||
|
lockReason: undefined,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
canEditStock: true,
|
||||||
|
canEditDepletion: true,
|
||||||
|
canEditEgg: false,
|
||||||
|
isLocked: false,
|
||||||
|
lockReason: undefined,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isTransition) {
|
||||||
|
return {
|
||||||
|
canEditStock: false,
|
||||||
|
canEditDepletion: true,
|
||||||
|
canEditEgg: false,
|
||||||
|
isLocked: false,
|
||||||
|
lockReason: undefined,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
canEditStock: true,
|
||||||
|
canEditDepletion: true,
|
||||||
|
canEditEgg: true,
|
||||||
|
isLocked: false,
|
||||||
|
lockReason: undefined,
|
||||||
|
};
|
||||||
|
};
|
||||||
+1
@@ -74,6 +74,7 @@ export type ProjectFlockKandangLookup = {
|
|||||||
available_quantity?: number;
|
available_quantity?: number;
|
||||||
population: number;
|
population: number;
|
||||||
chick_in_date: string;
|
chick_in_date: string;
|
||||||
|
is_transition: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ProjectFlockAvailableQuantity = {
|
export type ProjectFlockAvailableQuantity = {
|
||||||
|
|||||||
+1
-1
@@ -49,7 +49,7 @@ export type BaseRecording = {
|
|||||||
project_flock: ProjectFlock;
|
project_flock: ProjectFlock;
|
||||||
record_datetime: string;
|
record_datetime: string;
|
||||||
day: number;
|
day: number;
|
||||||
executed_at: string;
|
is_transition: boolean;
|
||||||
} & ProductionMetrics;
|
} & ProductionMetrics;
|
||||||
|
|
||||||
export type RecordingDepletion = {
|
export type RecordingDepletion = {
|
||||||
|
|||||||
Reference in New Issue
Block a user