Files
lti-web-client/src/components/pages/production/project-flock/detail/ProjectFlockDetail.tsx
T

476 lines
17 KiB
TypeScript

import Badge from '@/components/Badge';
import Button from '@/components/Button';
import Card from '@/components/Card';
import { RadioGroup, RadioGroupItem } from '@/components/input/RadioInput';
import Tooltip from '@/components/Tooltip';
import DrawerHeader from '@/components/helper/drawer/DrawerHeader';
import { cn, formatCurrency, formatDate, formatNumber } from '@/lib/helper';
import { ProjectFlock } from '@/types/api/production/project-flock';
import { Icon } from '@iconify/react';
import Link from 'next/link';
import { useRouter } from 'next/navigation';
import { useState } from 'react';
import { useModal } from '@/components/Modal';
import ConfirmationModal from '@/components/modal/ConfirmationModal';
import { ProjectFlockApi } from '@/services/api/production/project-flock';
import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
import toast from 'react-hot-toast';
import useSWR from 'swr';
import RequirePermission from '@/components/helper/RequirePermission';
import ApprovalStepsV2 from '@/components/helper/ApprovalStepsV2';
import { APPROVAL_WORKFLOWS } from '@/config/constant';
import Table from '@/components/Table';
import { ProjectFlockFormConfirmationTableType } from '../form/ProjectFlockForm';
import { ColumnDef } from '@tanstack/react-table';
import StatusBadge from '@/components/helper/StatusBadge';
import { ProjectFlockKandangApi } from '@/services/api/production/project-flock-kandang';
const ProjectFlockDetail = ({
projectFlock,
}: {
projectFlock: ProjectFlock;
}) => {
const router = useRouter();
const deleteModal = useModal();
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
const [openBudgets, setOpenBudget] = useState(false);
const [selectedKandangId, setSelectedKandangId] = useState<string | null>(
null
);
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 { data: projectFlockApprovalResponse } = useSWR(
projectFlock.id ? ['approval-project-flock', projectFlock.id] : undefined,
([, id]) => ProjectFlockApi.getApprovalLineHistory(Number(id))
);
const projectFlockApproval = isResponseSuccess(projectFlockApprovalResponse)
? projectFlockApprovalResponse.data
: undefined;
const { data: projectFlockKandangApprovalResponse } = useSWR(
selectedKandang?.project_flock_kandang_id
? [
'approval-project-flock-kandang',
selectedKandang?.project_flock_kandang_id,
]
: undefined,
([, id]) => ProjectFlockKandangApi.getApprovalLineHistory(Number(id))
);
const projectFlockKandangApproval = isResponseSuccess(
projectFlockKandangApprovalResponse
)
? projectFlockKandangApprovalResponse.data
: undefined;
const confirmationTableColumns: ColumnDef<ProjectFlockFormConfirmationTableType>[] =
[
{
header: 'Label',
accessorKey: 'label',
enableSorting: false,
cell: ({ row }) => {
const isSubRow = row.depth > 0;
return (
<>
{!isSubRow && row.original.label}
{isSubRow && (
<div
className={cn('w-full min-h-full flex items-stretch gap-0')}
>
<div className='w-px mx-4 bg-base-content/10' />
<span className='p-3'>{row.original.label}</span>
</div>
)}
</>
);
},
},
{
header: 'Value',
accessorKey: 'value',
enableSorting: false,
cell: ({ row }) => row.original.value,
},
];
const confirmationTableData: ProjectFlockFormConfirmationTableType[] = [
{
label: 'Tanggal',
value: formatDate(projectFlock.created_at, 'DD MMMM YYYY'),
},
{
label: 'Area',
value: projectFlock.area.name ?? '-',
},
{
label: 'Lokasi',
value: projectFlock.location.name ?? '-',
},
{
label: 'Flock',
value: projectFlock.flock_name ?? '-',
},
{
label: 'Kategori',
value: projectFlock.category ?? '-',
},
{
label: 'Standar Produksi',
value: projectFlock.production_standard.name ?? '-',
},
{
label: 'Periode',
value: projectFlock.period ?? '-',
},
];
const confirmationModalDeleteClickHandler = async () => {
setIsDeleteLoading(true);
const deleteProjectFlockRes = await ProjectFlockApi.delete(
projectFlock?.id as number
);
if (isResponseSuccess(deleteProjectFlockRes)) {
toast.success(deleteProjectFlockRes?.message as string);
router.push('/production/project-flock');
}
if (isResponseError(deleteProjectFlockRes)) {
toast.error(deleteProjectFlockRes?.message as string);
}
setIsDeleteLoading(false);
};
return (
<>
<div className='h-full w-full flex flex-col overflow-x-hidden overflow-y-auto'>
{/* Header */}
<DrawerHeader
leftIcon='heroicons:chevron-left'
leftIconHref='/production/project-flock'
leftIconClassName='hover:text-gray-400'
subtitle='Detail Flock'
className='sticky top-0 z-10 bg-base-100'
>
<RequirePermission permissions='lti.production.project_flocks.update'>
<Link
href={`/production/project-flock/detail/edit?projectFlockId=${projectFlock.id}`}
className='p-0'
>
<Tooltip content='Edit' position='bottom'>
<Button variant='link' className='p-0 text-neutral'>
<Icon icon='heroicons:pencil-square' width={20} height={20} />
</Button>
</Tooltip>
</Link>
</RequirePermission>
<RequirePermission permissions='lti.production.project_flocks.delete'>
<Button
variant='link'
className='p-0 text-error'
onClick={() => {
deleteModal.openModal();
}}
>
<Tooltip content='Hapus' position='bottom'>
<Icon icon='heroicons:trash' width={20} height={20} />
</Tooltip>
</Button>
</RequirePermission>
</DrawerHeader>
<ApprovalStepsV2
approvals={projectFlockApproval}
steps={APPROVAL_WORKFLOWS.PROJECT_FLOCKS}
/>
<div className='w-full p-4 flex flex-col gap-3 border-b border-base-content/10'>
<h4 className='text-base font-medium text-base-content/50 font-roboto'>
Informasi Umum
</h4>
<Table<ProjectFlockFormConfirmationTableType>
columns={confirmationTableColumns}
data={confirmationTableData}
withPagination={false}
pageSize={10000}
expanded={true}
getSubRows={(row) => row.subRows}
className={{
headerRowClassName: 'border-b border-base-content/10',
bodyRowClassName: 'border-none',
bodySubRowClassName: () => 'border-none',
bodySubRowColumnClassName: () => 'first:p-0',
}}
/>
</div>
<div className='w-full p-4 flex flex-col gap-3 border-b border-base-content/10'>
<h4 className='text-base font-medium text-base-content/50 font-roboto'>
Kandang
</h4>
<div className='flex flex-row flex-wrap gap-2 overflow-hidden'>
{projectFlock.kandangs?.filter(
(kandang) => kandang.status !== 'NON_ACTIVE'
).length > 0 && (
<StatusBadge
color='success'
text={`Kandang Active (${
projectFlock.kandangs?.filter(
(kandang) => kandang.status !== 'NON_ACTIVE'
).length ?? 0
})`}
className={{ badge: 'w-fit' }}
/>
)}
{projectFlock.kandangs?.filter(
(kandang) => kandang.status === 'NON_ACTIVE'
).length > 0 && (
<StatusBadge
color='error'
text={`Kandang Closed (${
projectFlock.kandangs?.filter(
(kandang) => kandang.status === 'NON_ACTIVE'
).length ?? 0
})`}
className={{ badge: 'w-fit' }}
/>
)}
<StatusBadge
color='neutral'
onClick={() => {
setOpenBudget(!openBudgets);
}}
text={
<>
{` ${formatCurrency(
(projectFlock.project_budgets ?? []).reduce(
(acc, curr) => acc + curr.price * curr.qty,
0
)
)}`}
<Icon
icon={`mdi:${openBudgets ? 'eye' : 'eye-off'}`}
width={12}
height={12}
/>
</>
}
className={{ badge: 'w-fit cursor-pointer' }}
/>
</div>
{/* Card List Project Budgets */}
{openBudgets &&
(projectFlock.project_budgets ?? []).map((budget) => (
<Card
key={budget.id}
variant='bordered'
className={{
wrapper: 'w-full rounded-lg',
body: 'p-3',
}}
>
<div className='flex flex-col gap-6'>
<div className='flex flex-row justify-between items-center'>
<div className='flex flex-row gap-2 items-center text-gray-400'>
<Icon icon={'mdi:tag'} width={14} height={14} />{' '}
<span>Jenis Produk</span>
</div>
<div className='text-end text-gray-500'>
{budget?.nonstock?.name}
</div>
</div>
<div className='flex flex-row justify-between items-center'>
<div className='flex flex-row gap-2 items-center text-gray-400'>
<Icon icon={'mdi:tag'} width={14} height={14} />{' '}
<span>Nama Satuan</span>
</div>
<div className='text-end text-gray-500'>
{budget?.nonstock?.uom?.name}
</div>
</div>
<div className='flex flex-row justify-between items-center'>
<div className='flex flex-row gap-2 items-center text-gray-400'>
<Icon icon={'mdi:file-multiple'} width={14} height={14} />{' '}
<span>Jumlah Pembelian</span>
</div>
<div className='text-end text-gray-500'>
{formatNumber(budget.qty)}
</div>
</div>
<div className='flex flex-row justify-between items-center'>
<div className='flex flex-row gap-2 items-center text-gray-400'>
<Icon icon={'mdi:file'} width={14} height={14} />{' '}
<span>Harga Satuan</span>
</div>
<div className='text-end text-gray-500'>
{formatCurrency(budget.price)}
</div>
</div>
<div className='flex flex-row justify-between items-center'>
<div className='flex flex-row gap-2 items-center text-gray-400'>
<Icon icon={'mdi:calculator'} width={14} height={14} />{' '}
<span>Total Harga</span>
</div>
<div className='text-end text-gray-500'>
{formatCurrency(budget.price * budget.qty)}
</div>
</div>
</div>
</Card>
))}
{/* Card Kandangs */}
<Card
variant='bordered'
className={{
wrapper: 'w-full rounded-lg',
body: 'p-3',
}}
>
<RadioGroup
name='gender'
className={{
radioWrapper: 'grid grid-cols-1 gap-6',
}}
onChange={(e) => setSelectedKandangId(e.target.value)}
value={selectedKandangId?.toString()}
size='md'
color='neutral'
disabled={projectFlock?.approval?.step_number == 1}
>
{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 &&
setSelectedKandangId(kandang?.id?.toString())
}
>
<RadioGroupItem
value={kandang?.id?.toString()}
label={kandang?.name}
disabled={projectFlock?.approval?.step_number == 1}
/>
<div className='text-end'>
<StatusBadge
color={
kandang?.status === 'NON_ACTIVE' ? 'error' : 'success'
}
text={<>Kapasitas {kandang?.capacity} Ekor</>}
className={{ badge: 'w-fit text-nowrap' }}
/>
</div>
</div>
))}
</RadioGroup>
</Card>
<div className='-mx-4'>
<ApprovalStepsV2
approvals={projectFlockKandangApproval}
steps={APPROVAL_WORKFLOWS.PROJECT_FLOCK_KANDANGS}
/>
</div>
<div
className={`grid gap-3 ${
selectedKandang?.status !== 'NON_ACTIVE'
? 'grid-cols-2'
: 'grid-cols-1'
}`}
>
{selectedKandang?.status !== 'NON_ACTIVE' && (
<RequirePermission permissions='lti.production.chickins.detail'>
<Link
href={`/production/project-flock/chickin/add/kandang?projectFlockKandangId=${selectedKandang?.project_flock_kandang_id}&projectFlockId=${projectFlock.id}`}
className='m-0 p-0'
>
<Button
className='w-full px-2 py-1 text-sm'
variant='outline'
color='success'
disabled={
!selectedKandangId ||
projectFlock?.approval?.step_number == 1
}
>
Chickin <Icon icon='mdi:checkbox-marked-outline' />
</Button>
</Link>
</RequirePermission>
)}
<RequirePermission permissions='lti.production.project_flock_kandangs.closing.detail'>
<Link
href={`/production/project-flock/closing?projectFlockId=${projectFlock.id}&projectFlockKandangId=${selectedKandang?.project_flock_kandang_id}`}
className='m-0 p-0'
>
<Button
className='w-full px-2 py-1 text-sm'
variant='outline'
color='error'
disabled={
!selectedKandangId ||
projectFlock?.approval?.step_number == 1
}
>
{selectedKandang?.status === 'NON_ACTIVE' ? (
<>
Unclose <Icon icon='mdi:lock-open-variant' />
</>
) : (
<>
Close <Icon icon='mdi:checkbox-marked-circle-outline' />
</>
)}
</Button>
</Link>
</RequirePermission>
</div>
</div>
</div>
<ConfirmationModal
ref={deleteModal.ref}
type='error'
text={`Apakah anda yakin ingin menghapus data Project Flock ini (${projectFlock?.flock_name} - ${projectFlock?.area?.name})?`}
secondaryButton={{
text: 'Tidak',
}}
primaryButton={{
text: 'Ya',
color: 'error',
isLoading: isDeleteLoading,
onClick: confirmationModalDeleteClickHandler,
}}
/>
</>
);
};
export default ProjectFlockDetail;