Compare commits

...

6 Commits

Author SHA1 Message Date
Rivaldi A N S 82dca3b57e Merge branch 'feat/debt-supplier-general-export' into 'development'
[FEAT/FE] Debt Supplier General Export

See merge request mbugroup/lti-web-client!486
2026-05-19 10:33:48 +00:00
ValdiANS 6668c7b1f9 feat: update .gitignore 2026-05-19 16:07:08 +07:00
ValdiANS ce4f50c92a feat: create Export to Excel - General button 2026-05-19 16:06:54 +07:00
ValdiANS 146192a5b3 feat: create exportToExcelGeneral method 2026-05-19 16:06:41 +07:00
Rivaldi A N S 27c24e7c82 Merge branch 'fix/daily-checklist' into 'development'
[FIX/FE] Daily Checklist

See merge request mbugroup/lti-web-client!485
2026-05-19 07:47:51 +00:00
ValdiANS a99a399f09 fix: show kandang label even if its not loaded yet in kandang options 2026-05-19 14:44:12 +07:00
4 changed files with 97 additions and 5 deletions
+3
View File
@@ -48,3 +48,6 @@ next-env.d.ts
# rtk # rtk
rtk.exe rtk.exe
# local specs
/local-specs
@@ -77,7 +77,10 @@ const DebtSupplierTab = ({ tabId }: DebtSupplierTabProps) => {
// ===== STATE MANAGEMENT ===== // ===== STATE MANAGEMENT =====
const [isPdfExportLoading, setIsPdfExportLoading] = useState(false); const [isPdfExportLoading, setIsPdfExportLoading] = useState(false);
const [isExcelExportLoading, setIsExcelExportLoading] = useState(false); const [isExcelExportLoading, setIsExcelExportLoading] = useState(false);
const isAnyExportLoading = isPdfExportLoading || isExcelExportLoading; const [isExcelGeneralExportLoading, setIsExcelGeneralExportLoading] =
useState(false);
const isAnyExportLoading =
isPdfExportLoading || isExcelExportLoading || isExcelGeneralExportLoading;
// ===== PAGINATION STATE ===== // ===== PAGINATION STATE =====
const [currentPage, setCurrentPage] = useState(1); const [currentPage, setCurrentPage] = useState(1);
@@ -308,6 +311,23 @@ const DebtSupplierTab = ({ tabId }: DebtSupplierTabProps) => {
formik.values.endDate, formik.values.endDate,
]); ]);
const handleExportExcelGeneral = useCallback(async () => {
setIsExcelGeneralExportLoading(true);
try {
await DebtSupplierApi.exportToExcelGeneral(
filterParams.supplier_ids,
filterParams.filter_by,
filterParams.start_date,
filterParams.end_date
);
toast.success('Excel General berhasil dibuat dan diunduh.');
} catch {
toast.error('Gagal membuat Excel General. Silakan coba lagi.');
} finally {
setIsExcelGeneralExportLoading(false);
}
}, [filterParams]);
// ===== TAB ACTIONS COMPONENT ===== // ===== TAB ACTIONS COMPONENT =====
const TabActions = useMemo(() => { const TabActions = useMemo(() => {
return function TabActionsComponent() { return function TabActionsComponent() {
@@ -370,7 +390,17 @@ const DebtSupplierTab = ({ tabId }: DebtSupplierTabProps) => {
className='w-full p-3 justify-start text-sm text-base-content/50 font-semibold text-nowrap' 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} /> <Icon icon='heroicons:table-cells' width={20} height={20} />
Export to Excel Export to Excel - Supplier Per Sheet
</Button>
<Button
variant='ghost'
color='none'
onClick={handleExportExcelGeneral}
isLoading={isExcelGeneralExportLoading}
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 - General
</Button> </Button>
<Button <Button
variant='ghost' variant='ghost'
@@ -400,8 +430,10 @@ const DebtSupplierTab = ({ tabId }: DebtSupplierTabProps) => {
filterParams, filterParams,
isAnyExportLoading, isAnyExportLoading,
handleExportExcel, handleExportExcel,
handleExportExcelGeneral,
handleExportPdf, handleExportPdf,
isExcelExportLoading, isExcelExportLoading,
isExcelGeneralExportLoading,
isPdfExportLoading, isPdfExportLoading,
]); ]);
@@ -184,6 +184,11 @@ export function DailyChecklistContent() {
const [emptyKandangEndDateError, setEmptyKandangEndDateError] = const [emptyKandangEndDateError, setEmptyKandangEndDateError] =
useState<string>(''); useState<string>('');
const [preloadedKandang, setPreloadedKandang] = useState<{
id: string;
name: string;
} | null>(null);
const [existingDocuments, setExistingDocuments] = useState<Document[]>([]); const [existingDocuments, setExistingDocuments] = useState<Document[]>([]);
const [documents, setDocuments] = useState<File[]>([]); const [documents, setDocuments] = useState<File[]>([]);
const [deletedDocumentIds, setDeletedDocumentIds] = useState<number[]>([]); const [deletedDocumentIds, setDeletedDocumentIds] = useState<number[]>([]);
@@ -228,7 +233,11 @@ export function DailyChecklistContent() {
const rawDate = data.date || ''; const rawDate = data.date || '';
setDate(rawDate.length > 10 ? rawDate.slice(0, 10) : rawDate); setDate(rawDate.length > 10 ? rawDate.slice(0, 10) : rawDate);
skipKandangClearRef.current = true; skipKandangClearRef.current = true;
setKandangId(String(data.kandang?.id || '')); const loadedKandangId = String(data.kandang?.id || '');
setKandangId(loadedKandangId);
if (data.kandang?.name) {
setPreloadedKandang({ id: loadedKandangId, name: data.kandang.name });
}
const isEmptyKandang = const isEmptyKandang =
!!data.empty_kandang || data.category === 'empty_kandang'; !!data.empty_kandang || data.category === 'empty_kandang';
@@ -1162,9 +1171,17 @@ export function DailyChecklistContent() {
<SelectValue placeholder='Pilih kandang' /> <SelectValue placeholder='Pilih kandang' />
</SelectTrigger> </SelectTrigger>
<SelectContent onScroll={handleKandangScroll}> <SelectContent onScroll={handleKandangScroll}>
{kandangOptions.map((kandang) => ( {preloadedKandang &&
!kandangOptions.some(
(k) => String(k.value) === preloadedKandang.id
) && (
<SelectItem value={preloadedKandang.id}>
{preloadedKandang.name}
</SelectItem>
)}
{kandangOptions.map((kandang, kandangIdx) => (
<SelectItem <SelectItem
key={kandang.value} key={`${kandang.value}-${kandangIdx}`}
value={String(kandang.value)} value={String(kandang.value)}
> >
{kandang.label} {kandang.label}
+40
View File
@@ -1,4 +1,6 @@
import { BaseApiService } from '@/services/api/base'; import { BaseApiService } from '@/services/api/base';
import { httpClient } from '@/services/http/client';
import { formatDate } from '@/lib/helper';
import { BaseApiResponse } from '@/types/api/api-general'; import { BaseApiResponse } from '@/types/api/api-general';
import { DebtSupplier } from '@/types/api/report/debt-supplier'; import { DebtSupplier } from '@/types/api/report/debt-supplier';
@@ -11,6 +13,44 @@ export class DebtSupplierApiService extends BaseApiService<
super(basePath); super(basePath);
} }
async exportToExcelGeneral(
supplier_ids?: string,
filter_by?: string,
start_date?: string,
end_date?: string
) {
const params = new URLSearchParams();
if (supplier_ids) params.set('supplier_ids', supplier_ids);
if (filter_by) params.set('filter_by', filter_by);
if (start_date) params.set('start_date', start_date);
if (end_date) params.set('end_date', end_date);
params.set('export', 'excel-all');
params.set('page', '1');
params.set('limit', '99999999999');
const queryString = `?${params.toString()}`;
const res = await httpClient<Blob>(
`${this.basePath.replace(/\/$/, '')}/debt-supplier${queryString}`,
{
method: 'GET',
responseType: 'blob',
}
);
const url = window.URL.createObjectURL(new Blob([res]));
const link = document.createElement('a');
link.href = url;
const fileName = `laporan-hutang-supplier-general-${formatDate(Date.now(), 'DD-MM-YYYY')}.xlsx`;
link.setAttribute('download', fileName);
document.body.appendChild(link);
link.click();
link.remove();
}
async getDebtSupplierReport( async getDebtSupplierReport(
supplier_ids?: string, supplier_ids?: string,
filter_by?: string, filter_by?: string,