fix(FE): resolve merge conflict

This commit is contained in:
randy-ar
2026-01-05 13:13:37 +07:00
6 changed files with 144 additions and 162 deletions
+13 -8
View File
@@ -29,8 +29,8 @@ const RequireAuth = ({ children }: RequireAuthProps) => {
>('/sso/userinfo', httpClientFetcher, {
shouldRetryOnError: false,
// refresh every 13 minutes
refreshInterval: 13 * 60 * 1000,
// refresh every 12 minutes
refreshInterval: 12 * 60 * 1000,
});
useEffect(() => {
@@ -61,12 +61,20 @@ const RequireAuth = ({ children }: RequireAuthProps) => {
async () => {
await AuthApi.refresh();
},
13 * 60 * 1000
12 * 60 * 1000
);
return () => clearInterval(interval);
}, []);
useEffect(() => {
const refreshUserSession = async () => {
await AuthApi.refresh();
};
refreshUserSession();
}, []);
if (
(isLoadingUserResponse && !userResponse && !userErrorResponse) ||
(!userResponse && !userErrorResponse)
@@ -78,7 +86,7 @@ const RequireAuth = ({ children }: RequireAuthProps) => {
);
}
if (userErrorResponse) {
if (!isLoadingUserResponse && userErrorResponse) {
return (
<div className='w-full h-screen flex flex-col justify-center items-center gap-4'>
<h2 className='text-2xl font-bold text-error'>Authentication Failed</h2>
@@ -86,10 +94,7 @@ const RequireAuth = ({ children }: RequireAuthProps) => {
Please try refreshing the page or contact support if the problem
persists.
</p>
<button
className='btn btn-primary'
onClick={() => window.location.reload()}
>
<button className='btn btn-primary' onClick={() => redirectToSSO()}>
Retry
</button>
</div>
@@ -24,6 +24,7 @@ import {
import { ProjectFlockKandang } from '@/types/api/production/project-flock-kandang';
import { isResponseError } from '@/lib/api-helper';
import Pagination from '@/components/Pagination';
import { ProductionResultReportApi } from '@/services/api/report/production-result';
const ProductionResultContent = () => {
const [projectFlockKandangs, setProjectFlockKandangs] = useState<
@@ -145,8 +146,11 @@ const ProductionResultContent = () => {
const exportToExcelHandler = async () => {
setIsLoadingExportingToExcel(true);
// TODO: Implement export functionality in API service first if needed
toast.error('Fitur export belum tersedia');
await ProductionResultReportApi.exportProductionResultToExcel(
projectFlockKandangs
);
setIsLoadingExportingToExcel(false);
};
@@ -319,7 +323,13 @@ const ProductionResultContent = () => {
align='end'
direction='bottom'
trigger={
<Button>
<Button
disabled={
!selectedArea ||
!selectedLocation ||
!selectedProjectFlock
}
>
Export{' '}
<Icon
icon='heroicons-outline:download'
@@ -352,7 +352,7 @@ const ProductionResultProjectFlockKandangTable = ({
productionResults?.data?.length === 0,
}),
headerColumnClassName:
'px-4 py-3 border-base-content/10 text-base-content/50',
'px-4 py-3 border-x border-base-content/10 text-base-content/50',
}}
/>
</div>
+1 -4
View File
@@ -99,10 +99,7 @@ export const ROUTE_PERMISSIONS: Record<string, string[]> = {
'/report/logistic-stock/': ['lti.repport.purchasesupplier.list'],
'/report/expense/': ['lti.repport.expense.list'],
'/report/marketing/': ['lti.repport.delivery.list'],
// TODO: change to real permission
// '/report/production-result/': ['lti.repport.production_result.list'],
'/report/production-result/': ['lti.repport.delivery.list'],
'/report/production-result/': ['lti.repport.production_result.list'],
// Inventory
'/inventory/adjustment/': ['lti.inventory.list'],
+115 -145
View File
@@ -1,145 +1,12 @@
import { sleep } from '@/lib/helper';
import * as XLSX from 'xlsx';
import toast from 'react-hot-toast';
import { formatDate } from '@/lib/helper';
import { isResponseSuccess } from '@/lib/api-helper';
import { BaseApiService } from '@/services/api/base';
import { httpClientFetcher } from '@/services/http/client';
import { httpClient, httpClientFetcher } from '@/services/http/client';
import { BaseApiResponse } from '@/types/api/api-general';
import { ProductionResult } from '@/types/api/report/production-result';
// TODO: delete this dummy data
const PRODUCTION_RESULT_DUMMY_DATA: BaseApiResponse<ProductionResult[]> = {
code: 200,
status: 'success',
message: 'Get Laporan Hasil Produksi successfully',
meta: {
page: 1,
limit: 1,
total_pages: 2,
total_results: 2,
},
data: [
{
created_user: {
id: 1,
id_user: 1001,
email: 'user@example.com',
name: 'John Doe',
},
project_flock: {
id: 1,
name: 'PROJECT',
category: 'LAYING',
kandang: {
id: 1,
name: 'Cikaum',
},
},
created_at: '2025-01-01T08:00:00Z',
updated_at: '2025-01-02T10:30:00Z',
woa: 25,
bw: 62.5,
std_bw: 60,
uniformity: 88,
std_uniformity: '90% up',
dep_kum: 3.2,
dep_std: 2.5,
butiran_utuh: 850,
butiran_putih: 50,
butiran_retak: 70,
butiran_pecah: 30,
butiran_jumlah: 1000,
total_butir: 1000,
kg_utuh: 52.3,
kg_putih: 3.1,
kg_retak: 4.2,
kg_pecah: 1.9,
kg_jumlah: 61.5,
total_kg: 61.5,
persen_utuh: 85,
persen_putih: 5,
persen_retak: 7,
persen_pecah: 3,
hd: 92,
hd_std: 90,
fi: 115,
fi_std: 667,
em: 85,
em_std: 83,
ew: 62,
ew_std: 60,
fcr: 2.1,
fcr_std: 2.0,
hh: 96,
hh_std: 95,
},
{
created_user: {
id: 1,
id_user: 1001,
email: 'user@example.com',
name: 'John Doe',
},
project_flock: {
id: 1,
name: 'PROJECT',
category: 'LAYING',
kandang: {
id: 1,
name: 'Cikaum',
},
},
created_at: '2025-01-01T08:00:00Z',
updated_at: '2025-01-02T10:30:00Z',
woa: 25,
bw: 62.5,
std_bw: 60,
uniformity: 88,
std_uniformity: '90% up',
dep_kum: 3.2,
dep_std: 2.5,
butiran_utuh: 850,
butiran_putih: 50,
butiran_retak: 70,
butiran_pecah: 30,
butiran_jumlah: 1000,
total_butir: 1000,
kg_utuh: 52.3,
kg_putih: 3.1,
kg_retak: 4.2,
kg_pecah: 1.9,
kg_jumlah: 61.5,
total_kg: 61.5,
persen_utuh: 85,
persen_putih: 5,
persen_retak: 7,
persen_pecah: 3,
hd: 92,
hd_std: 90,
fi: 115,
fi_std: 110,
em: 85,
em_std: 83,
ew: 62,
ew_std: 60,
fcr: 2.1,
fcr_std: 2.0,
hh: 96,
hh_std: 95,
},
],
};
import { BaseProjectFlockKandang } from '@/types/api/production/project-flock-kandang';
export class ProductionResultReportApiService extends BaseApiService<
ProductionResult,
@@ -153,14 +20,117 @@ export class ProductionResultReportApiService extends BaseApiService<
async getAllProductionResultFetcher(
endpoint: string
): Promise<BaseApiResponse<ProductionResult[]>> {
// return await httpClientFetcher<BaseApiResponse<ProductionResult[]>>(
// endpoint
// );
return await httpClientFetcher<BaseApiResponse<ProductionResult[]>>(
endpoint
);
}
await sleep(1000);
async exportProductionResultToExcel(
projectFlockKandangs: BaseProjectFlockKandang[] | null
) {
try {
const mappedProductionResults: {
projectFlockKandang: BaseProjectFlockKandang;
productionResult: ProductionResult[] | null;
}[] = [];
return PRODUCTION_RESULT_DUMMY_DATA;
projectFlockKandangs?.forEach(async (projectFlockKandang) => {
const getProductionResultPath = `${this.basePath}/${projectFlockKandang.id}?page=1&limit=99999999`;
const getProductionResultRes = await httpClient<
BaseApiResponse<ProductionResult[]>
>(getProductionResultPath);
mappedProductionResults.push({
projectFlockKandang,
productionResult: isResponseSuccess(getProductionResultRes)
? getProductionResultRes.data
: null,
});
});
const rows = mappedProductionResults;
if (!rows || rows.length === 0) {
toast.error('Tidak ada data untuk diexport.');
return;
}
// Group by Project Flock Kandang Name
const groupedData: Record<
string,
Record<string, string | number | undefined>[]
> = {};
rows.forEach((row) => {
const kandangName = row.projectFlockKandang.kandang.name || 'Unknown';
if (!groupedData[kandangName]) {
groupedData[kandangName] = [];
}
row.productionResult?.forEach((productionResult) => {
groupedData[kandangName].push({
woa: productionResult.woa,
bw: productionResult.bw,
std_bw: productionResult.std_bw,
uniformity: productionResult.uniformity,
std_uniformity: productionResult.std_uniformity,
dep_kum: productionResult.dep_kum,
dep_std: productionResult.dep_std,
butiran_utuh: productionResult.butiran_utuh,
butiran_putih: productionResult.butiran_putih,
butiran_retak: productionResult.butiran_retak,
butiran_pecah: productionResult.butiran_pecah,
butiran_jumlah: productionResult.butiran_jumlah,
total_butir: productionResult.total_butir,
kg_utuh: productionResult.kg_utuh,
kg_putih: productionResult.kg_putih,
kg_retak: productionResult.kg_retak,
kg_pecah: productionResult.kg_pecah,
kg_jumlah: productionResult.kg_jumlah,
total_kg: productionResult.total_kg,
persen_utuh: productionResult.persen_utuh,
persen_putih: productionResult.persen_putih,
persen_retak: productionResult.persen_retak,
persen_pecah: productionResult.persen_pecah,
hd: productionResult.hd,
hd_std: productionResult.hd_std,
fi: productionResult.fi,
fi_std: productionResult.fi_std,
em: productionResult.em,
em_std: productionResult.em_std,
ew: productionResult.ew,
ew_std: productionResult.ew_std,
fcr: productionResult.fcr,
fcr_std: productionResult.fcr_std,
hh: productionResult.hh,
hh_std: productionResult.hh_std,
project_flock_name: productionResult.project_flock.name,
project_flock_category: productionResult.project_flock.category,
kandang_name: productionResult.project_flock.kandang.name,
created_at: formatDate(productionResult.created_at, 'YYYY-MM-DD'),
updated_at: formatDate(productionResult.updated_at, 'YYYY-MM-DD'),
});
});
});
const wb = XLSX.utils.book_new();
Object.keys(groupedData).forEach((sheetName) => {
const ws = XLSX.utils.json_to_sheet(groupedData[sheetName]);
// Sheet names cannot exceed 31 chars
const safeSheetName = sheetName.substring(0, 31);
XLSX.utils.book_append_sheet(wb, ws, safeSheetName);
});
const productionResultExcelFileName = `laporan-hasil-produksi-${formatDate(Date.now(), 'YYYY-MM-DD')}-${rows[0].projectFlockKandang.project_flock.flock_name}.xlsx`;
XLSX.writeFile(wb, productionResultExcelFileName);
} catch (error) {
console.error(error);
toast.error('Gagal melakukan export laporan hasil produksi! Coba lagi.');
}
}
}
export const ProductionResultReportApi = new ProductionResultReportApiService();
export const ProductionResultReportApi = new ProductionResultReportApiService(
'/reports/production-result'
);