From c898154b488480cda868a30ad3c2ba8bda32e652 Mon Sep 17 00:00:00 2001 From: ValdiANS Date: Thu, 9 Apr 2026 14:14:50 +0700 Subject: [PATCH 1/3] feat: add export button --- .../production/recording/RecordingTable.tsx | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/src/components/pages/production/recording/RecordingTable.tsx b/src/components/pages/production/recording/RecordingTable.tsx index cea30502..8104d162 100644 --- a/src/components/pages/production/recording/RecordingTable.tsx +++ b/src/components/pages/production/recording/RecordingTable.tsx @@ -48,6 +48,7 @@ import { useUiStore } from '@/stores/ui/ui.store'; import { usePathname } from 'next/navigation'; import { Color } from '@/types/theme'; import ButtonFilter from '@/components/helper/ButtonFilter'; +import Dropdown from '@/components/Dropdown'; // ===== STATUS BADGE UTILITIES ===== const statusTextMap: Record = { @@ -352,6 +353,9 @@ const RecordingTable = () => { const [isRejectLoading, setIsRejectLoading] = useState(false); const [, setApprovalNotes] = useState(''); + const [isLoadingExportingToExcel, setIsLoadingExportingToExcel] = + useState(false); + const singleDeleteModal = useModal(); const approveModal = useModal(); const rejectModal = useModal(); @@ -686,6 +690,14 @@ const RecordingTable = () => { }); }, [selectedRowIds, recordings, isRecordingApproved]); + const exportToExcelHandler = async () => { + setIsLoadingExportingToExcel(true); + + await RecordingApi.exportToExcel(getTableFilterQueryString()); + + setIsLoadingExportingToExcel(false); + }; + useEffect(() => { if (isResponseSuccess(recordings) && recordings.data) { const newSelection: Record = {}; @@ -1313,6 +1325,50 @@ const RecordingTable = () => { onClick={handleFilterModalOpen} className='px-3 py-2.5' /> + + + + Export +
+ +
+ + } + className={{ + content: + 'mt-1 rounded-xl border border-base-content/5 shadow-sm overflow-hidden', + }} + > + +
From e50f4dbddba0fcc1a70b79ab8ea532d33f167769 Mon Sep 17 00:00:00 2001 From: ValdiANS Date: Thu, 9 Apr 2026 14:15:12 +0700 Subject: [PATCH 2/3] feat: add exportToExcel method to RecordingService --- src/services/api/production.ts | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/services/api/production.ts b/src/services/api/production.ts index d481081d..1f2a0373 100644 --- a/src/services/api/production.ts +++ b/src/services/api/production.ts @@ -12,6 +12,8 @@ import { NextDayRecording, } from '@/types/api/production/recording'; import { ProjectFlockKandang } from '@/types/api/production/project-flock-kandang'; +import { httpClient } from '@/services/http/client'; +import { formatDate } from '@/lib/helper'; export const ProjectFlockKandangApi = new BaseApiService< ProjectFlockKandang, @@ -88,6 +90,30 @@ export class RecordingService extends BaseApiService< } ); } + + async exportToExcel(initialQueryString: string) { + const params = new URLSearchParams(initialQueryString); + + params.set('export', 'excel'); + + const queryString = `?${params.toString()}`; + + const res = await httpClient(`${this.basePath}${queryString}`, { + method: 'GET', + responseType: 'blob', + }); + + const url = window.URL.createObjectURL(new Blob([res])); + const link = document.createElement('a'); + link.href = url; + + const fileName = `recording-${formatDate(Date.now(), 'DD-MM-YYYY')}.xlsx`; + link.setAttribute('download', fileName); + + document.body.appendChild(link); + link.click(); + link.remove(); + } } export const RecordingApi = new RecordingService('/production/recordings'); From 62d250109b7ca451b3f6a53178b6e4a03cf30d7e Mon Sep 17 00:00:00 2001 From: ValdiANS Date: Thu, 9 Apr 2026 14:15:29 +0700 Subject: [PATCH 3/3] feat: add responseType to axios config --- src/services/http/base.ts | 7 +++++++ src/services/http/client.ts | 1 + 2 files changed, 8 insertions(+) diff --git a/src/services/http/base.ts b/src/services/http/base.ts index 83bb5ee6..267e7622 100644 --- a/src/services/http/base.ts +++ b/src/services/http/base.ts @@ -9,6 +9,13 @@ export type RequestOptions = { auth?: AuthMode; // 'cookie' | 'bearer' | 'none' token?: string; // required if auth === 'bearer' timeoutMs?: number; + responseType?: + | 'arraybuffer' + | 'blob' + | 'document' + | 'json' + | 'text' + | 'stream'; }; export class HttpError extends Error { diff --git a/src/services/http/client.ts b/src/services/http/client.ts index 42e71978..c70a82ea 100644 --- a/src/services/http/client.ts +++ b/src/services/http/client.ts @@ -40,6 +40,7 @@ export async function httpClient( data: opts.body, timeout: opts.timeoutMs ?? 10_000, withCredentials: isCookieAuth && !isBearerAuth, + responseType: opts.responseType, headers: { ...(isFormData ? {} : { 'Content-Type': 'application/json' }), ...(opts.headers ?? {}),