mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 05:22:02 +00:00
feat(FE-316): Add uniformity Excel template generator
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
import { formatNumber, formatDate } from '@/lib/helper';
|
||||
import { toast } from 'react-hot-toast';
|
||||
import * as XLSX from 'xlsx';
|
||||
import { ProjectFlockKandangLookup } from '@/types/api/production/project-flock';
|
||||
|
||||
export const generateUniformityTemplate = (
|
||||
availableQuantity: number,
|
||||
projectFlockKandangLookup: ProjectFlockKandangLookup
|
||||
) => {
|
||||
try {
|
||||
// Calculate 2% sample from total population
|
||||
const sampleSize = Math.round(availableQuantity * 0.02);
|
||||
|
||||
const data = Array.from({ length: sampleSize }, (_, index) => ({
|
||||
NO: index + 1,
|
||||
BW: '',
|
||||
}));
|
||||
|
||||
const worksheet = XLSX.utils.json_to_sheet(data, {
|
||||
header: ['NO', 'BW'],
|
||||
});
|
||||
|
||||
worksheet['!cols'] = [{ wch: 10 }, { wch: 15 }];
|
||||
|
||||
const workbook = XLSX.utils.book_new();
|
||||
|
||||
const kandangName = projectFlockKandangLookup.kandang?.name || 'Kandang';
|
||||
const flockName = projectFlockKandangLookup.project_flock?.flock_name || '';
|
||||
const flockPeriod = projectFlockKandangLookup.project_flock?.period || 1;
|
||||
|
||||
const sheetName =
|
||||
kandangName.length > 31 ? kandangName.substring(0, 31) : kandangName;
|
||||
XLSX.utils.book_append_sheet(workbook, worksheet, sheetName);
|
||||
|
||||
const sanitizedFlockName = flockName
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9]+/g, '-')
|
||||
.replace(/^-+|-+$/g, '');
|
||||
|
||||
const sanitizedKandangName = kandangName
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9]+/g, '-')
|
||||
.replace(/^-+|-+$/g, '');
|
||||
|
||||
const filename = `${formatDate(
|
||||
new Date(),
|
||||
'YYYY-MM-DD'
|
||||
)}-${sanitizedFlockName}-${sanitizedKandangName}-periode-${flockPeriod}-${sampleSize}-data.xlsx`;
|
||||
|
||||
XLSX.writeFile(workbook, filename);
|
||||
|
||||
toast.success(
|
||||
`Template berhasil dibuat dengan ${formatNumber(sampleSize)} baris data (2% dari ${formatNumber(availableQuantity)} populasi).`
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('Error generating uniformity template:', error);
|
||||
toast.error('Gagal membuat template Excel. Silakan coba lagi.');
|
||||
}
|
||||
};
|
||||
@@ -40,8 +40,9 @@ import { ProjectFlockKandangLookup } from '@/types/api/production/project-flock'
|
||||
import { Kandang } from '@/types/api/master-data/kandang';
|
||||
import UniformityPreviewForm from '@/components/pages/uniformity/form/UniformityPreviewForm';
|
||||
import UniformityResultForm from '@/components/pages/uniformity/form/UniformityResultForm';
|
||||
import { generateUniformityTemplate } from '@/components/pages/uniformity/export/UniformityTemplate';
|
||||
import useSWR from 'swr';
|
||||
import { cn } from '@/lib/helper';
|
||||
import { cn, formatNumber } from '@/lib/helper';
|
||||
|
||||
interface UniformityFormProps {
|
||||
formType?: 'add' | 'edit';
|
||||
@@ -352,20 +353,31 @@ const UniformityForm = ({
|
||||
|
||||
formik.setFieldValue('file', file);
|
||||
},
|
||||
[formik]
|
||||
[]
|
||||
);
|
||||
|
||||
const handleDateChange = useCallback(
|
||||
(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
formik.setFieldValue('date', e.target.value);
|
||||
},
|
||||
[formik]
|
||||
[]
|
||||
);
|
||||
|
||||
const handleRemoveFile = useCallback(() => {
|
||||
formik.setFieldValue('files', undefined);
|
||||
}, [formik]);
|
||||
|
||||
const handleDownloadTemplate = useCallback(() => {
|
||||
const availableQuantity = projectFlockKandangLookup?.available_quantity;
|
||||
|
||||
if (!availableQuantity || !projectFlockKandangLookup) {
|
||||
toast.error('Silakan pilih Project Flock dan Kandang terlebih dahulu.');
|
||||
return;
|
||||
}
|
||||
|
||||
generateUniformityTemplate(availableQuantity, projectFlockKandangLookup);
|
||||
}, [projectFlockKandangLookup]);
|
||||
|
||||
// ===== SIDE EFFECTS =====
|
||||
useEffect(() => {
|
||||
if (formik.values.date) {
|
||||
@@ -576,36 +588,38 @@ const UniformityForm = ({
|
||||
</span>
|
||||
<span className='text-xs font-light text-[#18181B80] text-center max-w-xs px-4'>
|
||||
{projectFlockKandangLookup?.available_quantity
|
||||
? `Jumlah data yang dibutuhkan: ${projectFlockKandangLookup.available_quantity.toLocaleString('id-ID')} (2% dari total populasi).`
|
||||
? `Jumlah data yang dibutuhkan: ${formatNumber(Math.round(projectFlockKandangLookup.available_quantity * 0.02))} (2% dari ${formatNumber(projectFlockKandangLookup.available_quantity)} populasi).`
|
||||
: 'Upload data file (*.xlsx)'}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className='flex items-center justify-center gap-2 py-4'>
|
||||
<div className='h-px bg-[#18181B33] w-8'></div>
|
||||
<span className='text-[#18181B33] text-xs'>
|
||||
Templates
|
||||
</span>
|
||||
<div className='h-px bg-[#18181B33] w-8'></div>
|
||||
</div>
|
||||
{projectFlockKandangLookup?.available_quantity && (
|
||||
<>
|
||||
<div className='flex items-center justify-center gap-2 py-4'>
|
||||
<div className='h-px bg-[#18181B33] w-8'></div>
|
||||
<span className='text-[#18181B33] text-xs'>
|
||||
Templates
|
||||
</span>
|
||||
<div className='h-px bg-[#18181B33] w-8'></div>
|
||||
</div>
|
||||
|
||||
<div className='flex items-center justify-center mb-10'>
|
||||
<Button
|
||||
type='button'
|
||||
variant='outline'
|
||||
className='btn-sm rounded-2xl shadow-md border border-base-300'
|
||||
href='https://www.timestored.com/data/sample/chickweight.csv'
|
||||
target='_blank'
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<Icon
|
||||
icon='heroicons:arrow-down-tray'
|
||||
width={18}
|
||||
height={18}
|
||||
/>
|
||||
Template XLSX
|
||||
</Button>
|
||||
</div>
|
||||
<div className='flex items-center justify-center mb-10'>
|
||||
<Button
|
||||
type='button'
|
||||
variant='outline'
|
||||
className='btn-sm rounded-2xl shadow-md border border-base-300'
|
||||
onClick={handleDownloadTemplate}
|
||||
>
|
||||
<Icon
|
||||
icon='heroicons:arrow-down-tray'
|
||||
width={18}
|
||||
height={18}
|
||||
/>
|
||||
Template XLSX
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</section>
|
||||
|
||||
Reference in New Issue
Block a user