Merge branch 'development' into 'production'

Development

See merge request mbugroup/lti-web-client!378
This commit is contained in:
Adnan Zahir
2026-04-08 13:39:17 +07:00
3 changed files with 63 additions and 73 deletions
@@ -68,7 +68,6 @@ const DashboardProduction = () => {
const [analysisMode, setAnalysisMode] = useState<'OVERVIEW' | 'COMPARISON'>( const [analysisMode, setAnalysisMode] = useState<'OVERVIEW' | 'COMPARISON'>(
(filterValues.analysisMode as 'OVERVIEW' | 'COMPARISON') || 'OVERVIEW' (filterValues.analysisMode as 'OVERVIEW' | 'COMPARISON') || 'OVERVIEW'
); );
const [endpointUrl, setEndpointUrl] = useState('/dashboards');
const [selectedLocationIds, setSelectedLocationIds] = useState<number[]>( const [selectedLocationIds, setSelectedLocationIds] = useState<number[]>(
normalizeToArray(filterValues.location) normalizeToArray(filterValues.location)
); );
@@ -80,9 +79,29 @@ const DashboardProduction = () => {
const { const {
data: dashboardProductionResponse, data: dashboardProductionResponse,
isLoading: isLoadingDashboardProductionData, isLoading: isLoadingDashboardProductionData,
mutate: refreshDashboardProductionData, } = useSWR(
} = useSWR(endpointUrl, () => [
DashboardApi.getDashboardProductionFetcher(endpointUrl) 'dashboard-production',
filterValues.startDate ?? '',
filterValues.endDate ?? '',
filterValues.analysisMode ?? 'OVERVIEW',
normalizeToArray(filterValues.location).toString(),
normalizeToArray(filterValues.flock).toString(),
normalizeToArray(filterValues.kandang).toString(),
filterValues.comparisonType ?? '',
],
() =>
DashboardApi.getDashboardProductionFetcher({
start_date: filterValues.startDate || '',
end_date: filterValues.endDate || '',
analysis_mode:
(filterValues.analysisMode as 'OVERVIEW' | 'COMPARISON') ||
'OVERVIEW',
location_ids: normalizeToArray(filterValues.location),
flock_ids: normalizeToArray(filterValues.flock),
kandang_ids: normalizeToArray(filterValues.kandang),
comparison_type: filterValues.comparisonType || '',
})
); );
const dashboardProductionData = isResponseSuccess(dashboardProductionResponse) const dashboardProductionData = isResponseSuccess(dashboardProductionResponse)
@@ -135,18 +154,8 @@ const DashboardProduction = () => {
enableReinitialize: true, enableReinitialize: true,
validationSchema: getDashboardFilterSchema(analysisMode), validationSchema: getDashboardFilterSchema(analysisMode),
onSubmit: (values) => { onSubmit: (values) => {
// Save filter values to store
setFilterValues(values); setFilterValues(values);
filterModal.closeModal();
handleApplyFilter({
start_date: values.startDate || '',
end_date: values.endDate || '',
analysis_mode: values.analysisMode as 'OVERVIEW' | 'COMPARISON',
location_ids: normalizeToArray(values.location),
flock_ids: normalizeToArray(values.flock),
kandang_ids: normalizeToArray(values.kandang),
comparison_type: values.comparisonType,
});
}, },
}); });
@@ -156,48 +165,9 @@ const DashboardProduction = () => {
resetForm(); resetForm();
resetFilterValues(); // Clear stored filter values resetFilterValues(); // Clear stored filter values
setAnalysisMode('OVERVIEW'); setAnalysisMode('OVERVIEW');
setEndpointUrl('/dashboards');
setSelectedLocationIds([]); setSelectedLocationIds([]);
}, [resetForm, resetFilterValues]); }, [resetForm, resetFilterValues]);
const handleApplyFilter = useCallback(
(values: DashboardFilter) => {
// Build query params object, only include non-empty values
const params: Record<string, string> = {};
if (values.start_date) params.start_date = values.start_date;
if (values.end_date) params.end_date = values.end_date;
if (values.analysis_mode) params.analysis_mode = values.analysis_mode;
if (values.location_ids.length > 0)
params.location_ids = values.location_ids.toString();
if (values.flock_ids.length > 0)
params.flock_ids = values.flock_ids.toString();
if (values.kandang_ids.length > 0)
params.kandang_ids = values.kandang_ids.toString();
if (values.comparison_type)
params.comparison_type = values.comparison_type;
setEndpointUrl(`/dashboards?${new URLSearchParams(params).toString()}`);
filterModal.closeModal();
refreshDashboardProductionData();
},
[filterModal, refreshDashboardProductionData]
);
// ===== Load filter from store on mount =====
useEffect(() => {
if (!filterValues) return;
handleApplyFilter({
start_date: filterValues.startDate,
end_date: filterValues.endDate,
analysis_mode: filterValues.analysisMode as 'OVERVIEW' | 'COMPARISON',
location_ids: normalizeToArray(filterValues.location),
flock_ids: normalizeToArray(filterValues.flock),
kandang_ids: normalizeToArray(filterValues.kandang),
comparison_type: filterValues.comparisonType,
});
}, [filterValues, handleApplyFilter]);
// ===== Formik Error List ===== // ===== Formik Error List =====
const { formErrorList, close, handleFormSubmit } = useFormikErrorList(formik); const { formErrorList, close, handleFormSubmit } = useFormikErrorList(formik);
@@ -268,14 +238,6 @@ const DashboardProduction = () => {
}; };
}, [clearNavbarActions]); }, [clearNavbarActions]);
if (isLoadingDashboardProductionData) {
return (
<div className='w-full min-h-screen flex items-center justify-center'>
<span className='loading loading-spinner loading-xl'></span>
</div>
);
}
return ( return (
<> <>
<section className='w-full p-3 space-y-3'> <section className='w-full p-3 space-y-3'>
@@ -327,9 +289,15 @@ const DashboardProduction = () => {
</div> </div>
{/* Dashboard Stats */} {/* Dashboard Stats */}
<div> <div>
<DashboardStats {isLoadingDashboardProductionData ? (
data={dashboardProductionData?.statistics_data ?? []} <div className='w-full min-h-screen flex items-center justify-center'>
/> <span className='loading loading-spinner loading-xl'></span>
</div>
) : (
<DashboardStats
data={dashboardProductionData?.statistics_data ?? []}
/>
)}
</div> </div>
{/* Use DashboardLineChart component or skeleton */} {/* Use DashboardLineChart component or skeleton */}
@@ -1,6 +1,7 @@
'use client'; 'use client';
import { useState } from 'react'; import { useState } from 'react';
import moment from 'moment';
import { import {
Card, Card,
CardContent, CardContent,
@@ -59,10 +60,17 @@ const CATEGORY_LABELS: { [key: string]: string } = {
produksi_close: 'Produksi Close', produksi_close: 'Produksi Close',
}; };
const getThisMonthRange = () => ({
dateFrom: moment().startOf('month').format('YYYY-MM-DD'),
dateTo: moment().endOf('month').format('YYYY-MM-DD'),
});
export function Dashboard() { export function Dashboard() {
const defaultDateRange = getThisMonthRange();
// Filters // Filters
const [dateFrom, setDateFrom] = useState(''); const [dateFrom, setDateFrom] = useState(defaultDateRange.dateFrom);
const [dateTo, setDateTo] = useState(''); const [dateTo, setDateTo] = useState(defaultDateRange.dateTo);
const [kandangFilter, setKandangFilter] = useState('ALL'); const [kandangFilter, setKandangFilter] = useState('ALL');
const [categoryFilter, setCategoryFilter] = useState('ALL'); const [categoryFilter, setCategoryFilter] = useState('ALL');
+20 -6
View File
@@ -1,7 +1,6 @@
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, DashboardFilter } from '@/types/api/dashboard/dashboard';
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) {
@@ -14,11 +13,26 @@ class DashboardService extends BaseApiService<Dashboard, unknown, unknown> {
* @returns Promise with BaseApiResponse containing DashboardProduction * @returns Promise with BaseApiResponse containing DashboardProduction
*/ */
async getDashboardProductionFetcher( async getDashboardProductionFetcher(
endpoint: string params: DashboardFilter
): Promise<BaseApiResponse<Dashboard> | undefined> { ): Promise<BaseApiResponse<Dashboard> | undefined> {
return await httpClientFetcher<BaseApiResponse<Dashboard>>( return await this.customRequest<BaseApiResponse<Dashboard>>('', {
`${endpoint ? endpoint : this.basePath}` method: 'GET',
); params: {
start_date: params.start_date || undefined,
end_date: params.end_date || undefined,
analysis_mode: params.analysis_mode || undefined,
location_ids: params.location_ids.length
? params.location_ids.toString()
: undefined,
flock_ids: params.flock_ids.length
? params.flock_ids.toString()
: undefined,
kandang_ids: params.kandang_ids.length
? params.kandang_ids.toString()
: undefined,
comparison_type: params.comparison_type || undefined,
},
});
} }
} }