Преглед на файлове

Warehouse Supporting Function Update

reset-do-picking-order
B.E.N.S.O.N преди 1 седмица
родител
ревизия
2b7ff5d2ea
променени са 2 файла, в които са добавени 140 реда и са изтрити 5 реда
  1. +5
    -3
      src/app/api/warehouse/actions.ts
  2. +135
    -2
      src/components/WarehouseHandle/WarehouseHandle.tsx

+ 5
- 3
src/app/api/warehouse/actions.ts Целия файл

@@ -36,9 +36,11 @@ export const createWarehouse = async (data: WarehouseInputs) => {
};

export const editWarehouse = async (id: number, data: WarehouseInputs) => {
const updatedWarehouse = await serverFetchWithNoContent(`${BASE_API_URL}/warehouse/${id}`, {
method: "PUT",
body: JSON.stringify(data),
// Backend uses the same /warehouse/save POST endpoint for both create and update,
// distinguished by presence of id in the payload.
const updatedWarehouse = await serverFetchWithNoContent(`${BASE_API_URL}/warehouse/save`, {
method: "POST",
body: JSON.stringify({ id, ...data }),
headers: { "Content-Type": "application/json" },
});
revalidateTag("warehouse");


+ 135
- 2
src/components/WarehouseHandle/WarehouseHandle.tsx Целия файл

@@ -2,12 +2,13 @@

import { useCallback, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import SearchResults, { Column } from "../SearchResults/index";
import SearchResults, { Column } from "../SearchResults/SearchResults";
import DeleteIcon from "@mui/icons-material/Delete";
import EditIcon from "@mui/icons-material/Edit";
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 { deleteWarehouse, editWarehouse } from "@/app/api/warehouse/actions";
import Card from "@mui/material/Card";
import CardContent from "@mui/material/CardContent";
import CardActions from "@mui/material/CardActions";
@@ -18,6 +19,10 @@ 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";
import Dialog from "@mui/material/Dialog";
import DialogTitle from "@mui/material/DialogTitle";
import DialogContent from "@mui/material/DialogContent";
import DialogActions from "@mui/material/DialogActions";

interface Props {
warehouses: WarehouseResult[];
@@ -36,6 +41,15 @@ const WarehouseHandle: React.FC<Props> = ({ warehouses }) => {
const router = useRouter();
const [isSearching, setIsSearching] = useState(false);

// State for editing order & stockTakeSection
const [editingWarehouse, setEditingWarehouse] = useState<WarehouseResult | null>(null);
const [editValues, setEditValues] = useState({
order: "",
stockTakeSection: "",
});
const [isSavingEdit, setIsSavingEdit] = useState(false);
const [editError, setEditError] = useState("");

const [searchInputs, setSearchInputs] = useState({
store_id: "",
warehouse: "",
@@ -69,6 +83,71 @@ const WarehouseHandle: React.FC<Props> = ({ warehouses }) => {
setPagingController({ pageNum: 1, pageSize: pagingController.pageSize });
}, [warehouses, pagingController.pageSize]);

const onEditClick = useCallback((warehouse: WarehouseResult) => {
setEditingWarehouse(warehouse);
setEditValues({
order: warehouse.order ?? "",
stockTakeSection: warehouse.stockTakeSection ?? "",
});
setEditError("");
}, []);

const handleEditClose = useCallback(() => {
if (isSavingEdit) return;
setEditingWarehouse(null);
setEditError("");
}, [isSavingEdit]);

const handleEditSave = useCallback(async () => {
if (!editingWarehouse) return;

const trimmedOrder = editValues.order.trim();
const trimmedStockTakeSection = editValues.stockTakeSection.trim();

const orderPattern = /^[A-Za-z0-9]{2}-[A-Za-z0-9]{3}$/;
const sectionPattern = /^[A-Za-z0-9]{2}-[A-Za-z0-9]{3}$/;

if (trimmedOrder && !orderPattern.test(trimmedOrder)) {
setEditError(`${t("order")} 格式必須為 XF-YYY`);
return;
}

if (trimmedStockTakeSection && !sectionPattern.test(trimmedStockTakeSection)) {
setEditError(`${t("stockTakeSection")} 格式必須為 ST-YYY`);
return;
}

try {
setIsSavingEdit(true);
setEditError("");

await editWarehouse(editingWarehouse.id, {
order: trimmedOrder || undefined,
stockTakeSection: trimmedStockTakeSection || undefined,
});

setFilteredWarehouse((prev) =>
prev.map((w) =>
w.id === editingWarehouse.id
? {
...w,
order: trimmedOrder || undefined,
stockTakeSection: trimmedStockTakeSection || undefined,
}
: w,
),
);

router.refresh();
setEditingWarehouse(null);
} catch (error) {
console.error("Failed to edit warehouse:", error);
setEditError(t("An error has occurred. Please try again later."));
} finally {
setIsSavingEdit(false);
}
}, [editValues, editingWarehouse, router, t, setFilteredWarehouse]);

const handleSearch = useCallback(() => {
setIsSearching(true);
try {
@@ -177,6 +256,14 @@ const WarehouseHandle: React.FC<Props> = ({ warehouses }) => {

const columns = useMemo<Column<WarehouseResult>[]>(
() => [
{
name: "action",
label: t("Edit"),
onClick: onEditClick,
buttonIcon: <EditIcon />,
color: "primary",
sx: { width: "10%", minWidth: "80px" },
},
{
name: "code",
label: t("code"),
@@ -226,6 +313,7 @@ const WarehouseHandle: React.FC<Props> = ({ warehouses }) => {
headerAlign: "left",
sx: { width: "15%", minWidth: "120px" },
},

{
name: "action",
label: t("Delete"),
@@ -338,6 +426,51 @@ const WarehouseHandle: React.FC<Props> = ({ warehouses }) => {
pagingController={pagingController}
setPagingController={setPagingController}
/>
<Dialog
open={Boolean(editingWarehouse)}
onClose={handleEditClose}
fullWidth
maxWidth="sm"
>
<DialogTitle>{t("Edit")}</DialogTitle>
<DialogContent sx={{ pt: 2, display: "flex", flexDirection: "column", gap: 2 }}>
{editError && (
<Typography variant="body2" color="error">
{editError}
</Typography>
)}
<TextField
label={t("order")}
value={editValues.order}
onChange={(e) =>
setEditValues((prev) => ({ ...prev, order: e.target.value }))
}
size="small"
fullWidth
/>
<TextField
label={t("stockTakeSection")}
value={editValues.stockTakeSection}
onChange={(e) =>
setEditValues((prev) => ({ ...prev, stockTakeSection: e.target.value }))
}
size="small"
fullWidth
/>
</DialogContent>
<DialogActions>
<Button onClick={handleEditClose} disabled={isSavingEdit}>
{t("Cancel")}
</Button>
<Button
onClick={handleEditSave}
disabled={isSavingEdit}
variant="contained"
>
{t("Save", { ns: "common" })}
</Button>
</DialogActions>
</Dialog>
</>
);
};


Зареждане…
Отказ
Запис