Merge branch 'feat/FE/US-279/closing-button' of gitlab.com:mbugroup/lti-web-client into dev/hotfix/restu

This commit is contained in:
rstubryan
2025-12-11 10:46:52 +07:00
21 changed files with 2053 additions and 202 deletions
@@ -11,12 +11,12 @@ import { useState } from 'react';
import ApprovalSteps, {
useApprovalSteps,
} from '@/components/pages/ApprovalSteps';
import { PROJECT_FLOCK_KANDANG_APPROVAL_LINE } from '@/config/approval-line';
import ChickinFormView from '@/components/pages/production/chickin/form/tabs/ChickinFormView';
import ChickinLogsView from '@/components/pages/production/chickin/form/tabs/ChickLogsView';
import DrawerHeader from '@/components/helper/drawer/DrawerHeader';
import { Icon } from '@iconify/react';
import Badge from '@/components/Badge';
import { CHICKINS_APPROVAL_LINE } from '@/config/approval-line';
const ChickinFormKandang = ({
formType = 'add',
initialValues,
@@ -34,8 +34,8 @@ const ChickinFormKandang = ({
refresh: refreshApprovals,
} = useApprovalSteps({
latestApproval: initialValues?.approval,
approvalLines: PROJECT_FLOCK_KANDANG_APPROVAL_LINE,
moduleName: 'PROJECT_FLOCK_KANDANGS',
approvalLines: CHICKINS_APPROVAL_LINE,
moduleName: 'CHICKINS',
moduleId: initialValues?.id.toString() ?? '',
});
@@ -145,7 +145,7 @@ const ChickinLogsView = ({
})
)}
{initialValues?.approval?.step_number == 1 && (
{initialValues?.approval?.step_number <= 2 && (
<Button
color='success'
onClick={handleClickApprove}
@@ -9,6 +9,7 @@ import { ProjectFlock } from '@/types/api/production/project-flock';
import {
ClosingExpense,
ProjectFlockKandang,
StockItem,
} from '@/types/api/production/project-flock-kandang';
import { Icon } from '@iconify/react';
import useSWR from 'swr';
@@ -41,9 +42,9 @@ const ProjectFlockClosingForm = ({
const confirmationModalCloseClickHandler = async () => {
setIsClosingLoading(true);
const deleteProjectFlockRes = await ProjectFlockKandangApi.closing(
projectFlock?.id as number,
projectFlockKandang?.id as number,
{
closed_date: formatDate(new Date(), 'yyyy-MM-dd'),
closed_date: formatDate(new Date(), 'YYYY-MM-DD'),
action: isCanClose ? 'close' : 'unclose',
}
);
@@ -62,16 +63,16 @@ const ProjectFlockClosingForm = ({
const errorStock = useMemo(() => {
return isResponseSuccess(closingData)
? closingData?.data?.stock_remaining.every((stock) => stock.quantity > 0)
: false;
: true;
}, [closingData]);
const errorExpense = useMemo(() => {
return isResponseSuccess(closingData)
? closingData?.data?.expenses.every((expense) => expense.step < 5)
: false;
: true;
}, [closingData]);
const isCanCloseValid = !errorStock && !errorExpense;
const isCanCloseValid = true;
return (
<>
@@ -192,7 +193,7 @@ const ProjectFlockClosingForm = ({
: 'error'
}
>
{formatTitleCase(props.row.original.status)}
{formatTitleCase(props.row.original.step_name)}
</Badge>
);
},
@@ -211,18 +212,18 @@ const ProjectFlockClosingForm = ({
paginationClassName: 'hidden',
}}
/>
{errorExpense && (
<div className='text-center text-error'>
{/* {errorExpense && (
<div className='text-center text-error text-sm'>
*Pastikan semua biaya sudah selesai sebelum melakukan closing.
</div>
)}
)} */}
</div>
{/* Table Persediaan Gudang */}
<div className='divider'></div>
<div className='px-4 pb-4'>
<h2 className='text-2xl font-semibold'>Persediaan Gudang</h2>
<Table<ProductWarehouse>
<Table<StockItem>
data={
isResponseSuccess(closingData)
? closingData.data?.stock_remaining
@@ -231,11 +232,11 @@ const ProjectFlockClosingForm = ({
columns={[
{
header: 'Product',
accessorKey: 'product.name',
accessorKey: 'product_name',
},
{
header: 'Kategori',
accessorKey: 'product.product_category.name',
accessorKey: 'product_category',
},
{
header: 'Quantity',
@@ -243,7 +244,7 @@ const ProjectFlockClosingForm = ({
},
{
header: 'UOM',
accessorKey: 'product.uom.name',
accessorKey: 'uom',
},
]}
className={{
@@ -259,11 +260,11 @@ const ProjectFlockClosingForm = ({
paginationClassName: 'hidden',
}}
/>
{errorStock && (
<div className='text-center text-error'>
{/* {errorStock && (
<div className='text-center text-error text-sm'>
*Masih ada sisa stock yang belum dihabiskan.
</div>
)}
)} */}
</div>
<div className='p-4 mt-6'>
@@ -23,7 +23,12 @@ import toast from 'react-hot-toast';
import ApprovalSteps, {
useApprovalSteps,
} from '@/components/pages/ApprovalSteps';
import { PROJECT_FLOCK_APPROVAL_LINE } from '@/config/approval-line';
import {
PROJECT_FLOCK_APPROVAL_LINE,
PROJECT_FLOCK_KANDANGS_APPROVAL_LINE,
} from '@/config/approval-line';
import useSWR from 'swr';
import { ProjectFlockKandangApi } from '@/services/api/production';
const ProjectFlockDetail = ({
projectFlock,
@@ -38,10 +43,23 @@ const ProjectFlockDetail = ({
null
);
const selectedKandang = projectFlock.kandangs.find(
const selectedKandang = projectFlock.kandangs?.find(
(kandang) => kandang.id === Number(selectedKandangId)
);
const { data: projectFlockKandang, isLoading: projectFlockKandangLoading } =
useSWR(
selectedKandangId
? `${ProjectFlockKandangApi.basePath}/get-detail/${selectedKandangId}`
: null,
selectedKandangId
? () =>
ProjectFlockKandangApi.getSingle(
Number(selectedKandang?.project_flock_kandang_id)
)
: null
);
const {
approvals,
isLoading: approvalsLoading,
@@ -53,6 +71,20 @@ const ProjectFlockDetail = ({
moduleId: projectFlock?.id.toString() ?? '',
});
const { approvals: kandangApprovals, isLoading: kandangApprovalsLoading } =
useApprovalSteps({
latestApproval:
selectedKandangId && isResponseSuccess(projectFlockKandang)
? projectFlockKandang?.data?.approval
: undefined,
approvalLines: PROJECT_FLOCK_KANDANGS_APPROVAL_LINE,
moduleName: 'PROJECT_FLOCK_KANDANGS',
moduleId:
selectedKandangId && isResponseSuccess(projectFlockKandang)
? projectFlockKandang?.data?.id?.toString()
: '',
});
const confirmationModalDeleteClickHandler = async () => {
setIsDeleteLoading(true);
const deleteProjectFlockRes = await ProjectFlockApi.delete(
@@ -151,7 +183,7 @@ const ProjectFlockDetail = ({
className={{ badge: 'rounded-lg px-2' }}
>
<Icon icon='mdi:bookmark' width={12} height={12} />
{` ${formatTitleCase(projectFlock.category)}`}
{` ${formatTitleCase(projectFlock.category ?? '')}`}
</Badge>
</div>
{/* Information Grid */}
@@ -168,7 +200,7 @@ const ProjectFlockDetail = ({
}}
>
<Icon icon='mdi:account-circle' width={14} height={14} />{' '}
{projectFlock.created_user.name}
{projectFlock.created_user?.name}
</Badge>
</div>
@@ -194,7 +226,7 @@ const ProjectFlockDetail = ({
>
<Icon width={14} height={14} icon='mdi:circle-slice-8' /> Area
</div>
<div className='col-span-2'>{projectFlock.area.name}</div>
<div className='col-span-2'>{projectFlock?.area?.name}</div>
{/* BARIS 2 */}
<div
@@ -204,7 +236,7 @@ const ProjectFlockDetail = ({
>
<Icon width={14} height={14} icon='mdi:circle-slice-8' /> Lokasi
</div>
<div className='col-span-2'>{projectFlock.location.name}</div>
<div className='col-span-2'>{projectFlock?.location?.name}</div>
<div
className='col-span-1 flex flex-row items-center text-gray-400 font-semibold gap-2
@@ -213,7 +245,7 @@ const ProjectFlockDetail = ({
>
<Icon width={14} height={14} icon='mdi:circle-slice-8' /> FCR
</div>
<div className='col-span-2'>{projectFlock.fcr.name}</div>
<div className='col-span-2'>{projectFlock?.fcr?.name}</div>
{/* BARIS 3 (Terakhir - TIDAK PERLU garis di bawahnya) */}
<div className='col-span-1 flex flex-row items-center text-gray-400 font-semibold gap-2'>
@@ -221,7 +253,7 @@ const ProjectFlockDetail = ({
Kategori
</div>
<div className='col-span-2'>
{formatTitleCase(projectFlock.category)}
{formatTitleCase(projectFlock.category ?? '')}
</div>
</div>
</div>
@@ -231,6 +263,9 @@ const ProjectFlockDetail = ({
<div className='border-t-1 border-gray-300'>
<div className='p-4 flex flex-col gap-4'>
<h2 className='text-2xl font-semibold'>Kandang Aktif</h2>
{kandangApprovals && !kandangApprovalsLoading && (
<ApprovalSteps approvals={kandangApprovals} />
)}
{/* Badge Row */}
<div className='flex flex-row gap-2'>
<Badge
@@ -246,7 +281,7 @@ const ProjectFlockDetail = ({
height={12}
color={'success'}
/>{' '}
Kandang Aktif ({projectFlock.kandangs.length})
Kandang Aktif ({projectFlock.kandangs?.length})
</Badge>
<div className='divider divider-horizontal p-0 m-0'></div>
<Badge
@@ -289,7 +324,7 @@ const ProjectFlockDetail = ({
<span>Jenis Produk</span>
</div>
<div className='text-end text-gray-500'>
{budget.nonstock?.name}
{budget?.nonstock?.name}
</div>
</div>
<div className='flex flex-row justify-between items-center'>
@@ -298,7 +333,7 @@ const ProjectFlockDetail = ({
<span>Nama Satuan</span>
</div>
<div className='text-end text-gray-500'>
{budget.nonstock?.uom.name}
{budget?.nonstock?.uom?.name}
</div>
</div>
<div className='flex flex-row justify-between items-center'>
@@ -353,21 +388,21 @@ const ProjectFlockDetail = ({
value={selectedKandangId?.toString()}
size='md'
color='neutral'
disabled={projectFlock.approval.step_number == 1}
disabled={projectFlock?.approval?.step_number == 1}
>
{projectFlock.kandangs.map((kandang) => (
{projectFlock.kandangs?.map((kandang) => (
<div
key={kandang.id}
className={`grid grid-cols-2 gap-6 cursor-pointer hover:text-gray-800`}
onClick={() =>
projectFlock.approval.step_number > 1 &&
setSelectedKamdangId(kandang.id.toString())
projectFlock?.approval?.step_number > 1 &&
setSelectedKamdangId(kandang?.id?.toString())
}
>
<RadioGroupItem
value={kandang.id.toString()}
label={kandang.name}
disabled={projectFlock.approval.step_number == 1}
value={kandang?.id?.toString()}
label={kandang?.name}
disabled={projectFlock?.approval?.step_number == 1}
/>
<div className='text-end'>
<Badge
@@ -375,7 +410,7 @@ const ProjectFlockDetail = ({
badge: 'rounded-lg',
}}
>
Kapasitas {kandang.capacity} Ekor
Kapasitas {kandang?.capacity} Ekor
</Badge>
</div>
</div>
@@ -392,14 +427,15 @@ const ProjectFlockDetail = ({
variant='outline'
color='success'
disabled={
!selectedKandangId || projectFlock.approval.step_number == 1
!selectedKandangId ||
projectFlock?.approval?.step_number == 1
}
>
Chickin <Icon icon='mdi:checkbox-marked-outline' />
</Button>
</Link>
<Link
href={`/production/project-flock/closing?projectFlockId=${projectFlock.id}&projectFlockKandangId=${selectedKandangId}`}
href={`/production/project-flock/closing?projectFlockId=${projectFlock.id}&projectFlockKandangId=${selectedKandang?.project_flock_kandang_id}`}
className='m-0 p-0'
>
<Button
@@ -407,7 +443,8 @@ const ProjectFlockDetail = ({
variant='outline'
color='error'
disabled={
!selectedKandangId || projectFlock.approval.step_number == 1
!selectedKandangId ||
projectFlock?.approval?.step_number == 1
}
>
Close <Icon icon='mdi:checkbox-marked-circle-outline' />
@@ -226,9 +226,7 @@ export const getFilledTransferToLayingFormInitialValues = async (
// targetKandang.target_project_flock_kandang.kandang.capacity,
// TODO: integrate this to real API kandang capacity
maxQuantity:
targetKandang.target_project_flock_kandang.kandang.capacity ??
Infinity,
maxQuantity: Infinity,
}))
: [],