Переглянути джерело

Missing Item Maintanence

master
Tommy\2Fi-Staff 3 тижднів тому
джерело
коміт
198652e4c5
5 змінених файлів з 99 додано та 57 видалено
  1. +16
    -1
      src/app/api/settings/item/actions.ts
  2. +1
    -0
      src/app/api/settings/item/index.ts
  3. +13
    -2
      src/components/CreateItem/CreateItemWrapper.tsx
  4. +8
    -1
      src/components/CreateItem/ProductDetails.tsx
  5. +61
    -53
      src/components/ItemsSearch/ItemsSearch.tsx

+ 16
- 1
src/app/api/settings/item/actions.ts Переглянути файл

@@ -4,7 +4,7 @@ import {
serverFetchJson,
serverFetchWithNoContent,
} from "@/app/utils/fetchUtil";
import { revalidateTag } from "next/cache";
import { revalidateTag, revalidatePath } from "next/cache";
import { BASE_API_URL } from "@/config/api";
import { CreateItemResponse, RecordsRes } from "../../utils";
import { ItemQc, ItemsResult } from ".";
@@ -60,6 +60,21 @@ export const saveItem = async (data: CreateItemInputs) => {
return item;
};

export const deleteItem = async (id: number) => {
const response = await serverFetchJson<ItemsResult>(
`${BASE_API_URL}/items/${id}`,
{
method: "DELETE",
headers: { "Content-Type": "application/json" },
},
);

revalidateTag("items");
revalidatePath("/(main)/settings/items");

return response;
};

