feat(FE): API integration dashboard

This commit is contained in:
randy-ar
2026-01-11 19:15:22 +07:00
parent c752cad057
commit 0da9f9d651
13 changed files with 95 additions and 4423 deletions
@@ -1,7 +1,6 @@
'use client'; 'use client';
import Button from '@/components/Button'; import Button from '@/components/Button';
import Card from '@/components/Card';
import { Icon } from '@iconify/react'; import { Icon } from '@iconify/react';
import Modal, { useModal } from '@/components/Modal'; import Modal, { useModal } from '@/components/Modal';
import DateInput from '@/components/input/DateInput'; import DateInput from '@/components/input/DateInput';
@@ -50,7 +49,7 @@ const DashboardProduction = () => {
const [analysisMode, setAnalysisMode] = useState<'OVERVIEW' | 'COMPARISON'>( const [analysisMode, setAnalysisMode] = useState<'OVERVIEW' | 'COMPARISON'>(
'OVERVIEW' 'OVERVIEW'
); );
const [endpointUrl, setEndpointUrl] = useState('/dashboard'); const [endpointUrl, setEndpointUrl] = useState('/dashboards');
const [selectedLocationIds, setSelectedLocationIds] = useState<number[]>([]); const [selectedLocationIds, setSelectedLocationIds] = useState<number[]>([]);
const [formErrorList, setFormErrorList] = useState<string[]>([]); const [formErrorList, setFormErrorList] = useState<string[]>([]);
@@ -84,8 +83,8 @@ const DashboardProduction = () => {
limit: 'limit', limit: 'limit',
location_id: selectedLocationIds ? selectedLocationIds.toString() : '', location_id: selectedLocationIds ? selectedLocationIds.toString() : '',
}); });
const comparedByOptions = [ const comparisonTypeOptions = [
{ value: 'LOCATION', label: 'Farm' }, { value: 'FARM', label: 'Farm' },
{ value: 'FLOCK', label: 'Flock' }, { value: 'FLOCK', label: 'Flock' },
{ value: 'KANDANG', label: 'Kandang' }, { value: 'KANDANG', label: 'Kandang' },
]; ];
@@ -99,7 +98,7 @@ const DashboardProduction = () => {
location: [] as OptionType[], location: [] as OptionType[],
kandang: [] as OptionType[], kandang: [] as OptionType[],
analysisMode: analysisMode, analysisMode: analysisMode,
comparedBy: '', comparisonType: '',
lokasiIds: [], lokasiIds: [],
flockIds: [], flockIds: [],
kandangIds: [], kandangIds: [],
@@ -115,6 +114,7 @@ const DashboardProduction = () => {
location_ids: normalizeToArray(values.location), location_ids: normalizeToArray(values.location),
flock_ids: normalizeToArray(values.flock), flock_ids: normalizeToArray(values.flock),
kandang_ids: normalizeToArray(values.kandang), kandang_ids: normalizeToArray(values.kandang),
comparison_type: values.comparisonType,
}); });
}, },
}); });
@@ -122,7 +122,7 @@ const DashboardProduction = () => {
const handleResetFilter = () => { const handleResetFilter = () => {
formik.resetForm(); formik.resetForm();
setAnalysisMode('OVERVIEW'); setAnalysisMode('OVERVIEW');
setEndpointUrl('/dashboard'); setEndpointUrl('/dashboards');
}; };
const handleApplyFilter = (values: DashboardFilter) => { const handleApplyFilter = (values: DashboardFilter) => {
@@ -140,8 +140,9 @@ const DashboardProduction = () => {
params.flock_ids = values.flock_ids.toString(); params.flock_ids = values.flock_ids.toString();
if (values.kandang_ids.length > 0) if (values.kandang_ids.length > 0)
params.kandang_ids = values.kandang_ids.toString(); params.kandang_ids = values.kandang_ids.toString();
if (values.comparison_type) params.comparison_type = values.comparison_type;
setEndpointUrl(`/dashboard?${new URLSearchParams(params).toString()}`); setEndpointUrl(`/dashboards?${new URLSearchParams(params).toString()}`);
console.log(endpointUrl); console.log(endpointUrl);
filterModal.closeModal(); filterModal.closeModal();
refreshDashboardProductionData(); refreshDashboardProductionData();
@@ -262,7 +263,13 @@ const DashboardProduction = () => {
data={dashboardProductionData} data={dashboardProductionData}
/> />
) : ( ) : (
<DashboardLineChartSkeleton /> <DashboardLineChartSkeleton
meta={
isResponseSuccess(dashboardProductionResponse)
? (dashboardProductionResponse.meta as unknown as DashboardMeta)
: undefined
}
/>
)} )}
</section> </section>
@@ -343,7 +350,7 @@ const DashboardProduction = () => {
formik.setFieldValue('location', []); formik.setFieldValue('location', []);
formik.setFieldValue('flock', []); formik.setFieldValue('flock', []);
formik.setFieldValue('kandang', []); formik.setFieldValue('kandang', []);
formik.setFieldValue('comparedBy', ''); formik.setFieldValue('comparisonType', '');
setSelectedLocationIds([]); setSelectedLocationIds([]);
}} }}
color='primary' color='primary'
@@ -368,21 +375,21 @@ const DashboardProduction = () => {
<div className='px-4'> <div className='px-4'>
<SelectInput <SelectInput
label='Compared By' label='Compared By'
value={comparedByOptions.find( value={comparisonTypeOptions.find(
(option) => option.value === formik.values.comparedBy (option) => option.value === formik.values.comparisonType
)} )}
onChange={(selected) => onChange={(selected) =>
formik.setFieldValue( formik.setFieldValue(
'comparedBy', 'comparisonType',
selected ? (selected as OptionType).value : '' selected ? (selected as OptionType).value : ''
) )
} }
errorMessage={formik.errors.comparedBy as string} errorMessage={formik.errors.comparisonType as string}
options={comparedByOptions} options={comparisonTypeOptions}
isLoading={isLoadingLocationOptions} isLoading={isLoadingLocationOptions}
isError={ isError={
Boolean(formik.errors.comparedBy) && Boolean(formik.errors.comparisonType) &&
Boolean(formik.touched.comparedBy) Boolean(formik.touched.comparisonType)
} }
/> />
</div> </div>
@@ -405,9 +412,9 @@ const DashboardProduction = () => {
options={locationOptions} options={locationOptions}
isLoading={isLoadingLocationOptions} isLoading={isLoadingLocationOptions}
isMulti={ isMulti={
comparedByOptions.find( comparisonTypeOptions.find(
(option) => option.value === formik.values.comparedBy (option) => option.value === formik.values.comparisonType
)?.value === 'LOCATION' )?.value === 'FARM'
} }
isError={ isError={
Boolean(formik.errors.location) && Boolean(formik.errors.location) &&
@@ -420,8 +427,8 @@ const DashboardProduction = () => {
{!( {!(
formik.values.analysisMode === 'COMPARISON' && formik.values.analysisMode === 'COMPARISON' &&
!( !(
formik.values.comparedBy === 'FLOCK' || formik.values.comparisonType === 'FLOCK' ||
formik.values.comparedBy === 'KANDANG' formik.values.comparisonType === 'KANDANG'
) )
) && ( ) && (
<div className='px-4'> <div className='px-4'>
@@ -435,8 +442,8 @@ const DashboardProduction = () => {
options={flockOptions} options={flockOptions}
isLoading={isLoadingFlockOptions} isLoading={isLoadingFlockOptions}
isMulti={ isMulti={
comparedByOptions.find( comparisonTypeOptions.find(
(option) => option.value === formik.values.comparedBy (option) => option.value === formik.values.comparisonType
)?.value === 'FLOCK' )?.value === 'FLOCK'
} }
isError={ isError={
@@ -450,7 +457,7 @@ const DashboardProduction = () => {
{/* Kandang */} {/* Kandang */}
{!( {!(
formik.values.analysisMode === 'COMPARISON' && formik.values.analysisMode === 'COMPARISON' &&
!(formik.values.comparedBy === 'KANDANG') !(formik.values.comparisonType === 'KANDANG')
) && ( ) && (
<div className='px-4'> <div className='px-4'>
<SelectInput <SelectInput
@@ -463,8 +470,8 @@ const DashboardProduction = () => {
options={kandangOptions} options={kandangOptions}
isLoading={isLoadingKandangOptions} isLoading={isLoadingKandangOptions}
isMulti={ isMulti={
comparedByOptions.find( comparisonTypeOptions.find(
(option) => option.value === formik.values.comparedBy (option) => option.value === formik.values.comparisonType
)?.value === 'KANDANG' )?.value === 'KANDANG'
} }
isError={ isError={
@@ -5,7 +5,7 @@ export type DashboardFilterType = {
startDate: string; startDate: string;
endDate: string; endDate: string;
analysisMode: string; analysisMode: string;
comparedBy: string | undefined; comparisonType: string | undefined;
location: OptionType | OptionType[]; location: OptionType | OptionType[];
lokasiIds: number[] | undefined; lokasiIds: number[] | undefined;
flock: OptionType | OptionType[] | undefined; flock: OptionType | OptionType[] | undefined;
@@ -20,7 +20,7 @@ export const DashboardFilterOverviewSchema: yup.ObjectSchema<DashboardFilterType
startDate: yup.string().required('Start date is required'), startDate: yup.string().required('Start date is required'),
endDate: yup.string().required('End date is required'), endDate: yup.string().required('End date is required'),
analysisMode: yup.string().required('Analysis mode is required'), analysisMode: yup.string().required('Analysis mode is required'),
comparedBy: yup.string().when('analysisMode', { comparisonType: yup.string().when('analysisMode', {
is: 'COMPARISON', is: 'COMPARISON',
then: (schema) => schema.required('Compared by is required'), then: (schema) => schema.required('Compared by is required'),
otherwise: (schema) => schema.optional(), otherwise: (schema) => schema.optional(),
@@ -63,7 +63,7 @@ export const DashboardFilterComparisonSchema: yup.ObjectSchema<DashboardFilterTy
startDate: yup.string().required('Start date is required'), startDate: yup.string().required('Start date is required'),
endDate: yup.string().required('End date is required'), endDate: yup.string().required('End date is required'),
analysisMode: yup.string().required('Analysis mode is required'), analysisMode: yup.string().required('Analysis mode is required'),
comparedBy: yup.string().when('analysisMode', { comparisonType: yup.string().when('analysisMode', {
is: 'COMPARISON', is: 'COMPARISON',
then: (schema) => schema.required('Compared by is required'), then: (schema) => schema.required('Compared by is required'),
otherwise: (schema) => schema.optional(), otherwise: (schema) => schema.optional(),
@@ -80,7 +80,7 @@ export const DashboardFilterComparisonSchema: yup.ObjectSchema<DashboardFilterTy
} }
return !!value; return !!value;
}), }),
flock: yup.mixed<OptionType | OptionType[]>().when('comparedBy', { flock: yup.mixed<OptionType | OptionType[]>().when('comparisonType', {
is: (value: string) => value === 'FLOCK' || value === 'KANDANG', is: (value: string) => value === 'FLOCK' || value === 'KANDANG',
then: (schema) => then: (schema) =>
schema.test('is-required', 'Flock is required', (value) => { schema.test('is-required', 'Flock is required', (value) => {
@@ -91,7 +91,7 @@ export const DashboardFilterComparisonSchema: yup.ObjectSchema<DashboardFilterTy
}), }),
otherwise: (schema) => schema.optional(), otherwise: (schema) => schema.optional(),
}), }),
kandang: yup.mixed<OptionType | OptionType[]>().when('comparedBy', { kandang: yup.mixed<OptionType | OptionType[]>().when('comparisonType', {
is: 'KANDANG', is: 'KANDANG',
then: (schema) => then: (schema) =>
schema.test('is-required', 'Kandang is required', (value) => { schema.test('is-required', 'Kandang is required', (value) => {
@@ -1,6 +1,7 @@
import { Icon } from '@iconify/react'; import { Icon } from '@iconify/react';
import { DashboardMeta } from '@/types/api/dashboard/dashboard';
const DashboardLineChartSkeleton = () => { const DashboardLineChartSkeleton = ({ meta }: { meta?: DashboardMeta }) => {
return ( return (
<div className='w-full bg-white rounded-lg shadow-sm border border-gray-200 p-6 relative'> <div className='w-full bg-white rounded-lg shadow-sm border border-gray-200 p-6 relative'>
{/* Header with title skeleton */} {/* Header with title skeleton */}
@@ -32,24 +33,49 @@ const DashboardLineChartSkeleton = () => {
<div className='flex-1 relative'> <div className='flex-1 relative'>
{/* Empty state centered in chart area */} {/* Empty state centered in chart area */}
<div className='absolute inset-0 flex flex-col items-center justify-center pb-12'> <div className='absolute inset-0 flex flex-col items-center justify-center pb-12'>
{/* Filter icon */} {!meta?.filters && (
<div className='w-12 h-12 bg-blue-500 rounded-xl flex items-center justify-center mb-4'> <>
<Icon {/* Filter icon */}
icon='heroicons:funnel' <div className='w-12 h-12 bg-blue-500 rounded-xl flex items-center justify-center mb-4'>
className='text-white' <Icon
width={24} icon='heroicons:funnel'
height={24} className='text-white'
/> width={24}
</div> height={24}
/>
</div>
{/* Empty state text */} {/* Empty state text */}
<h3 className='text-gray-900 font-semibold text-base mb-2'> <h3 className='text-gray-900 font-semibold text-base mb-2'>
No Filters Selected No Filters Selected
</h3> </h3>
<p className='text-gray-500 text-sm text-center max-w-xs'> <p className='text-gray-500 text-sm text-center max-w-xs'>
Please choose filters to narrow down your results and make your Please choose filters to narrow down your results and make
search easier. your search easier.
</p> </p>
</>
)}
{meta?.filters && (
<>
{/* Filter icon */}
<div className='w-12 h-12 bg-blue-500 rounded-xl flex items-center justify-center mb-4'>
<Icon
icon='heroicons:chart-bar'
className='text-white'
width={24}
height={24}
/>
</div>
{/* Empty state text */}
<h3 className='text-gray-900 font-semibold text-base mb-2'>
Data Not Yet Available
</h3>
<p className='text-gray-500 text-sm text-center max-w-xs'>
Please change your filters to get the data.
</p>
</>
)}
</div> </div>
{/* Placeholder for chart height */} {/* Placeholder for chart height */}
@@ -40,6 +40,7 @@ const DebtSupplierTab = () => {
const [filterSupplier, setFilterSupplier] = useState<OptionType[]>([]); const [filterSupplier, setFilterSupplier] = useState<OptionType[]>([]);
const [filterStartDate, setFilterStartDate] = useState(''); const [filterStartDate, setFilterStartDate] = useState('');
const [filterEndDate, setFilterEndDate] = useState(''); const [filterEndDate, setFilterEndDate] = useState('');
const [filterDataType, setFilterDataType] = useState<OptionType>();
const [filterErrors, setFilterErrors] = useState<Record<string, string>>({}); const [filterErrors, setFilterErrors] = useState<Record<string, string>>({});
const filterModal = useModal(); const filterModal = useModal();
@@ -142,6 +143,7 @@ const DebtSupplierTab = () => {
filter_by: 'do_date' as const, filter_by: 'do_date' as const,
start_date: filterStartDate || undefined, start_date: filterStartDate || undefined,
end_date: filterEndDate || undefined, end_date: filterEndDate || undefined,
date_type: filterDataType ? filterDataType.value : undefined,
limit: 100, limit: 100,
page: 1, page: 1,
}; };
@@ -556,6 +558,9 @@ const DebtSupplierTab = () => {
placeholder='Pilih Filter Berdasarkan' placeholder='Pilih Filter Berdasarkan'
options={dataTypeOptions} options={dataTypeOptions}
value={dataTypeOptions[0]} value={dataTypeOptions[0]}
onChange={(val) => {
setFilterDataType(val ? (val as OptionType) : undefined);
}}
isDisabled={true} isDisabled={true}
className={{ wrapper: 'w-full' }} className={{ wrapper: 'w-full' }}
/> />
@@ -1,366 +0,0 @@
{
"code": 200,
"status": "success",
"message": "Get dashboard performance flock comparison successfully",
"meta": {
"page": 1,
"limit": 10,
"total_pages": 1,
"total_results": 1,
"filters": {
"start_date": "2025-12-01",
"end_date": "2025-12-31",
"analysis_mode": "COMPARASION",
"lokasi_ids": [1],
"flock_ids": [1, 2, 3],
"kandang_ids": []
}
},
"data": {
"statistics_data": [
{
"label": "HPP Global",
"value": 16200,
"percent_last_month": 15.5
},
{
"label": "Avg. Selling Price",
"value": 28300,
"percent_last_month": -50
},
{
"label": "FCR",
"value": 24.02,
"percent_last_month": 15.5
},
{
"label": "Mortality",
"value": 5,
"percent_last_month": -15.5
}
],
"charts": {
"flock": {
"series": [
{
"id": 1,
"label": "Flock Dago",
"unit": "%"
},
{
"id": 2,
"label": "Flock Sulanjana",
"unit": "%"
},
{
"id": 3,
"label": "Flock Garut 2",
"unit": "%"
}
],
"dataset": [
{
"week": 1,
"1": 18.5,
"2": 20.2,
"3": 17.8
},
{
"week": 2,
"1": 19.2,
"2": 21.5,
"3": 18.1
},
{
"week": 3,
"1": 20.1,
"2": 22.8,
"3": 18.5
},
{
"week": 4,
"1": 21.5,
"2": 24.0,
"3": 19.2
},
{
"week": 5,
"1": 22.8,
"2": 23.5,
"3": 20.4
},
{
"week": 6,
"1": 24.2,
"2": 22.1,
"3": 21.6
},
{
"week": 7,
"1": 25.8,
"2": 21.8,
"3": 22.9
},
{
"week": 8,
"1": 26.5,
"2": 22.4,
"3": 23.5
},
{
"week": 9,
"1": 26.2,
"2": 23.9,
"3": 24.1
},
{
"week": 10,
"1": 25.4,
"2": 24.8,
"3": 24.8
},
{
"week": 11,
"1": 24.8,
"2": 26.2,
"3": 25.4
},
{
"week": 12,
"1": 24.1,
"2": 27.5,
"3": 26.2
},
{
"week": 13,
"1": 23.5,
"2": 28.1,
"3": 27.5
},
{
"week": 14,
"1": 22.8,
"2": 27.4,
"3": 28.4
},
{
"week": 15,
"1": 21.9,
"2": 26.5,
"3": 29.1
},
{
"week": 16,
"1": 21.2,
"2": 25.8,
"3": 28.5
},
{
"week": 17,
"1": 20.8,
"2": 24.2,
"3": 27.2
},
{
"week": 18,
"1": 20.1,
"2": 23.1,
"3": 26.1
},
{
"week": 19,
"1": 19.5,
"2": 22.5,
"3": 25.8
},
{
"week": 20,
"1": 19.8,
"2": 21.9,
"3": 24.5
},
{
"week": 21,
"1": 20.5,
"2": 21.4,
"3": 23.2
},
{
"week": 22,
"1": 21.8,
"2": 21.0,
"3": 22.8
},
{
"week": 23,
"1": 22.5,
"2": 21.8,
"3": 21.9
},
{
"week": 24,
"1": 23.9,
"2": 22.5,
"3": 21.2
},
{
"week": 25,
"1": 24.5,
"2": 23.4,
"3": 20.5
},
{
"week": 26,
"1": 25.1,
"2": 24.8,
"3": 20.1
},
{
"week": 27,
"1": 26.8,
"2": 25.5,
"3": 19.8
},
{
"week": 28,
"1": 27.5,
"2": 26.2,
"3": 20.4
},
{
"week": 29,
"1": 27.2,
"2": 27.8,
"3": 21.5
},
{
"week": 30,
"1": 26.4,
"2": 28.5,
"3": 22.1
},
{
"week": 31,
"1": 25.8,
"2": 29.2,
"3": 23.4
},
{
"week": 32,
"1": 24.9,
"2": 28.8,
"3": 24.2
},
{
"week": 33,
"1": 24.2,
"2": 27.4,
"3": 25.8
},
{
"week": 34,
"1": 23.5,
"2": 26.5,
"3": 26.4
},
{
"week": 35,
"1": 22.8,
"2": 25.8,
"3": 27.1
},
{
"week": 36,
"1": 21.4,
"2": 24.2,
"3": 27.8
},
{
"week": 37,
"1": 20.5,
"2": 23.5,
"3": 28.2
},
{
"week": 38,
"1": 19.8,
"2": 22.8,
"3": 28.9
},
{
"week": 39,
"1": 19.2,
"2": 21.9,
"3": 27.5
},
{
"week": 40,
"1": 18.8,
"2": 21.2,
"3": 26.4
},
{
"week": 41,
"1": 18.5,
"2": 20.8,
"3": 25.2
},
{
"week": 42,
"1": 19.1,
"2": 20.5,
"3": 24.1
},
{
"week": 43,
"1": 20.2,
"2": 21.4,
"3": 23.5
},
{
"week": 44,
"1": 21.5,
"2": 22.8,
"3": 22.1
},
{
"week": 45,
"1": 22.8,
"2": 24.1,
"3": 21.8
},
{
"week": 46,
"1": 23.4,
"2": 25.2,
"3": 20.9
},
{
"week": 47,
"1": 24.1,
"2": 26.8,
"3": 20.1
},
{
"week": 48,
"1": 25.8,
"2": 27.5,
"3": 19.5
},
{
"week": 49,
"1": 26.2,
"2": 28.2,
"3": 19.1
},
{
"week": 50,
"1": 26.8,
"2": 28.8,
"3": 18.8
}
]
}
}
}
}
@@ -1,347 +0,0 @@
{
"statistics_data": [
{
"label": "HPP Global",
"value": 16200,
"percent_last_month": 15.5
},
{
"label": "Avg. Selling Price",
"value": 28300,
"percent_last_month": -50
},
{
"label": "FCR",
"value": 24.02,
"percent_last_month": 15.5
},
{
"label": "Mortality",
"value": 5,
"percent_last_month": -15.5
}
],
"charts": {
"kandang": {
"series": [
{
"id": 1,
"label": "Kandang Dago",
"unit": "%"
},
{
"id": 2,
"label": "Kandang Sulanjana",
"unit": "%"
},
{
"id": 3,
"label": "Kandang Garut 2",
"unit": "%"
}
],
"dataset": [
{
"week": 1,
"1": 21.2,
"2": 19.5,
"3": 20.1
},
{
"week": 2,
"1": 22.5,
"2": 19.8,
"3": 20.4
},
{
"week": 3,
"1": 23.1,
"2": 20.2,
"3": 21.0
},
{
"week": 4,
"1": 24.5,
"2": 21.5,
"3": 22.1
},
{
"week": 5,
"1": 25.8,
"2": 22.4,
"3": 23.5
},
{
"week": 6,
"1": 26.2,
"2": 23.1,
"3": 24.8
},
{
"week": 7,
"1": 27.5,
"2": 24.5,
"3": 26.2
},
{
"week": 8,
"1": 28.1,
"2": 25.8,
"3": 27.5
},
{
"week": 9,
"1": 28.8,
"2": 26.2,
"3": 28.4
},
{
"week": 10,
"1": 29.1,
"2": 27.5,
"3": 28.1
},
{
"week": 11,
"1": 28.5,
"2": 28.1,
"3": 27.4
},
{
"week": 12,
"1": 27.2,
"2": 29.1,
"3": 26.5
},
{
"week": 13,
"1": 26.1,
"2": 28.5,
"3": 25.8
},
{
"week": 14,
"1": 25.8,
"2": 27.2,
"3": 24.2
},
{
"week": 15,
"1": 24.5,
"2": 26.1,
"3": 23.1
},
{
"week": 16,
"1": 23.2,
"2": 25.8,
"3": 22.5
},
{
"week": 17,
"1": 22.8,
"2": 24.5,
"3": 21.9
},
{
"week": 18,
"1": 21.9,
"2": 23.2,
"3": 21.0
},
{
"week": 19,
"1": 21.2,
"2": 22.8,
"3": 20.5
},
{
"week": 20,
"1": 20.5,
"2": 21.9,
"3": 19.8
},
{
"week": 21,
"1": 19.8,
"2": 21.2,
"3": 19.2
},
{
"week": 22,
"1": 20.4,
"2": 20.5,
"3": 18.5
},
{
"week": 23,
"1": 21.0,
"2": 19.8,
"3": 18.1
},
{
"week": 24,
"1": 22.1,
"2": 20.4,
"3": 17.8
},
{
"week": 25,
"1": 23.5,
"2": 21.0,
"3": 18.5
},
{
"week": 26,
"1": 24.8,
"2": 22.1,
"3": 19.2
},
{
"week": 27,
"1": 26.2,
"2": 23.5,
"3": 20.1
},
{
"week": 28,
"1": 27.5,
"2": 24.8,
"3": 21.5
},
{
"week": 29,
"1": 28.4,
"2": 26.2,
"3": 22.8
},
{
"week": 30,
"1": 28.1,
"2": 27.5,
"3": 24.2
},
{
"week": 31,
"1": 27.4,
"2": 28.4,
"3": 25.8
},
{
"week": 32,
"1": 26.5,
"2": 28.1,
"3": 26.5
},
{
"week": 33,
"1": 25.8,
"2": 27.4,
"3": 27.2
},
{
"week": 34,
"1": 24.2,
"2": 26.5,
"3": 28.1
},
{
"week": 35,
"1": 23.1,
"2": 25.8,
"3": 28.5
},
{
"week": 36,
"1": 22.5,
"2": 24.2,
"3": 29.1
},
{
"week": 37,
"1": 21.9,
"2": 23.1,
"3": 28.8
},
{
"week": 38,
"1": 21.0,
"2": 22.5,
"3": 28.1
},
{
"week": 39,
"1": 20.5,
"2": 21.9,
"3": 27.4
},
{
"week": 40,
"1": 19.8,
"2": 21.0,
"3": 26.5
},
{
"week": 41,
"1": 19.2,
"2": 20.5,
"3": 25.8
},
{
"week": 42,
"1": 18.5,
"2": 19.8,
"3": 24.2
},
{
"week": 43,
"1": 18.1,
"2": 19.2,
"3": 23.1
},
{
"week": 44,
"1": 17.8,
"2": 18.5,
"3": 22.5
},
{
"week": 45,
"1": 18.5,
"2": 18.1,
"3": 21.9
},
{
"week": 46,
"1": 19.2,
"2": 17.8,
"3": 21.0
},
{
"week": 47,
"1": 20.1,
"2": 18.5,
"3": 20.5
},
{
"week": 48,
"1": 21.5,
"2": 19.2,
"3": 19.8
},
{
"week": 49,
"1": 22.8,
"2": 20.1,
"3": 19.2
},
{
"week": 50,
"1": 24.2,
"2": 21.5,
"3": 18.5
}
]
}
}
}
File diff suppressed because it is too large Load Diff
@@ -1,15 +0,0 @@
{
"statistics_data": [
{
"label": "HPP Global",
"value": 16200,
"percent_last_month": 15.5
},
{
"label": "Avg. Selling Price",
"value": 28300,
"percent_last_month": -50
}
],
"charts": {}
}
File diff suppressed because it is too large Load Diff
@@ -1,42 +0,0 @@
/**
* Dummy data for DashboardProduction
* Generated from: dashboard.production.dummy.json
*
* This file is auto-generated. Do not edit manually.
*/
import { Dashboard, DashboardMeta } from '../../types/api/dashboard/dashboard';
import { BaseApiResponse } from '@/types/api/api-general';
import dummyData from './dashboard.overview.dummy.json';
import dummyData2 from './dashboard.comparasion.location.dummy.json';
import dummyData3 from './dashboard.comparasion.flock.dummy.json';
import dummyData4 from './dashboard.comparasion.kandang.dummy.json';
import dummyData5 from './dashboard.default.json';
/**
* Get dummy DashboardProduction data
* @returns Promise with BaseApiResponse containing DashboardProduction
*/
export async function getDummySingle(): Promise<BaseApiResponse<Dashboard>> {
return new Promise((resolve) => {
setTimeout(() => {
resolve({
code: 200,
status: 'success',
message: 'Data retrieved successfully',
meta: {
page: 1,
limit: 1,
total_pages: 1,
total_results: 1,
filters: {
analysis_mode: 'OVERVIEW',
location_ids: [1],
flock_ids: [1],
kandang_ids: [1],
},
} as DashboardMeta,
data: dummyData as unknown as Dashboard,
});
});
});
}
+1 -1
View File
@@ -165,4 +165,4 @@
"debt_price": -125000000 "debt_price": -125000000
} }
} }
] ]
+6 -11
View File
@@ -1,7 +1,7 @@
import { BaseApiService } from '@/services/api/base'; import { BaseApiService } from '@/services/api/base';
import { BaseApiResponse } from '@/types/api/api-general'; import { BaseApiResponse } from '@/types/api/api-general';
import { Dashboard } from '@/types/api/dashboard/dashboard'; import { Dashboard } from '@/types/api/dashboard/dashboard';
import { getDummySingle } from '@/dummy/dashboard/dashboard.production.dummy'; import { httpClientFetcher } from '@/services/http/client';
class DashboardService extends BaseApiService<Dashboard, unknown, unknown> { class DashboardService extends BaseApiService<Dashboard, unknown, unknown> {
constructor(basePath: string) { constructor(basePath: string) {
@@ -12,19 +12,14 @@ class DashboardService extends BaseApiService<Dashboard, unknown, unknown> {
* Fetch dashboard production data * Fetch dashboard production data
* @param endpoint - The endpoint URL with query parameters * @param endpoint - The endpoint URL with query parameters
* @returns Promise with BaseApiResponse containing DashboardProduction * @returns Promise with BaseApiResponse containing DashboardProduction
*
* Note: Currently using dummy data. When real API is ready,
* uncomment the line below and remove getDummySingle() call:
* return await this.customRequest<BaseApiResponse<Dashboard>>(endpoint);
*/ */
async getDashboardProductionFetcher( async getDashboardProductionFetcher(
endpoint: string endpoint: string
): Promise<BaseApiResponse<Dashboard>> { ): Promise<BaseApiResponse<Dashboard> | undefined> {
// For now, we're using dummy data regardless of the endpoint return await httpClientFetcher<BaseApiResponse<Dashboard>>(
// The endpoint parameter is kept for future API integration `${endpoint ? endpoint : this.basePath}`
console.log('Fetching dashboard data with endpoint:', endpoint); );
return await getDummySingle();
} }
} }
export const DashboardApi = new DashboardService('/dashboard'); export const DashboardApi = new DashboardService('/dashboards');
+1
View File
@@ -47,6 +47,7 @@ export interface DashboardFilter {
end_date: string; end_date: string;
analysis_mode: 'OVERVIEW' | 'COMPARISON'; analysis_mode: 'OVERVIEW' | 'COMPARISON';
location_ids: number[]; location_ids: number[];
comparison_type?: string | undefined;
flock_ids: number[]; flock_ids: number[];
kandang_ids: number[]; kandang_ids: number[];
} }