mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 13:32:00 +00:00
Merge branch 'feat/recording-export' into 'development'
[FEAT/FE] Recording See merge request mbugroup/lti-web-client!381
This commit is contained in:
@@ -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<string, string> = {
|
||||
@@ -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<string, boolean> = {};
|
||||
@@ -1313,6 +1325,50 @@ const RecordingTable = () => {
|
||||
onClick={handleFilterModalOpen}
|
||||
className='px-3 py-2.5'
|
||||
/>
|
||||
|
||||
<Dropdown
|
||||
align='end'
|
||||
direction='bottom'
|
||||
trigger={
|
||||
<Button
|
||||
variant='outline'
|
||||
color='none'
|
||||
className={cn(
|
||||
'px-3 py-2.5 rounded-lg font-semibold text-sm gap-1.5',
|
||||
'text-sm text-base-content/50 border border-base-content/10 shadow-button-soft'
|
||||
)}
|
||||
>
|
||||
<Icon
|
||||
width={20}
|
||||
height={20}
|
||||
icon='heroicons:cloud-arrow-down'
|
||||
/>
|
||||
Export
|
||||
<div className='w-6.5 h-5 flex items-center justify-center border-l border-base-content/10'>
|
||||
<Icon
|
||||
width={14}
|
||||
height={14}
|
||||
icon='heroicons:chevron-down'
|
||||
/>
|
||||
</div>
|
||||
</Button>
|
||||
}
|
||||
className={{
|
||||
content:
|
||||
'mt-1 rounded-xl border border-base-content/5 shadow-sm overflow-hidden',
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
variant='ghost'
|
||||
color='none'
|
||||
onClick={exportToExcelHandler}
|
||||
isLoading={isLoadingExportingToExcel}
|
||||
className='w-full p-3 justify-start text-sm text-base-content/50 font-semibold text-nowrap'
|
||||
>
|
||||
<Icon icon='heroicons:table-cells' width={20} height={20} />
|
||||
Export to Excel
|
||||
</Button>
|
||||
</Dropdown>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -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<Blob>(`${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');
|
||||
|
||||
@@ -9,6 +9,13 @@ export type RequestOptions<B = unknown> = {
|
||||
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 {
|
||||
|
||||
@@ -40,6 +40,7 @@ export async function httpClient<T, B = unknown>(
|
||||
data: opts.body,
|
||||
timeout: opts.timeoutMs ?? 10_000,
|
||||
withCredentials: isCookieAuth && !isBearerAuth,
|
||||
responseType: opts.responseType,
|
||||
headers: {
|
||||
...(isFormData ? {} : { 'Content-Type': 'application/json' }),
|
||||
...(opts.headers ?? {}),
|
||||
|
||||
Reference in New Issue
Block a user