export interface ItemCombo {
id: number,
label: string,


+ 1
- 0
src/app/api/settings/item/index.ts Переглянути файл

@@ -58,6 +58,7 @@ export type ItemsResult = {
area?: string | undefined;
slot?: string | undefined;
LocationCode?: string | undefined;
locationCode?: string | undefined; // Backend may return lowercase version
isEgg?: boolean | undefined;
isFee?: boolean | undefined;
isBag?: boolean | undefined;


+ 13
- 2
src/components/CreateItem/CreateItemWrapper.tsx Переглянути файл

@@ -26,7 +26,18 @@ const CreateItemWrapper: React.FC<Props> & SubComponents = async ({ id }) => {
const item = result.item;
qcChecks = result.qcChecks;
const activeRows = qcChecks.filter((it) => it.isActive).map((i) => i.id);
console.log(qcChecks);
// Normalize LocationCode field (handle case sensitivity from MySQL)
const locationCode = item?.LocationCode || item?.locationCode;
console.log("Fetched item data for edit:", {
id: item?.id,
code: item?.code,
name: item?.name,
LocationCode: locationCode,
rawItem: item
});
defaultValues = {
type: item?.type,
id: item?.id,
@@ -44,7 +55,7 @@ const CreateItemWrapper: React.FC<Props> & SubComponents = async ({ id }) => {
warehouse: item?.warehouse,
area: item?.area,
slot: item?.slot,
LocationCode: item?.LocationCode,
LocationCode: locationCode,
isEgg: item?.isEgg,
isFee: item?.isFee,
isBag: item?.isBag,


+ 8
- 1
src/components/CreateItem/ProductDetails.tsx Переглянути файл

@@ -23,7 +23,7 @@ import { Controller, useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";
import InputDataGrid from "../InputDataGrid";

import { SyntheticEvent, useCallback, useMemo, useState } from "react";
import { SyntheticEvent, useCallback, useEffect, useMemo, useState } from "react";
import { GridColDef, GridRowModel } from "@mui/x-data-grid";
import { InputDataGridProps, TableRow } from "../InputDataGrid/InputDataGrid";
import { TypeEnum } from "@/app/utils/typeEnum";
@@ -114,6 +114,13 @@ const ProductDetails: React.FC<Props> = ({ isEditMode, qcCategoryCombo, warehous
onChange(value.id)
}, [])

// Ensure LocationCode is set from defaultValues when component mounts
useEffect(() => {
if (initialDefaultValues?.LocationCode && !getValues("LocationCode")) {
setValue("LocationCode", initialDefaultValues.LocationCode);
}
}, [initialDefaultValues, setValue, getValues]);

return (
<Card sx={{ display: "block" }}>
<CardContent component={Stack} spacing={4}>


+ 61
- 53
src/components/ItemsSearch/ItemsSearch.tsx Переглянути файл

@@ -13,6 +13,8 @@ import { TypeEnum } from "@/app/utils/typeEnum";
import axios from "axios";
import { BASE_API_URL, NEXT_PUBLIC_API_URL } from "@/config/api";
import axiosInstance from "@/app/(main)/axios/axiosInstance";
import { deleteItem } from "@/app/api/settings/item/actions";
import { deleteDialog, successDialog } from "../Swal/CustomAlerts";

type Props = {
items: ItemsResult[];
@@ -50,8 +52,6 @@ const ItemsSearch: React.FC<Props> = ({ items }) => {
[router],
);

const onDeleteClick = useCallback((item: ItemsResult) => {}, [router]);

const checkItemStatus = useCallback((item: ItemsResult): "complete" | "missing" => {
// Check if type exists and is not empty
const hasType = item.type != null && String(item.type).trim() !== "";
@@ -76,48 +76,6 @@ const ItemsSearch: React.FC<Props> = ({ items }) => {
return "missing";
}, []);

const columns = useMemo<Column<ItemsResultWithStatus>[]>(
() => [
{
name: "id",
label: t("Details"),
onClick: onDetailClick,
buttonIcon: <EditNote />,
},
{
name: "code",
label: t("Code"),
},
{
name: "name",
label: t("Name"),
},
{
name: "type",
label: t("Type"),
},
{
name: "status",
label: t("Status"),
renderCell: (item) => {
const status = item.status || checkItemStatus(item);
if (status === "complete") {
return <Chip label={t("Complete")} color="success" size="small" />;
} else {
return <Chip label={t("Missing Data")} color="warning" size="small" />;
}
},
},
{
name: "action",
label: t(""),
buttonIcon: <GridDeleteIcon />,
onClick: onDeleteClick,
},
],
[onDeleteClick, onDetailClick, t, checkItemStatus],
);

const refetchData = useCallback(
async (filterObj: SearchQuery) => {
const authHeader = axiosInstance.defaults.headers["Authorization"];
@@ -134,8 +92,6 @@ const ItemsSearch: React.FC<Props> = ({ items }) => {
`${NEXT_PUBLIC_API_URL}/items/getRecordByPage`,
{ params },
);
console.log("API Response:", response);
console.log("First record keys:", response.data?.records?.[0] ? Object.keys(response.data.records[0]) : "No records");
if (response.status == 200) {
// Normalize field names and add status to each item
const itemsWithStatus: ItemsResultWithStatus[] = response.data.records.map((item: any) => {
@@ -150,18 +106,12 @@ const ItemsSearch: React.FC<Props> = ({ items }) => {
qcCategory: item.qcCategory || (qcCategoryId ? { id: qcCategoryId } : undefined),
};
console.log("Normalized item:", {
id: normalizedItem.id,
LocationCode: normalizedItem.LocationCode,
qcCategoryId: qcCategoryId,
qcCategory: normalizedItem.qcCategory
});
return {
...normalizedItem,
status: checkItemStatus(normalizedItem),
};
});
console.log("Fetched items data:", itemsWithStatus);
setFilteredItems(itemsWithStatus as ItemsResult[]);
setTotalCount(response.data.total);
return response; // Return the data from the response
@@ -185,6 +135,64 @@ const ItemsSearch: React.FC<Props> = ({ items }) => {
refetchData,
]);

const onDeleteClick = useCallback(
(item: ItemsResult) => {
deleteDialog(async () => {
if (item.id) {
const itemId = typeof item.id === "string" ? parseInt(item.id, 10) : item.id;
if (!isNaN(itemId)) {
await deleteItem(itemId);
await refetchData(filterObj);
await successDialog(t("Delete Success"), t);
}
}
}, t);
},
[refetchData, filterObj, t],
);

const columns = useMemo<Column<ItemsResultWithStatus>[]>(
() => [
{
name: "id",
label: t("Details"),
onClick: onDetailClick,
buttonIcon: <EditNote />,
},
{
name: "code",
label: t("Code"),
},
{
name: "name",
label: t("Name"),
},
{
name: "type",
label: t("Type"),
},
{
name: "status",
label: t("Status"),
renderCell: (item) => {
const status = item.status || checkItemStatus(item);
if (status === "complete") {
return <Chip label={t("Complete")} color="success" size="small" />;
} else {
return <Chip label={t("Missing Data")} color="warning" size="small" />;
}
},
},
{
name: "action",
label: t(""),
buttonIcon: <GridDeleteIcon />,
onClick: onDeleteClick,
},
],
[onDeleteClick, onDetailClick, t, checkItemStatus],
);

const onReset = useCallback(() => {
setFilteredItems(items);
}, [items]);


Завантаження…
Відмінити
Зберегти