refactor(FE-316,317,438): Move Uniformity feature under production

namespace
This commit is contained in:
rstubryan
2025-12-31 11:17:26 +07:00
parent f3f552bd16
commit a1e8f582ba
28 changed files with 71 additions and 76 deletions
@@ -0,0 +1,126 @@
import React from 'react';
import {
Bar,
BarChart,
CartesianGrid,
Rectangle,
ResponsiveContainer,
Tooltip,
XAxis,
YAxis,
} from 'recharts';
interface Payload {
value?: number;
name?: string;
dataKey?: string | number;
}
interface CustomTooltipProps {
active?: boolean;
payload?: readonly Payload[];
label?: string | number;
}
interface BarChartData {
name: string;
uv: number;
}
interface UniformityBarChartProps {
data: BarChartData[];
}
function CustomTooltip({ payload, label, active }: CustomTooltipProps) {
if (active && payload && payload.length && label !== undefined) {
const labelStr = String(label);
return (
<div className='bg-[#18181B] p-2.5 shadow-sm text-white rounded-2xl rounded-bl-none'>
<p className='m-0 font-bold text-white/50'>Uniformity 2025</p>
<div className='flex items-center gap-2 mt-2 justify-between'>
<div className='flex items-center gap-2'>
<div className='w-5 h-5 bg-[#0069E0] rounded-md'></div>
{payload[0].value} of Birds
</div>
<span>{labelStr}</span>
</div>
</div>
);
}
return null;
}
const UniformityBarChart: React.FC<UniformityBarChartProps> = ({ data }) => {
const margin = {
top: 20,
right: 30,
left: 20,
bottom: 5,
};
return (
<ResponsiveContainer
width='100%'
height='100%'
className='min-h-[300px] xl:min-h-[350px]'
>
<BarChart data={data} margin={margin} barGap={20}>
<defs>
<linearGradient id='activeBarGradient' x1='0' y1='0' x2='0' y2='1'>
<stop offset='0%' stopColor='#0069E0' stopOpacity={0.01} />
<stop offset='40%' stopColor='#0069E0' stopOpacity={1} />
<stop offset='100%' stopColor='#0069E0' stopOpacity={1} />
</linearGradient>
</defs>
<XAxis
dataKey='name'
axisLine={false}
tickLine={false}
label={{
value: 'Body Weight Range',
position: 'insideBottom',
offset: -5,
style: { textAnchor: 'middle', fontSize: 14, fill: '#18181B33' },
}}
/>
<YAxis
axisLine={false}
tickLine={false}
label={{
value: 'Number of Birds',
angle: -90,
position: 'insideLeft',
style: { textAnchor: 'middle', fontSize: 14, fill: '#18181B33' },
}}
/>
<Tooltip
cursor={false}
content={CustomTooltip}
wrapperStyle={{
width: '200px',
}}
/>
<CartesianGrid vertical={false} />
<Bar
name='Birds'
dataKey='uv'
fill='#FFFFFF'
stroke='#DDD'
strokeWidth={2}
radius={[25, 25, 0, 0]}
activeBar={
<Rectangle
fill='url(#activeBarGradient)'
stroke='#18181B'
strokeWidth={0}
radius={[25, 25, 0, 0]}
/>
}
/>
</BarChart>
</ResponsiveContainer>
);
};
export default UniformityBarChart;
@@ -0,0 +1,108 @@
import React from 'react';
import { Cell, Pie, PieChart, ResponsiveContainer } from 'recharts';
import Card from '@/components/Card';
import { Icon } from '@iconify/react';
import { formatNumber } from '@/lib/helper';
interface UniformityGaugeChartProps {
value: number;
label: string;
kandang?: string;
week?: string;
currentValue?: number;
totalValue?: number;
}
const UniformityGaugeChart: React.FC<UniformityGaugeChartProps> = ({
value,
label,
kandang,
week,
currentValue,
totalValue,
}) => {
const numberOfSegments = 50;
const filledSegments = Math.round((value / 100) * numberOfSegments);
const data = Array.from({ length: numberOfSegments }, (_, index) => ({
name: index,
value: 1,
filled: index < filledSegments,
}));
const activeColor = '#1890ff';
const inactiveColor = '#f0f0f0';
return (
<div className='flex flex-col w-full'>
<div className='h-64 w-full relative flex justify-center'>
<div className='relative w-full h-full flex flex-col items-center justify-end'>
<ResponsiveContainer width='100%' height='100%'>
<PieChart>
<Pie
data={data}
cx='50%'
cy='70%'
startAngle={180}
endAngle={0}
innerRadius='75%'
outerRadius='100%'
paddingAngle={2}
dataKey='value'
stroke='none'
isAnimationActive={false}
>
{data.map((entry, index) => (
<Cell
key={`cell-${index}`}
fill={entry.filled ? activeColor : inactiveColor}
/>
))}
</Pie>
</PieChart>
</ResponsiveContainer>
<div className='absolute inset-x-0 bottom-8 flex flex-col items-center justify-center'>
<span className='2xl:text-3xl text-2xl font-bold text-gray-800 mb-4'>
{value}%
</span>
<div className='mt-2 px-4 py-1 bg-base-100 rounded-full shadow-sm border border-gray-200'>
<span className='text-sm font-medium text-gray-700 mb-32'>
{label}
</span>
</div>
</div>
</div>
</div>
<Card
variant='bordered'
className={{
wrapper: 'w-full',
}}
>
<section className='flex items-center gap-4'>
<div className='w-12 h-12 bg-base-200 rounded-lg flex items-center justify-center border border-gray-200 shrink-0'>
<Icon icon='heroicons:calendar-date-range' width={24} height={24} />
</div>
<div className='grid grid-cols-1 min-w-0'>
<div className='flex items-center space-x-2 text-[#18181B80] text-sm mb-1'>
<span className='font-medium truncate'>{kandang}</span>
<span className='shrink-0'></span>
<span className='text-[#0069E0] font-semibold truncate'>
{week}
</span>
</div>
<div className='text-xl font-bold text-[#18181B80]'>
<span className='text-[#0069E0] break-all'>
{formatNumber(currentValue ?? 0)}
</span>
<span className='mx-1 text-gray-400 text-base'>From</span>
<span className='break-all'>{formatNumber(totalValue ?? 0)}</span>
</div>
</div>
</section>
</Card>
</div>
);
};
export default UniformityGaugeChart;
@@ -0,0 +1,93 @@
import Badge from '../../../../Badge';
import Card from '@/components/Card';
import { Icon } from '@iconify/react';
import { formatNumber } from '@/lib/helper';
const UniformityStat = () => {
const statisticsData = [
{
title: 'Total Population',
value: 1908978,
icon: 'heroicons-outline:inbox-stack',
change: '15.5%',
changeType: 'increase',
},
{
title: 'Total Uniformity',
value: 954489,
icon: 'heroicons-outline:scale',
change: '50%',
changeType: 'decrease',
},
{
title: 'Total Depletion',
value: 954489,
icon: 'heroicons-outline:inbox-stack',
change: '15.5%',
changeType: 'increase',
},
{
title: 'Total Production',
value: 2534,
icon: 'heroicons-outline:inbox-stack',
change: '15.5%',
changeType: 'increase',
},
];
return (
<section className='grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 gap-4'>
{statisticsData.map((stat, index) => (
<Card
key={index}
variant='bordered'
size='sm'
className={{
wrapper: 'w-full',
footer: 'bg-[#F8F8F8]',
}}
footer={
<>
<section className='flex items-center justify-between'>
<span className='font-normal text-gray-500'>
From last month
</span>
<Badge
color={stat.changeType === 'increase' ? 'success' : 'error'}
variant='soft'
className={{ badge: 'rounded-2xl' }}
>
<Icon
icon={
stat.changeType === 'increase'
? 'heroicons-outline:arrow-trending-up'
: 'heroicons-outline:arrow-trending-down'
}
width={16}
height={16}
className='inline-block'
/>
{stat.change}
</Badge>
</section>
</>
}
>
<div className='flex gap-2 items-center'>
<div className='p-2 border rounded-xl border-gray-300 shrink-0'>
<Icon icon={stat.icon} width={32} height={32} />
</div>
<div className='grid grid-cols-1 min-w-0'>
<span className='truncate'>{stat.title}</span>
<span className='text-xl font-semibold break-all'>
{formatNumber(stat.value)}
</span>
</div>
</div>
</Card>
))}
</section>
);
};
export default UniformityStat;