diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index e02ea8ee..e80a7e02 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -7,7 +7,7 @@ stages:
# ==========================================================
default:
tags:
- - self-hosted
+ - server-development-biznet
interruptible: true
# ==========================================================
diff --git a/src/components/helper/RequireAuth.tsx b/src/components/helper/RequireAuth.tsx
index aa7f81b2..a4c9f5e0 100644
--- a/src/components/helper/RequireAuth.tsx
+++ b/src/components/helper/RequireAuth.tsx
@@ -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 (
Authentication Failed
@@ -86,10 +94,7 @@ const RequireAuth = ({ children }: RequireAuthProps) => {
Please try refreshing the page or contact support if the problem
persists.
- window.location.reload()}
- >
+ redirectToSSO()}>
Retry
diff --git a/src/components/pages/report/production-result/ProductionResultContent.tsx b/src/components/pages/report/production-result/ProductionResultContent.tsx
index 6fc8f7ea..ae6f744b 100644
--- a/src/components/pages/report/production-result/ProductionResultContent.tsx
+++ b/src/components/pages/report/production-result/ProductionResultContent.tsx
@@ -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={
-
+
Export{' '}
diff --git a/src/config/route-permission.ts b/src/config/route-permission.ts
index 2f3e36d3..7c256795 100644
--- a/src/config/route-permission.ts
+++ b/src/config/route-permission.ts
@@ -99,10 +99,7 @@ export const ROUTE_PERMISSIONS: Record = {
'/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'],
diff --git a/src/services/api/report/production-result.ts b/src/services/api/report/production-result.ts
index 98997e9b..251e3eb4 100644
--- a/src/services/api/report/production-result.ts
+++ b/src/services/api/report/production-result.ts
@@ -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 = {
- 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> {
- // return await httpClientFetcher>(
- // endpoint
- // );
+ return await httpClientFetcher>(
+ 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
+ >(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[]
+ > = {};
+
+ 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'
+);