mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 13:32:00 +00:00
Merge branch 'development' into 'production'
Development See merge request mbugroup/lti-web-client!378
This commit is contained in:
@@ -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');
|
||||||
|
|
||||||
|
|||||||
@@ -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,
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user