Fix: Data inconsistency pada transisi tahun/bulan dan setup API lokal untuk testing
- Fix deteksi transisi bulan untuk semua bulan (tidak hanya 1 Januari) - Perbaikan validasi data dengan threshold 20% untuk transisi bulan/tahun - Auto-reset chart jika data hourly tidak valid - Setup force local mode untuk testing API lokal - Perbaikan normalisasi dan validasi tanggal - Enhanced logging untuk debugging transisi
This commit is contained in:
@@ -67,6 +67,19 @@ async function apiRequest(path, options = {}) {
|
||||
json = { raw: text };
|
||||
}
|
||||
|
||||
// Log response body untuk debug (khusus untuk summary endpoint)
|
||||
if (url.includes('/dashboard/summary') || url.includes('/summary/hourly') || url.includes('/by-category')) {
|
||||
console.log('[API] Response body for', url, ':', {
|
||||
textLength: text.length,
|
||||
jsonKeys: Object.keys(json || {}),
|
||||
jsonPreview: JSON.stringify(json).substring(0, 500),
|
||||
hasSuccess: json && 'success' in json,
|
||||
hasData: json && 'data' in json,
|
||||
totalCount: json?.total_count ?? json?.data?.total_count,
|
||||
totalAmount: json?.total_amount ?? json?.data?.total_amount
|
||||
});
|
||||
}
|
||||
|
||||
if (!res.ok) {
|
||||
const msg = json.message || json.error || `HTTP ${res.status}`;
|
||||
throw new Error(msg);
|
||||
@@ -103,7 +116,48 @@ function buildQuery(params = {}) {
|
||||
const search = new URLSearchParams();
|
||||
Object.entries(params).forEach(([key, value]) => {
|
||||
if (value !== undefined && value !== null && value !== '') {
|
||||
search.append(key, value);
|
||||
// Pastikan value adalah string dan sudah di-encode dengan benar
|
||||
let stringValue = String(value).trim();
|
||||
|
||||
// Validasi khusus untuk parameter date: harus format YYYY-MM-DD
|
||||
if (key === 'date' || key === 'start_date' || key === 'end_date') {
|
||||
// Validasi format tanggal
|
||||
if (!/^\d{4}-\d{2}-\d{2}$/.test(stringValue)) {
|
||||
console.error('[API] buildQuery - Invalid date format:', stringValue);
|
||||
// Coba normalisasi jika mungkin
|
||||
const dateObj = new Date(stringValue);
|
||||
if (!isNaN(dateObj.getTime())) {
|
||||
const year = dateObj.getFullYear();
|
||||
const month = String(dateObj.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(dateObj.getDate()).padStart(2, '0');
|
||||
stringValue = `${year}-${month}-${day}`;
|
||||
console.warn('[API] buildQuery - Date normalized to:', stringValue);
|
||||
} else {
|
||||
console.error('[API] buildQuery - Cannot normalize date, skipping:', stringValue);
|
||||
return; // Skip parameter ini jika tidak valid
|
||||
}
|
||||
}
|
||||
|
||||
// Validasi bahwa tanggal valid (tidak ada 2025-13-45)
|
||||
const [year, month, day] = stringValue.split('-').map(Number);
|
||||
const dateObj = new Date(year, month - 1, day);
|
||||
if (dateObj.getFullYear() !== year || dateObj.getMonth() !== month - 1 || dateObj.getDate() !== day) {
|
||||
console.error('[API] buildQuery - Invalid date values:', { year, month, day });
|
||||
return; // Skip parameter ini jika tidak valid
|
||||
}
|
||||
|
||||
console.log('[API] buildQuery - Date param validated:', {
|
||||
key,
|
||||
originalValue: value,
|
||||
stringValue: stringValue,
|
||||
encoded: stringValue, // URLSearchParams akan encode otomatis
|
||||
year: year,
|
||||
month: month,
|
||||
day: day
|
||||
});
|
||||
}
|
||||
|
||||
search.append(key, stringValue);
|
||||
}
|
||||
});
|
||||
const qs = search.toString();
|
||||
@@ -139,7 +193,9 @@ export async function apiGetSummary({ date, locationCode, gateCode }) {
|
||||
location_code: locationCode,
|
||||
gate_code: gateCode
|
||||
});
|
||||
return apiRequest(`/retribusi/v1/dashboard/summary${qs}`);
|
||||
const url = `/retribusi/v1/dashboard/summary${qs}`;
|
||||
console.log('[API] apiGetSummary - URL:', url, 'Params:', { date, locationCode, gateCode });
|
||||
return apiRequest(url);
|
||||
}
|
||||
|
||||
export async function apiGetDaily({ startDate, endDate, locationCode }) {
|
||||
@@ -157,7 +213,9 @@ export async function apiGetByCategory({ date, locationCode, gateCode }) {
|
||||
location_code: locationCode,
|
||||
gate_code: gateCode
|
||||
});
|
||||
return apiRequest(`/retribusi/v1/dashboard/by-category${qs}`);
|
||||
const url = `/retribusi/v1/dashboard/by-category${qs}`;
|
||||
console.log('[API] apiGetByCategory - URL:', url, 'Params:', { date, locationCode, gateCode });
|
||||
return apiRequest(url);
|
||||
}
|
||||
|
||||
// Ringkasan global harian (daily_summary)
|
||||
@@ -169,7 +227,9 @@ export async function apiGetSummaryDaily(params = {}) {
|
||||
// Ringkasan per jam (hourly_summary)
|
||||
export async function apiGetSummaryHourly(params = {}) {
|
||||
const qs = buildQuery(params);
|
||||
return apiRequest(`/retribusi/v1/summary/hourly${qs}`);
|
||||
const url = `/retribusi/v1/summary/hourly${qs}`;
|
||||
console.log('[API] apiGetSummaryHourly - URL:', url, 'Params:', params);
|
||||
return apiRequest(url);
|
||||
}
|
||||
|
||||
// Snapshot realtime (untuk panel live / TV wall)
|
||||
@@ -202,3 +262,55 @@ export async function apiGetEvents(params = {}) {
|
||||
// Catatan: realtime SSE /retribusi/v1/realtime/stream akan diakses langsung via EventSource,
|
||||
// bukan lewat fetch/apiRequest karena menggunakan Server-Sent Events (SSE).
|
||||
|
||||
// Test function untuk debug - bandingkan URL yang dihasilkan untuk tanggal berbeda
|
||||
// Bisa dipanggil dari browser console: window.testDateUrls('2025-12-31', '2026-01-01')
|
||||
if (typeof window !== 'undefined') {
|
||||
window.testDateUrls = function(date1, date2) {
|
||||
console.log('=== TEST: Membandingkan URL untuk tanggal berbeda ===');
|
||||
|
||||
const testParams = {
|
||||
date: date1 || '2025-12-31',
|
||||
locationCode: '',
|
||||
gateCode: ''
|
||||
};
|
||||
|
||||
const testParams2 = {
|
||||
date: date2 || '2026-01-01',
|
||||
locationCode: '',
|
||||
gateCode: ''
|
||||
};
|
||||
|
||||
console.log('\n--- Tanggal 1:', testParams.date, '---');
|
||||
const qs1 = buildQuery(testParams);
|
||||
console.log('Query string:', qs1);
|
||||
console.log('Full URL:', `${API_CONFIG.BASE_URL}/retribusi/v1/dashboard/summary${qs1}`);
|
||||
|
||||
console.log('\n--- Tanggal 2:', testParams2.date, '---');
|
||||
const qs2 = buildQuery(testParams2);
|
||||
console.log('Query string:', qs2);
|
||||
console.log('Full URL:', `${API_CONFIG.BASE_URL}/retribusi/v1/dashboard/summary${qs2}`);
|
||||
|
||||
console.log('\n--- Perbandingan ---');
|
||||
console.log('Query string sama?', qs1 === qs2);
|
||||
console.log('Date param sama?', testParams.date === testParams2.date);
|
||||
console.log('Date length sama?', testParams.date.length === testParams2.date.length);
|
||||
|
||||
// Test URLSearchParams parsing
|
||||
const params1 = new URLSearchParams(qs1.substring(1));
|
||||
const params2 = new URLSearchParams(qs2.substring(1));
|
||||
console.log('Parsed date 1:', params1.get('date'));
|
||||
console.log('Parsed date 2:', params2.get('date'));
|
||||
console.log('Parsed dates sama?', params1.get('date') === params2.get('date'));
|
||||
|
||||
return {
|
||||
date1: testParams.date,
|
||||
date2: testParams2.date,
|
||||
url1: `${API_CONFIG.BASE_URL}/retribusi/v1/dashboard/summary${qs1}`,
|
||||
url2: `${API_CONFIG.BASE_URL}/retribusi/v1/dashboard/summary${qs2}`,
|
||||
qs1,
|
||||
qs2,
|
||||
areEqual: qs1 === qs2
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user