Files
lti-web-client/src/components/pages/report/production-result/ProductionResultContent.tsx
T
2026-01-15 09:48:02 +07:00

428 lines
13 KiB
TypeScript

'use client';
import { useState } from 'react';
import toast from 'react-hot-toast';
import { Icon } from '@iconify/react';
import Button from '@/components/Button';
import Dropdown from '@/components/dropdown/Dropdown';
import SelectInput, {
OptionType,
useSelect,
} from '@/components/input/SelectInput';
import Menu from '@/components/menu/Menu';
import MenuItem from '@/components/menu/MenuItem';
import Card from '@/components/Card';
import ProductionResultProjectFlockKandangTable from '@/components/pages/report/production-result/ProductionResultProjectFlockKandangTable';
import { BaseKandang } from '@/types/api/master-data/kandang';
import { AreaApi, LocationApi } from '@/services/api/master-data';
import {
ProjectFlockApi,
ProjectFlockKandangApi,
} from '@/services/api/production';
import { ProjectFlockKandang } from '@/types/api/production/project-flock-kandang';
import { isResponseError } from '@/lib/api-helper';
import Pagination from '@/components/Pagination';
import { ProductionResultReportApi } from '@/services/api/report/production-result';
const ProductionResultContent = () => {
const [projectFlockKandangs, setProjectFlockKandangs] = useState<
ProjectFlockKandang[] | null
>(null);
const [projectFlockKandangMetadata, setProjectFlockKandangMetadata] =
useState<
| {
page: number;
limit: number;
total_pages: number;
total_results: number;
}
| undefined
>(undefined);
const [page, setPage] = useState(1);
const [pageSize, setPageSize] = useState(10);
const [isLoadingSearch, setIsLoadingSearch] = useState(false);
const [isLoadingExportingToExcel, setIsLoadingExportingToExcel] =
useState(false);
const [selectedArea, setSelectedArea] = useState<OptionType | null>(null);
const [selectedLocation, setSelectedLocation] = useState<OptionType | null>(
null
);
const [selectedProjectFlock, setSelectedProjectFlock] =
useState<OptionType | null>(null);
const [selectedProjectFlockKandang, setSelectedProjectFlockKandang] =
useState<OptionType | null>(null);
const {
setInputValue: setAreaInputValue,
options: areaOptions,
isLoadingOptions: isLoadingAreaOptions,
loadMore: loadMoreAreas,
} = useSelect<BaseKandang>(AreaApi.basePath, 'id', 'name');
const areaChangeHandler = (val: OptionType | OptionType[] | null) => {
setSelectedArea(val as OptionType);
setSelectedLocation(null);
setSelectedProjectFlock(null);
setSelectedProjectFlockKandang(null);
};
const {
setInputValue: setLocationInputValue,
options: locationOptions,
isLoadingOptions: isLoadingLocationOptions,
loadMore: loadMoreLocations,
} = useSelect<BaseKandang>(LocationApi.basePath, 'id', 'name', 'search', {
area_id: selectedArea ? ((selectedArea as OptionType).value as string) : '',
});
const locationChangeHandler = (val: OptionType | OptionType[] | null) => {
setSelectedLocation(val as OptionType);
setSelectedProjectFlock(null);
setSelectedProjectFlockKandang(null);
};
const {
setInputValue: setProjectFlockInputValue,
options: projectFlockOptions,
isLoadingOptions: isLoadingProjectFlockOptions,
loadMore: loadMoreProjectFlocks,
} = useSelect<BaseKandang>(
ProjectFlockApi.basePath,
'id',
'flock_name',
'search',
{
area_id: selectedArea
? ((selectedArea as OptionType).value as string)
: '',
location_id: selectedLocation
? ((selectedLocation as OptionType).value as string)
: '',
category: 'LAYING',
}
);
const projectFlockChangeHandler = (val: OptionType | OptionType[] | null) => {
setSelectedProjectFlock(val as OptionType);
setSelectedProjectFlockKandang(null);
};
const {
setInputValue: setProjectFlockKandangInputValue,
options: projectFlockKandangOptions,
isLoadingOptions: isLoadingProjectFlockKandangOptions,
loadMore: loadMoreProjectFlockKandangs,
} = useSelect<BaseKandang>(
ProjectFlockKandangApi.basePath,
'id',
'kandang.name',
'search',
{
area_id: selectedArea
? ((selectedArea as OptionType).value as string)
: '',
location_id: selectedLocation
? ((selectedLocation as OptionType).value as string)
: '',
project_flock_id: selectedProjectFlock
? ((selectedProjectFlock as OptionType).value as string)
: '',
}
);
const projectFlockKandangChangeHandler = (
val: OptionType | OptionType[] | null
) => {
setSelectedProjectFlockKandang(val as OptionType);
};
const exportToExcelHandler = async () => {
setIsLoadingExportingToExcel(true);
await ProductionResultReportApi.exportProductionResultToExcel(
projectFlockKandangs
);
setIsLoadingExportingToExcel(false);
};
const searchHandler = async () => {
setProjectFlockKandangs(null);
setIsLoadingSearch(true);
try {
if (selectedProjectFlockKandang) {
const projectFlockKandangResponse =
await ProjectFlockKandangApi.getSingle(
selectedProjectFlockKandang?.value as number
);
if (
!projectFlockKandangResponse ||
isResponseError(projectFlockKandangResponse)
) {
throw new Error();
}
setProjectFlockKandangs([projectFlockKandangResponse.data]);
setProjectFlockKandangMetadata(projectFlockKandangResponse.meta);
setIsLoadingSearch(false);
return;
}
const projectFlockKandangsResponse = await ProjectFlockKandangApi.getAll({
area_id: selectedArea?.value,
project_flock_id: selectedProjectFlock?.value,
});
if (
!projectFlockKandangsResponse ||
isResponseError(projectFlockKandangsResponse)
) {
throw new Error();
}
setProjectFlockKandangs(projectFlockKandangsResponse.data);
setProjectFlockKandangMetadata(projectFlockKandangsResponse.meta);
setIsLoadingSearch(false);
} catch (error) {
toast.error('Gagal mencari data! Coba lagi.');
setProjectFlockKandangs(null);
setProjectFlockKandangMetadata(undefined);
setIsLoadingSearch(false);
}
};
const resetHandler = () => {
setProjectFlockKandangs(null);
setSelectedArea(null);
setSelectedLocation(null);
setSelectedProjectFlock(null);
setSelectedProjectFlockKandang(null);
// resetFilter();
};
return (
<div className='w-full p-4'>
<Card
variant='bordered'
className={{
wrapper: 'w-full',
}}
>
<div>
<h2 className='text-xl font-bold text-center'>
Laporan Hasil Produksi
</h2>
</div>
{/* Filters */}
<div className='flex flex-col gap-4 mb-6 mt-4'>
<div className='grid grid-cols-12 gap-4'>
<SelectInput
label='Area'
placeholder='Pilih Area'
options={areaOptions}
isLoading={isLoadingAreaOptions}
value={selectedArea}
onChange={areaChangeHandler}
onInputChange={setAreaInputValue}
onMenuScrollToBottom={loadMoreAreas}
isClearable
className={{
wrapper: 'col-span-12 sm:col-span-6 lg:col-span-4',
}}
/>
<SelectInput
label='Lokasi'
placeholder={
selectedArea ? 'Pilih Lokasi' : 'Pilih Area terlebih dahulu'
}
options={locationOptions}
isLoading={isLoadingLocationOptions}
value={selectedLocation}
onChange={locationChangeHandler}
onInputChange={setLocationInputValue}
onMenuScrollToBottom={loadMoreLocations}
isClearable
isDisabled={!selectedArea}
className={{
wrapper: 'col-span-12 sm:col-span-6 lg:col-span-4',
}}
/>
<SelectInput
label='Project Flock'
placeholder={
selectedArea && selectedLocation
? 'Pilih Project Flock'
: 'Pilih Area dan Lokasi terlebih dahulu'
}
options={projectFlockOptions}
isLoading={isLoadingProjectFlockOptions}
value={selectedProjectFlock}
onChange={projectFlockChangeHandler}
onInputChange={setProjectFlockInputValue}
onMenuScrollToBottom={loadMoreProjectFlocks}
isClearable
isDisabled={!selectedArea || !selectedLocation}
className={{
wrapper: 'col-span-12 sm:col-span-6 lg:col-span-4',
}}
/>
<SelectInput
label='Project Flock Kandang'
placeholder={
selectedProjectFlock
? 'Pilih Project Flock Kandang'
: 'Pilih Project Flock terlebih dahulu'
}
options={projectFlockKandangOptions}
isLoading={isLoadingProjectFlockKandangOptions}
value={selectedProjectFlockKandang}
onChange={projectFlockKandangChangeHandler}
onInputChange={setProjectFlockKandangInputValue}
onMenuScrollToBottom={loadMoreProjectFlockKandangs}
isClearable
isDisabled={!selectedProjectFlock}
className={{
wrapper: 'col-span-12 sm:col-span-6 lg:col-span-4',
}}
/>
</div>
<div className='grid grid-cols-12 gap-4'>
<div className='col-span-12 flex flex-wrap sm:justify-end items-end gap-2'>
<Button
onClick={searchHandler}
isLoading={isLoadingSearch}
disabled={
!selectedArea || !selectedLocation || !selectedProjectFlock
}
className='flex-1 sm:flex-none'
>
<Icon icon='heroicons-outline:search' width={20} height={20} />
Cari
</Button>
<Button
color='warning'
onClick={resetHandler}
className='flex-1 sm:flex-none'
>
<Icon icon='heroicons-outline:refresh' width={20} height={20} />
Reset
</Button>
<Dropdown
align='end'
direction='bottom'
trigger={
<Button
disabled={
!selectedArea ||
!selectedLocation ||
!selectedProjectFlock
}
>
Export{' '}
<Icon
icon='heroicons-outline:download'
width={20}
height={20}
/>
</Button>
}
>
<Menu>
<MenuItem
title='Export to Excel'
icon='icon-park-outline:excel'
isLoading={isLoadingExportingToExcel}
onClick={exportToExcelHandler}
className='text-nowrap'
/>
</Menu>
</Dropdown>
</div>
</div>
</div>
</Card>
<div className='mt-4'>
{isLoadingSearch && (
<span className='loading loading-dots loading-xl block mx-auto text-gray-400' />
)}
{!isLoadingSearch && !projectFlockKandangs && (
<p className='text-center text-gray-500'>
Silakan pilih filter dan klik tombol Cari untuk menampilkan data.
</p>
)}
{!isLoadingSearch && projectFlockKandangs?.length === 0 && (
<p className='text-center text-gray-500'>
Tidak ada data kandang project flock yang dapat ditampilkan.
</p>
)}
{!isLoadingSearch && projectFlockKandangs && (
<Card
variant='bordered'
className={{
wrapper: 'w-full',
}}
>
{projectFlockKandangs.map((projectFlockKandang) => (
<ProductionResultProjectFlockKandangTable
key={projectFlockKandang.id}
projectFlockKandangId={projectFlockKandang.id}
kandangName={projectFlockKandang.kandang.name}
/>
))}
<div className='max-w-sm ml-auto mt-5'>
<Pagination
totalItems={projectFlockKandangMetadata?.total_results || 0}
itemsPerPage={projectFlockKandangMetadata?.limit || 0}
currentPage={projectFlockKandangMetadata?.page || 0}
onPrevPage={() =>
setPage((currPage) =>
currPage > 1 ? currPage - 1 : currPage
)
}
onNextPage={() =>
setPage((currPage) =>
projectFlockKandangMetadata?.total_pages &&
currPage < projectFlockKandangMetadata.total_pages
? currPage + 1
: currPage
)
}
onPageChange={(pageNumber) => setPage(pageNumber)}
rowOptions={[10, 20, 50, 100]}
onRowChange={setPageSize}
/>
</div>
</Card>
)}
</div>
</div>
);
};
export default ProductionResultContent;