mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-22 22:35:45 +00:00
178 lines
5.4 KiB
TypeScript
178 lines
5.4 KiB
TypeScript
import Alert from '@/components/Alert';
|
|
import Card from '@/components/Card';
|
|
import { formatNumber } from '@/lib/helper';
|
|
import { DashboardStatisticsData } from '@/types/api/dashboard/dashboard';
|
|
import { Icon } from '@iconify/react';
|
|
|
|
interface DashboardStatsProps {
|
|
data: DashboardStatisticsData[];
|
|
}
|
|
|
|
// Konfigurasi untuk setiap kartu
|
|
const CARD_CONFIG = [
|
|
{
|
|
key: 'HPP Global',
|
|
icon: 'heroicons:banknotes',
|
|
alertColor: 'warning' as const,
|
|
suffix: ' /Kg',
|
|
prefix: 'RP ',
|
|
},
|
|
{
|
|
key: 'Avg. Selling Price',
|
|
icon: 'heroicons:document-currency-dollar',
|
|
alertColor: 'success' as const,
|
|
suffix: ' /Kg Telur',
|
|
prefix: '',
|
|
},
|
|
{
|
|
key: 'FCR',
|
|
icon: 'heroicons:clipboard-document-list',
|
|
alertColor: 'info' as const,
|
|
suffix: '',
|
|
prefix: '',
|
|
},
|
|
{
|
|
key: 'Mortality',
|
|
icon: 'heroicons:exclamation-triangle',
|
|
alertColor: 'error' as const,
|
|
suffix: ' %',
|
|
prefix: '',
|
|
},
|
|
];
|
|
|
|
const DashboardStats = ({ data }: DashboardStatsProps) => {
|
|
// Helper to get trend icon and color
|
|
const getTrendDisplay = (percent: number) => {
|
|
const isPositive = percent >= 0;
|
|
return {
|
|
icon: isPositive
|
|
? 'heroicons:arrow-trending-up'
|
|
: 'heroicons:arrow-trending-down',
|
|
color: isPositive ? 'text-[#008000]' : 'text-[#FF3A3A]',
|
|
value: Math.abs(percent),
|
|
};
|
|
};
|
|
|
|
// Helper to format value
|
|
const formatValue = (value: number, prefix: string, suffix: string) => {
|
|
return (
|
|
<>
|
|
{prefix}
|
|
{formatNumber(value)}
|
|
{suffix && (
|
|
<span className='text-sm font-normal text-base-content/50'>
|
|
{suffix}
|
|
</span>
|
|
)}
|
|
</>
|
|
);
|
|
};
|
|
|
|
return (
|
|
<div className='grid sm:grid-cols-2 xl:grid-cols-4 gap-3'>
|
|
{CARD_CONFIG.map((config) => {
|
|
// Find matching data from API
|
|
const cardData = data.find((item) => item.label === config.key);
|
|
|
|
if (!cardData) {
|
|
// Show placeholder card for missing data (FCR & Mortality)
|
|
return (
|
|
<Card
|
|
key={config.key}
|
|
className={{
|
|
wrapper: 'w-full rounded-xl border border-base-content/10',
|
|
body: 'p-0',
|
|
wrapperContent:
|
|
'h-full flex flex-col items-between justify-between',
|
|
footer: 'mt-0!',
|
|
}}
|
|
variant='bordered'
|
|
footer={
|
|
<div className='flex flex-row justify-between px-4 pb-4 max-h-12'>
|
|
<div className='text-base-content/50 font-semibold text-xs'>
|
|
From last month
|
|
</div>
|
|
<div className='text-base-content/50 font-semibold text-xs'>
|
|
Filter Required
|
|
</div>
|
|
</div>
|
|
}
|
|
>
|
|
<div className='flex flex-row items-center gap-3 px-4 py-4'>
|
|
<Alert
|
|
variant='soft'
|
|
className={`rounded-lg p-0 w-12.5 h-12.5 bg-[${config.alertColor}]/12 flex items-center justify-center`}
|
|
>
|
|
<Icon
|
|
icon={config.icon}
|
|
width={24}
|
|
height={24}
|
|
className='text-base-content/50'
|
|
/>
|
|
</Alert>
|
|
<div>
|
|
<h3 className='text-base-content/50 font-semibold text-sm'>
|
|
{config.key}
|
|
</h3>
|
|
<p className='text-xl font-semibold text-base-content/50'>
|
|
********
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</Card>
|
|
);
|
|
}
|
|
|
|
const trend = getTrendDisplay(cardData.percent_last_month);
|
|
|
|
return (
|
|
<Card
|
|
key={config.key}
|
|
className={{
|
|
wrapper: 'w-full rounded-xl border border-base-content/10',
|
|
body: 'p-0',
|
|
wrapperContent:
|
|
'h-full flex flex-col items-between justify-between',
|
|
footer: 'mt-0!',
|
|
}}
|
|
variant='bordered'
|
|
footer={
|
|
<div className='flex flex-row justify-between px-4 pb-4'>
|
|
<div className='text-base-content/50 font-semibold text-xs'>
|
|
From last month
|
|
</div>
|
|
<div
|
|
className={`${trend.color} font-semibold flex flex-row items-center gap-2 text-xs`}
|
|
>
|
|
<Icon icon={trend.icon} width={16} height={16} />
|
|
{trend.value}%
|
|
</div>
|
|
</div>
|
|
}
|
|
>
|
|
<div className='flex flex-row items-center gap-4 px-4 pt-4'>
|
|
<Alert
|
|
variant='soft'
|
|
color={config.alertColor}
|
|
className={`rounded-lg p-3 bg-[${config.alertColor}]/12 flex items-center justify-center`}
|
|
>
|
|
<Icon icon={config.icon} width={24} height={24} />
|
|
</Alert>
|
|
<div className='space-y-1'>
|
|
<h3 className='text-base-content/50 font-semibold text-sm'>
|
|
{cardData.label}
|
|
</h3>
|
|
<p className='text-xl font-semibold'>
|
|
{formatValue(cardData.value, config.prefix, config.suffix)}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</Card>
|
|
);
|
|
})}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default DashboardStats;
|