|
- "use client";
-
- import { useCallback, useMemo, useState } from "react";
- import { useTranslation } from "react-i18next";
- import SearchResults, { Column } from "../SearchResults/index";
- import DeleteIcon from "@mui/icons-material/Delete";
- import { useRouter } from "next/navigation";
- import { deleteDialog, successDialog } from "../Swal/CustomAlerts";
- import { WarehouseResult } from "@/app/api/warehouse";
- import { deleteWarehouse } from "@/app/api/warehouse/actions";
- import Card from "@mui/material/Card";
- import CardContent from "@mui/material/CardContent";
- import CardActions from "@mui/material/CardActions";
- import Typography from "@mui/material/Typography";
- import TextField from "@mui/material/TextField";
- import Button from "@mui/material/Button";
- import Box from "@mui/material/Box";
- import RestartAlt from "@mui/icons-material/RestartAlt";
- import Search from "@mui/icons-material/Search";
- import InputAdornment from "@mui/material/InputAdornment";
-
- interface Props {
- warehouses: WarehouseResult[];
- }
-
- type SearchQuery = Partial<Omit<WarehouseResult, "id">>;
- type SearchParamNames = keyof SearchQuery;
-
- const WarehouseHandle: React.FC<Props> = ({ warehouses }) => {
- const { t } = useTranslation(["warehouse", "common"]);
- const [filteredWarehouse, setFilteredWarehouse] = useState(warehouses);
- const [pagingController, setPagingController] = useState({
- pageNum: 1,
- pageSize: 10,
- });
- const router = useRouter();
- const [isSearching, setIsSearching] = useState(false);
-
- const [searchInputs, setSearchInputs] = useState({
- store_id: "",
- warehouse: "",
- area: "",
- slot: "",
- stockTakeSection: "",
- });
-
- const onDeleteClick = useCallback((warehouse: WarehouseResult) => {
- deleteDialog(async () => {
- try {
- await deleteWarehouse(warehouse.id);
- setFilteredWarehouse(prev => prev.filter(w => w.id !== warehouse.id));
- router.refresh();
- successDialog(t("Delete Success"), t);
- } catch (error) {
- console.error("Failed to delete warehouse:", error);
- // Don't redirect on error, just show error message
- // The error will be logged but user stays on the page
- }
- }, t);
- }, [t, router]);
-
- const handleReset = useCallback(() => {
- setSearchInputs({
- store_id: "",
- warehouse: "",
- area: "",
- slot: "",
- stockTakeSection: "",
- });
- setFilteredWarehouse(warehouses);
- setPagingController({ pageNum: 1, pageSize: pagingController.pageSize });
- }, [warehouses, pagingController.pageSize]);
-
- const handleSearch = useCallback(() => {
- setIsSearching(true);
- try {
- let results: WarehouseResult[] = warehouses;
-
- // Build search pattern from the four fields: store_idF-warehouse-area-slot
- // Only search by code field - match the code that follows this pattern
- const storeId = searchInputs.store_id?.trim() || "";
- const warehouse = searchInputs.warehouse?.trim() || "";
- const area = searchInputs.area?.trim() || "";
- const slot = searchInputs.slot?.trim() || "";
- const stockTakeSection = searchInputs.stockTakeSection?.trim() || "";
-
- // If any field has a value, filter by code pattern and stockTakeSection
- if (storeId || warehouse || area || slot || stockTakeSection) {
- results = warehouses.filter((warehouseItem) => {
- // Filter by stockTakeSection if provided
- if (stockTakeSection) {
- const itemStockTakeSection = String(warehouseItem.stockTakeSection || "").toLowerCase();
- if (!itemStockTakeSection.includes(stockTakeSection.toLowerCase())) {
- return false;
- }
- }
-
- // Filter by code pattern if any code-related field is provided
- if (storeId || warehouse || area || slot) {
- if (!warehouseItem.code) {
- return false;
- }
-
- const codeValue = String(warehouseItem.code).toLowerCase();
-
- // Check if code matches the pattern: store_id-warehouse-area-slot
- // Match each part if provided
- const codeParts = codeValue.split("-");
-
- if (codeParts.length >= 4) {
- const codeStoreId = codeParts[0] || "";
- const codeWarehouse = codeParts[1] || "";
- const codeArea = codeParts[2] || "";
- const codeSlot = codeParts[3] || "";
-
- const storeIdMatch = !storeId || codeStoreId.includes(storeId.toLowerCase());
- const warehouseMatch = !warehouse || codeWarehouse.includes(warehouse.toLowerCase());
- const areaMatch = !area || codeArea.includes(area.toLowerCase());
- const slotMatch = !slot || codeSlot.includes(slot.toLowerCase());
-
- return storeIdMatch && warehouseMatch && areaMatch && slotMatch;
- }
-
- // Fallback: if code doesn't follow the pattern, check if it contains any of the search terms
- const storeIdMatch = !storeId || codeValue.includes(storeId.toLowerCase());
- const warehouseMatch = !warehouse || codeValue.includes(warehouse.toLowerCase());
- const areaMatch = !area || codeValue.includes(area.toLowerCase());
- const slotMatch = !slot || codeValue.includes(slot.toLowerCase());
-
- return storeIdMatch && warehouseMatch && areaMatch && slotMatch;
- }
-
- // If only stockTakeSection is provided, return true (already filtered above)
- return true;
- });
- } else {
- // If no search terms, show all warehouses
- results = warehouses;
- }
-
- setFilteredWarehouse(results);
- setPagingController({ pageNum: 1, pageSize: pagingController.pageSize });
- } catch (error) {
- console.error("Error searching warehouses:", error);
- // Fallback: filter by code pattern and stockTakeSection
- const storeId = searchInputs.store_id?.trim().toLowerCase() || "";
- const warehouse = searchInputs.warehouse?.trim().toLowerCase() || "";
- const area = searchInputs.area?.trim().toLowerCase() || "";
- const slot = searchInputs.slot?.trim().toLowerCase() || "";
- const stockTakeSection = searchInputs.stockTakeSection?.trim().toLowerCase() || "";
-
- setFilteredWarehouse(
- warehouses.filter((warehouseItem) => {
- // Filter by stockTakeSection if provided
- if (stockTakeSection) {
- const itemStockTakeSection = String(warehouseItem.stockTakeSection || "").toLowerCase();
- if (!itemStockTakeSection.includes(stockTakeSection)) {
- return false;
- }
- }
-
- // Filter by code if any code-related field is provided
- if (storeId || warehouse || area || slot) {
- if (!warehouseItem.code) {
- return false;
- }
-
- const codeValue = String(warehouseItem.code).toLowerCase();
- const codeParts = codeValue.split("-");
-
- if (codeParts.length >= 4) {
- const storeIdMatch = !storeId || codeParts[0].includes(storeId);
- const warehouseMatch = !warehouse || codeParts[1].includes(warehouse);
- const areaMatch = !area || codeParts[2].includes(area);
- const slotMatch = !slot || codeParts[3].includes(slot);
- return storeIdMatch && warehouseMatch && areaMatch && slotMatch;
- }
-
- return (!storeId || codeValue.includes(storeId)) &&
- (!warehouse || codeValue.includes(warehouse)) &&
- (!area || codeValue.includes(area)) &&
- (!slot || codeValue.includes(slot));
- }
-
- return true;
- })
- );
- } finally {
- setIsSearching(false);
- }
- }, [searchInputs, warehouses, pagingController.pageSize]);
-
- const columns = useMemo<Column<WarehouseResult>[]>(
- () => [
- {
- name: "code",
- label: t("code"),
- align: "left",
- headerAlign: "left",
- sx: { width: "15%", minWidth: "120px" },
- },
- {
- name: "store_id",
- label: t("store_id"),
- align: "left",
- headerAlign: "left",
- sx: { width: "15%", minWidth: "120px" },
- },
- {
- name: "warehouse",
- label: t("warehouse"),
- align: "left",
- headerAlign: "left",
- sx: { width: "15%", minWidth: "120px" },
- },
- {
- name: "area",
- label: t("area"),
- align: "left",
- headerAlign: "left",
- sx: { width: "15%", minWidth: "120px" },
- },
- {
- name: "slot",
- label: t("slot"),
- align: "left",
- headerAlign: "left",
- sx: { width: "15%", minWidth: "120px" },
- },
- {
- name: "order",
- label: t("order"),
- align: "left",
- headerAlign: "left",
- sx: { width: "15%", minWidth: "120px" },
- },
- {
- name: "stockTakeSection",
- label: t("stockTakeSection"),
- align: "left",
- headerAlign: "left",
- sx: { width: "15%", minWidth: "120px" },
- },
- {
- name: "action",
- label: t("Delete"),
- onClick: onDeleteClick,
- buttonIcon: <DeleteIcon />,
- color: "error",
- sx: { width: "10%", minWidth: "80px" },
- },
- ],
- [t, onDeleteClick],
- );
-
- return (
- <>
- <Card>
- <CardContent sx={{ display: "flex", flexDirection: "column", gap: 1 }}>
- <Typography variant="overline">{t("Search Criteria")}</Typography>
- <Box
- sx={{
- display: "flex",
- alignItems: "center",
- gap: 1,
- flexWrap: "nowrap",
- justifyContent: "flex-start",
- }}
- >
- {/* 樓層 field with F inside on the right */}
- <TextField
- label={t("store_id")}
- value={searchInputs.store_id}
- onChange={(e) =>
- setSearchInputs((prev) => ({ ...prev, store_id: e.target.value }))
- }
- size="small"
- sx={{ width: "150px", minWidth: "120px" }}
- InputProps={{
- endAdornment: (
- <InputAdornment position="end">F</InputAdornment>
- ),
- }}
- />
- <Typography variant="body1" sx={{ mx: 0.5 }}>
- -
- </Typography>
- {/* 倉庫 field */}
- <TextField
- label={t("warehouse")}
- value={searchInputs.warehouse}
- onChange={(e) =>
- setSearchInputs((prev) => ({ ...prev, warehouse: e.target.value }))
- }
- size="small"
- sx={{ width: "150px", minWidth: "120px" }}
- />
- <Typography variant="body1" sx={{ mx: 0.5 }}>
- -
- </Typography>
- {/* 區域 field */}
- <TextField
- label={t("area")}
- value={searchInputs.area}
- onChange={(e) =>
- setSearchInputs((prev) => ({ ...prev, area: e.target.value }))
- }
- size="small"
- sx={{ width: "150px", minWidth: "120px" }}
- />
- <Typography variant="body1" sx={{ mx: 0.5 }}>
- -
- </Typography>
- {/* 儲位 field */}
- <TextField
- label={t("slot")}
- value={searchInputs.slot}
- onChange={(e) =>
- setSearchInputs((prev) => ({ ...prev, slot: e.target.value }))
- }
- size="small"
- sx={{ width: "150px", minWidth: "120px" }}
- />
- {/* 盤點區域 field */}
- <Box sx={{ flex: 1, minWidth: "150px", ml: 2 }}>
- <TextField
- label={t("stockTakeSection")}
- value={searchInputs.stockTakeSection}
- onChange={(e) =>
- setSearchInputs((prev) => ({ ...prev, stockTakeSection: e.target.value }))
- }
- size="small"
- fullWidth
- />
- </Box>
- </Box>
- <CardActions sx={{ justifyContent: "flex-start", px: 0, pt: 1 }}>
- <Button
- variant="text"
- startIcon={<RestartAlt />}
- onClick={handleReset}
- >
- {t("Reset")}
- </Button>
- <Button
- variant="outlined"
- startIcon={<Search />}
- onClick={handleSearch}
- >
- {t("Search")}
- </Button>
- </CardActions>
- </CardContent>
- </Card>
- <SearchResults<WarehouseResult>
- items={filteredWarehouse}
- columns={columns}
- pagingController={pagingController}
- setPagingController={setPagingController}
- />
- </>
- );
- };
- export default WarehouseHandle;
|