mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 13:32:00 +00:00
refactor(FE): Move sampling and result tables to UniformityDetail
This commit is contained in:
@@ -11,7 +11,7 @@ import Badge from '@/components/Badge';
|
|||||||
import Tooltip from '@/components/Tooltip';
|
import Tooltip from '@/components/Tooltip';
|
||||||
import RequirePermission from '@/components/helper/RequirePermission';
|
import RequirePermission from '@/components/helper/RequirePermission';
|
||||||
import { UniformityDetail as UniformityDetailType } from '@/types/api/production/uniformity';
|
import { UniformityDetail as UniformityDetailType } from '@/types/api/production/uniformity';
|
||||||
import { formatDate } from '@/lib/helper';
|
import { formatDate, formatNumber } from '@/lib/helper';
|
||||||
import { useUiStore } from '@/stores/ui/ui.store';
|
import { useUiStore } from '@/stores/ui/ui.store';
|
||||||
import UniformityDetailsPreview from '@/components/pages/production/uniformity/detail/UniformityDetailsPreview';
|
import UniformityDetailsPreview from '@/components/pages/production/uniformity/detail/UniformityDetailsPreview';
|
||||||
import {
|
import {
|
||||||
@@ -47,8 +47,6 @@ const UniformityDetail: React.FC<UniformityDetailProps> = ({
|
|||||||
<UniformityDetailsPreview
|
<UniformityDetailsPreview
|
||||||
info_umum={initialValues.info_umum}
|
info_umum={initialValues.info_umum}
|
||||||
uniformity_details={initialValues.uniformity_details}
|
uniformity_details={initialValues.uniformity_details}
|
||||||
sampling={initialValues.sampling}
|
|
||||||
result={initialValues.result}
|
|
||||||
uniformityId={initialValues.id}
|
uniformityId={initialValues.id}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@@ -154,7 +152,7 @@ const UniformityDetail: React.FC<UniformityDetailProps> = ({
|
|||||||
return (
|
return (
|
||||||
<div className='flex items-center gap-2'>
|
<div className='flex items-center gap-2'>
|
||||||
<span>{valueMap[id]}</span>
|
<span>{valueMap[id]}</span>
|
||||||
<Tooltip content='Lihat Detail'>
|
<Tooltip content='Lihat Detail' position='left'>
|
||||||
<button
|
<button
|
||||||
className='p-1 hover:bg-gray-100 rounded cursor-pointer'
|
className='p-1 hover:bg-gray-100 rounded cursor-pointer'
|
||||||
onClick={handleViewUniformityDetails}
|
onClick={handleViewUniformityDetails}
|
||||||
@@ -173,6 +171,87 @@ const UniformityDetail: React.FC<UniformityDetailProps> = ({
|
|||||||
[initialValues]
|
[initialValues]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const samplingTableData: DetailOptionType[] = useMemo(() => {
|
||||||
|
if (!initialValues.sampling) return [];
|
||||||
|
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
id: 'sampling-size',
|
||||||
|
label: 'Sampling size',
|
||||||
|
value: `${formatNumber(initialValues.sampling.chick_qty_of_weight)} of Birds`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'mean-weight',
|
||||||
|
label: 'Mean Weight',
|
||||||
|
value: `${initialValues.sampling.mean_weight} g`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'min-limit',
|
||||||
|
label: 'Min Limit (-10%)',
|
||||||
|
value: `${initialValues.sampling.mean_down} g`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'max-limit',
|
||||||
|
label: 'Max Limit (+10%)',
|
||||||
|
value: `${initialValues.sampling.mean_up} g`,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}, [initialValues.sampling]);
|
||||||
|
|
||||||
|
const columnsSampling: ColumnDef<DetailOptionType>[] = useMemo(
|
||||||
|
() => [
|
||||||
|
{
|
||||||
|
accessorKey: 'label',
|
||||||
|
header: 'Label',
|
||||||
|
cell: (props) => props.row.original.label,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: 'value',
|
||||||
|
header: 'Value',
|
||||||
|
cell: (props) => <span>{props.row.original.value}</span>,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
|
const resultTableData: DetailOptionType[] = useMemo(() => {
|
||||||
|
if (!initialValues.result) return [];
|
||||||
|
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
id: 'ideal-birds',
|
||||||
|
label: 'Ideal Birds',
|
||||||
|
value: `${formatNumber(initialValues.result.uniform_qty)} of Birds`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'outside-range',
|
||||||
|
label: 'Outside Range',
|
||||||
|
value: `${formatNumber(initialValues.result.outside_qty)} of Birds`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'uniformity',
|
||||||
|
label: 'Uniformity',
|
||||||
|
value: `${initialValues.result.uniformity} %`,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}, [initialValues.result]);
|
||||||
|
|
||||||
|
const resultColumns: ColumnDef<DetailOptionType>[] = useMemo(
|
||||||
|
() => [
|
||||||
|
{
|
||||||
|
accessorKey: 'label',
|
||||||
|
header: 'Label',
|
||||||
|
cell: (props) => props.row.original.label,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: 'value',
|
||||||
|
header: 'Value',
|
||||||
|
cell: (props) => <span>{props.row.original.value}</span>,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className='w-full h-full bg-white border-l border-gray-200'>
|
<section className='w-full h-full bg-white border-l border-gray-200'>
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
@@ -200,23 +279,55 @@ const UniformityDetail: React.FC<UniformityDetailProps> = ({
|
|||||||
paginationClassName: 'hidden',
|
paginationClassName: 'hidden',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Approve/Reject Buttons */}
|
|
||||||
{initialValues.result &&
|
|
||||||
initialValues.latest_approval?.step_name === 'CREATED' ? (
|
|
||||||
<>
|
|
||||||
<div className='divider my-3.5' />
|
|
||||||
<RequirePermission permissions='lti.production.uniformity.approve'>
|
|
||||||
<div className='grid grid-cols-1 sm:grid-cols-2 gap-4 [&_button]:rounded-lg'>
|
|
||||||
<Button variant='outline' onClick={handleReject}>
|
|
||||||
Reject
|
|
||||||
</Button>
|
|
||||||
<Button onClick={handleApprove}>Approve</Button>
|
|
||||||
</div>
|
|
||||||
</RequirePermission>
|
|
||||||
</>
|
|
||||||
) : null}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Sampling and Range */}
|
||||||
|
{initialValues.sampling && (
|
||||||
|
<div className=''>
|
||||||
|
<p className='text-sm font-medium mb-5'>Sampling and Range</p>
|
||||||
|
<Table<DetailOptionType>
|
||||||
|
data={samplingTableData}
|
||||||
|
columns={columnsSampling}
|
||||||
|
pageSize={4}
|
||||||
|
className={{
|
||||||
|
containerClassName: 'mb-0',
|
||||||
|
paginationClassName: 'hidden',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Result */}
|
||||||
|
{initialValues.result && (
|
||||||
|
<div className=''>
|
||||||
|
<p className='text-sm font-medium mb-5'>Result</p>
|
||||||
|
<Table<DetailOptionType>
|
||||||
|
data={resultTableData}
|
||||||
|
columns={resultColumns}
|
||||||
|
pageSize={4}
|
||||||
|
className={{
|
||||||
|
containerClassName: 'mb-0',
|
||||||
|
paginationClassName: 'hidden',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Approve/Reject Buttons */}
|
||||||
|
{initialValues.result &&
|
||||||
|
initialValues.latest_approval?.step_name === 'CREATED' ? (
|
||||||
|
<>
|
||||||
|
<div className='divider my-3.5' />
|
||||||
|
<RequirePermission permissions='lti.production.uniformity.approve'>
|
||||||
|
<div className='grid grid-cols-1 sm:grid-cols-2 gap-4 [&_button]:rounded-lg'>
|
||||||
|
<Button variant='outline' onClick={handleReject}>
|
||||||
|
Reject
|
||||||
|
</Button>
|
||||||
|
<Button onClick={handleApprove}>Approve</Button>
|
||||||
|
</div>
|
||||||
|
</RequirePermission>
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className='flex flex-col items-center justify-center py-10 text-gray-400'>
|
<div className='flex flex-col items-center justify-center py-10 text-gray-400'>
|
||||||
|
|||||||
@@ -7,14 +7,10 @@ import DrawerHeader from '@/components/helper/drawer/DrawerHeader';
|
|||||||
import { useUiStore } from '@/stores/ui/ui.store';
|
import { useUiStore } from '@/stores/ui/ui.store';
|
||||||
import {
|
import {
|
||||||
UniformityDetailItem,
|
UniformityDetailItem,
|
||||||
UniformitySampling,
|
|
||||||
UniformityResult,
|
|
||||||
UniformityInfoUmum,
|
UniformityInfoUmum,
|
||||||
} from '@/types/api/production/uniformity';
|
} from '@/types/api/production/uniformity';
|
||||||
import Table from '@/components/Table';
|
import Table from '@/components/Table';
|
||||||
import Badge from '@/components/Badge';
|
import Badge from '@/components/Badge';
|
||||||
import { formatNumber } from '@/lib/helper';
|
|
||||||
import { DetailOptionType } from '@/types/api/production/uniformity';
|
|
||||||
import {
|
import {
|
||||||
getWeightStatusColor,
|
getWeightStatusColor,
|
||||||
getWeightStatusIndicatorColor,
|
getWeightStatusIndicatorColor,
|
||||||
@@ -28,8 +24,6 @@ import { isResponseSuccess } from '@/lib/api-helper';
|
|||||||
|
|
||||||
interface UniformityDetailsPreviewProps {
|
interface UniformityDetailsPreviewProps {
|
||||||
info_umum: UniformityInfoUmum;
|
info_umum: UniformityInfoUmum;
|
||||||
sampling: UniformitySampling;
|
|
||||||
result: UniformityResult;
|
|
||||||
uniformity_details?: UniformityDetailItem[];
|
uniformity_details?: UniformityDetailItem[];
|
||||||
uniformityId: number;
|
uniformityId: number;
|
||||||
}
|
}
|
||||||
@@ -37,8 +31,6 @@ interface UniformityDetailsPreviewProps {
|
|||||||
const UniformityDetailsPreview = ({
|
const UniformityDetailsPreview = ({
|
||||||
info_umum,
|
info_umum,
|
||||||
uniformity_details: initialUniformityDetails,
|
uniformity_details: initialUniformityDetails,
|
||||||
sampling,
|
|
||||||
result,
|
|
||||||
uniformityId,
|
uniformityId,
|
||||||
}: UniformityDetailsPreviewProps) => {
|
}: UniformityDetailsPreviewProps) => {
|
||||||
const setExpandedDrawerOpen = useUiStore((s) => s.setExpandedDrawerOpen);
|
const setExpandedDrawerOpen = useUiStore((s) => s.setExpandedDrawerOpen);
|
||||||
@@ -66,87 +58,6 @@ const UniformityDetailsPreview = ({
|
|||||||
setShouldFetchDetails(true);
|
setShouldFetchDetails(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const samplingTableData: DetailOptionType[] = useMemo(() => {
|
|
||||||
if (!sampling) return [];
|
|
||||||
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
id: 'sampling-size',
|
|
||||||
label: 'Sampling size',
|
|
||||||
value: `${formatNumber(sampling.chick_qty_of_weight)} of Birds`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'mean-weight',
|
|
||||||
label: 'Mean Weight',
|
|
||||||
value: `${sampling.mean_weight} g`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'min-limit',
|
|
||||||
label: 'Min Limit (-10%)',
|
|
||||||
value: `${sampling.mean_down} g`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'max-limit',
|
|
||||||
label: 'Max Limit (+10%)',
|
|
||||||
value: `${sampling.mean_up} g`,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}, [sampling]);
|
|
||||||
|
|
||||||
const columnsSampling: ColumnDef<DetailOptionType>[] = useMemo(
|
|
||||||
() => [
|
|
||||||
{
|
|
||||||
accessorKey: 'label',
|
|
||||||
header: 'Label',
|
|
||||||
cell: (props) => props.row.original.label,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
accessorKey: 'value',
|
|
||||||
header: 'Value',
|
|
||||||
cell: (props) => <span>{props.row.original.value}</span>,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
|
|
||||||
const resultTableData: DetailOptionType[] = useMemo(() => {
|
|
||||||
if (!result) return [];
|
|
||||||
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
id: 'ideal-birds',
|
|
||||||
label: 'Ideal Birds',
|
|
||||||
value: `${formatNumber(result.uniform_qty)} of Birds`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'outside-range',
|
|
||||||
label: 'Outside Range',
|
|
||||||
value: `${formatNumber(result.outside_qty)} of Birds`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'uniformity',
|
|
||||||
label: 'Uniformity',
|
|
||||||
value: `${result.uniformity} %`,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}, [result]);
|
|
||||||
|
|
||||||
const resultColumns: ColumnDef<DetailOptionType>[] = useMemo(
|
|
||||||
() => [
|
|
||||||
{
|
|
||||||
accessorKey: 'label',
|
|
||||||
header: 'Label',
|
|
||||||
cell: (props) => props.row.original.label,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
accessorKey: 'value',
|
|
||||||
header: 'Value',
|
|
||||||
cell: (props) => <span>{props.row.original.value}</span>,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
|
|
||||||
const tableData = useMemo(() => {
|
const tableData = useMemo(() => {
|
||||||
if (!uniformity_details) return [];
|
if (!uniformity_details) return [];
|
||||||
|
|
||||||
@@ -229,40 +140,8 @@ const UniformityDetailsPreview = ({
|
|||||||
{/* Form Section */}
|
{/* Form Section */}
|
||||||
<div className='divider mt-3.5'></div>
|
<div className='divider mt-3.5'></div>
|
||||||
<section className='w-full px-6'>
|
<section className='w-full px-6'>
|
||||||
{info_umum || sampling || result ? (
|
{info_umum ? (
|
||||||
<div className='flex flex-col gap-4'>
|
<div className='flex flex-col gap-4'>
|
||||||
{/* Sampling and Range */}
|
|
||||||
{sampling && (
|
|
||||||
<div className=''>
|
|
||||||
<p className='text-sm font-medium mb-5'>Sampling and Range</p>
|
|
||||||
<Table<DetailOptionType>
|
|
||||||
data={samplingTableData}
|
|
||||||
columns={columnsSampling}
|
|
||||||
pageSize={4}
|
|
||||||
className={{
|
|
||||||
containerClassName: 'mb-0',
|
|
||||||
paginationClassName: 'hidden',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Result */}
|
|
||||||
{result && (
|
|
||||||
<div className=''>
|
|
||||||
<p className='text-sm font-medium mb-5'>Result</p>
|
|
||||||
<Table<DetailOptionType>
|
|
||||||
data={resultTableData}
|
|
||||||
columns={resultColumns}
|
|
||||||
pageSize={4}
|
|
||||||
className={{
|
|
||||||
containerClassName: 'mb-0',
|
|
||||||
paginationClassName: 'hidden',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{!uniformity_details || uniformity_details.length === 0 ? (
|
{!uniformity_details || uniformity_details.length === 0 ? (
|
||||||
<div className='mt-4'>
|
<div className='mt-4'>
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
Reference in New Issue
Block a user