diff --git a/src/components/pages/inventory/product/detail/InventoryProductDetail.tsx b/src/components/pages/inventory/product/detail/InventoryProductDetail.tsx
index 39609b06..715a7a43 100644
--- a/src/components/pages/inventory/product/detail/InventoryProductDetail.tsx
+++ b/src/components/pages/inventory/product/detail/InventoryProductDetail.tsx
@@ -1,5 +1,6 @@
import Card from '@/components/Card';
import { FormHeader } from '@/components/helper/form/FormHeader';
+import RequirePermission from '@/components/helper/RequirePermission';
import StockLogTable from '@/components/pages/inventory/product/detail/StockLogTable';
import StockProductWarehouseTable from '@/components/pages/inventory/product/detail/StockProductWarehouseTable';
import { formatCurrency, formatNumber } from '@/lib/helper';
@@ -11,18 +12,6 @@ const InventoryProductDetail = ({
}: {
inventoryProduct?: InventoryProduct;
}) => {
- const stockLogs = useMemo(() => {
- return (
- inventoryProduct?.product_warehouses?.flatMap((warehouse) =>
- warehouse.stock_logs.map((log) => ({
- ...log,
- warehouse_name: warehouse.warehouse_name,
- warehouse_id: warehouse.warehouse_id,
- }))
- ) || []
- );
- }, [inventoryProduct]);
-
return (
-
+
+ {inventoryProduct?.product_warehouses?.map((productWarehouse) => (
+
+ ))}
+
);
};
diff --git a/src/components/pages/inventory/product/detail/StockLogTable.tsx b/src/components/pages/inventory/product/detail/StockLogTable.tsx
index a8240952..b92a4512 100644
--- a/src/components/pages/inventory/product/detail/StockLogTable.tsx
+++ b/src/components/pages/inventory/product/detail/StockLogTable.tsx
@@ -1,11 +1,20 @@
+import Button from '@/components/Button';
import Card from '@/components/Card';
import Table from '@/components/Table';
+import { isResponseSuccess } from '@/lib/api-helper';
import { formatDate, formatNumber, formatTitleCase } from '@/lib/helper';
+import { StockLogApi } from '@/services/api/inventory';
import { useTableFilter } from '@/services/hooks/useTableFilter';
-import { StockLog } from '@/types/api/inventory/product';
+import { ProductWarehouseStock, StockLog } from '@/types/api/inventory/product';
import { ColumnDef } from '@tanstack/react-table';
+import { FileDown } from 'lucide-react';
+import toast from 'react-hot-toast';
+import { useState } from 'react';
+import useSWR from 'swr';
-const stockLogTableColumns: ColumnDef[] = [
+const stockLogTableColumns: (warehouseName: string) => ColumnDef[] = (
+ warehouseName
+) => [
{
header: 'ID',
accessorKey: 'id',
@@ -20,6 +29,7 @@ const stockLogTableColumns: ColumnDef[] = [
{
header: 'Gudang',
accessorKey: 'warehouse_name',
+ cell: warehouseName,
},
{
header: 'Stock Akhir',
@@ -65,31 +75,77 @@ const stockLogTableColumns: ColumnDef[] = [
];
const StockLogTable = ({
- stockLogs,
+ productWarehouse,
}: {
- stockLogs: (StockLog & { warehouse_name: string; warehouse_id: number })[];
+ productWarehouse: ProductWarehouseStock;
}) => {
- const { state: tableFilterState, setPage, setPageSize } = useTableFilter();
+ const [isExportLoading, setIsExportLoading] = useState(false);
+
+ const {
+ state: tableFilterState,
+ setPage,
+ setPageSize,
+ toQueryString: getTableFilterQueryString,
+ } = useTableFilter({
+ initial: {
+ product_warehouse_id: productWarehouse.id,
+ },
+ });
+
+ const handleExportExcel = async () => {
+ setIsExportLoading(true);
+ try {
+ await StockLogApi.exportToExcel(
+ productWarehouse.warehouse_name,
+ getTableFilterQueryString()
+ );
+ toast.success('Excel berhasil dibuat dan diunduh.');
+ } catch {
+ toast.error('Gagal membuat Excel. Silakan coba lagi.');
+ } finally {
+ setIsExportLoading(false);
+ }
+ };
+
+ const { data: stockLogsResponse, isLoading: isLoadingStockLogs } = useSWR(
+ `${StockLogApi.basePath}${getTableFilterQueryString()}`,
+ StockLogApi.getAllFetcher
+ );
+
+ const stockLogs = isResponseSuccess(stockLogsResponse)
+ ? stockLogsResponse.data
+ : [];
return (
+
+
+
data={stockLogs}
- columns={stockLogTableColumns}
+ columns={stockLogTableColumns(productWarehouse.warehouse_name)}
page={tableFilterState.page ?? 0}
pageSize={tableFilterState.pageSize}
onPageChange={setPage}
onPageSizeChange={setPageSize}
- totalItems={stockLogs?.length ?? 0}
+ isLoading={isLoadingStockLogs}
+ totalItems={
+ isResponseSuccess(stockLogsResponse)
+ ? stockLogsResponse.meta?.total_results
+ : 0
+ }
className={{
- containerClassName: 'mt-6',
+ containerClassName: 'mt-4 mb-0',
tableWrapperClassName: 'overflow-x-auto min-h-full!',
tableClassName: 'font-inter w-full table-auto min-h-full!',
headerRowClassName: 'border-b border-b-gray-200',
diff --git a/src/services/api/inventory.ts b/src/services/api/inventory.ts
index 70a7c8f9..df72959f 100644
--- a/src/services/api/inventory.ts
+++ b/src/services/api/inventory.ts
@@ -13,7 +13,9 @@ import {
CreateInventoryAdjustmentPayload,
InventoryAdjustment,
} from '@/types/api/inventory/adjustment';
-import { InventoryProduct } from '@/types/api/inventory/product';
+import { InventoryProduct, StockLog } from '@/types/api/inventory/product';
+import { httpClient } from '../http/client';
+import { formatDate } from '@/lib/helper';
export const ProductWarehouseApi = new BaseApiService<
ProductWarehouse,
@@ -65,3 +67,41 @@ export const InventoryProductApi = new BaseApiService<
unknown,
unknown
>('/inventory/product-stocks');
+
+export class StockLogService extends BaseApiService<
+ StockLog,
+ unknown,
+ unknown
+> {
+ constructor(basePath: string = '/inventory/stock-logs') {
+ super(basePath);
+ }
+
+ async exportToExcel(warehouseName: string, initialQueryString: string) {
+ const params = new URLSearchParams(initialQueryString);
+
+ params.set('export', 'excel');
+ params.set('page', '1');
+ params.set('limit', '99999999999');
+
+ 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 = `informasi-stok-produk-${warehouseName.toLowerCase().replaceAll(' ', '-')}-${formatDate(Date.now(), 'DD-MM-YYYY')}.xlsx`;
+ link.setAttribute('download', fileName);
+
+ document.body.appendChild(link);
+ link.click();
+ link.remove();
+ }
+}
+
+export const StockLogApi = new StockLogService('/inventory/stock-logs');