mirror of
https://github.com/ForFarmTeam/ForFarm.git
synced 2025-12-19 14:04:08 +01:00
feat: refactor inventory item deletion and editing logic for improved error handling and structure
This commit is contained in:
parent
f037bf766f
commit
63d38fb99d
@ -160,7 +160,6 @@ type GetInventoryItemOutput struct {
|
|||||||
|
|
||||||
type DeleteInventoryItemInput struct {
|
type DeleteInventoryItemInput struct {
|
||||||
Header string `header:"Authorization" required:"true" example:"Bearer token"`
|
Header string `header:"Authorization" required:"true" example:"Bearer token"`
|
||||||
UserID string `header:"userId" required:"true" example:"user-uuid"`
|
|
||||||
ID string `path:"id"`
|
ID string `path:"id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -347,7 +346,8 @@ func (a *api) updateInventoryItemHandler(ctx context.Context, input *UpdateInven
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *api) deleteInventoryItemHandler(ctx context.Context, input *DeleteInventoryItemInput) (*DeleteInventoryItemOutput, error) {
|
func (a *api) deleteInventoryItemHandler(ctx context.Context, input *DeleteInventoryItemInput) (*DeleteInventoryItemOutput, error) {
|
||||||
err := a.inventoryRepo.Delete(ctx, input.ID, input.UserID)
|
userID, err := a.getUserIDFromHeader(input.Header)
|
||||||
|
err = a.inventoryRepo.Delete(ctx, input.ID, userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -92,9 +92,32 @@ export async function deleteInventoryItem(id: string) {
|
|||||||
try {
|
try {
|
||||||
const response = await axiosInstance.delete("/inventory/" + id);
|
const response = await axiosInstance.delete("/inventory/" + id);
|
||||||
return response.data;
|
return response.data;
|
||||||
} catch (error) {
|
} catch (error: unknown) {
|
||||||
console.error("Error while deleting Inventory Item! " + error);
|
// Cast error to AxiosError to safely access response properties
|
||||||
throw new Error("Failed to deleting inventory item: " + error);
|
if (error instanceof AxiosError && error.response) {
|
||||||
|
// Log the detailed error message
|
||||||
|
console.error("Error while deleting Inventory Item!");
|
||||||
|
console.error("Response Status:", error.response.status); // e.g., 422
|
||||||
|
console.error("Error Detail:", error.response.data?.detail); // Custom error message from backend
|
||||||
|
console.error("Full Error Response:", error.response.data); // Entire error object (including details)
|
||||||
|
|
||||||
|
// Throw a new error with a more specific message
|
||||||
|
throw new Error(
|
||||||
|
`Failed to delete inventory item: ${
|
||||||
|
error.response.data?.detail || error.message
|
||||||
|
}`
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// Handle other errors (e.g., network errors or unknown errors)
|
||||||
|
console.error(
|
||||||
|
"Error while deleting Inventory Item, unknown error:",
|
||||||
|
error
|
||||||
|
);
|
||||||
|
throw new Error(
|
||||||
|
"Failed to delete inventory item: " +
|
||||||
|
(error instanceof Error ? error.message : "Unknown error")
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export async function updateInventoryItem(
|
export async function updateInventoryItem(
|
||||||
|
|||||||
@ -19,7 +19,6 @@ export function DeleteInventoryItem({ id }: { id: string }) {
|
|||||||
mutationFn: deleteInventoryItem,
|
mutationFn: deleteInventoryItem,
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
queryClient.invalidateQueries({ queryKey: ["inventoryItems"] });
|
queryClient.invalidateQueries({ queryKey: ["inventoryItems"] });
|
||||||
setOpen(false); // Close dialog on success
|
|
||||||
},
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
console.error("Failed to delete item:", error);
|
console.error("Failed to delete item:", error);
|
||||||
@ -32,7 +31,7 @@ export function DeleteInventoryItem({ id }: { id: string }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{/* trigger button for the confirmation dialog */}
|
{/* delete confirmation dialog */}
|
||||||
<Dialog open={open} onOpenChange={setOpen}>
|
<Dialog open={open} onOpenChange={setOpen}>
|
||||||
<DialogTrigger asChild>
|
<DialogTrigger asChild>
|
||||||
<Button
|
<Button
|
||||||
@ -48,8 +47,6 @@ export function DeleteInventoryItem({ id }: { id: string }) {
|
|||||||
Are you sure you want to delete this item? This action cannot be
|
Are you sure you want to delete this item? This action cannot be
|
||||||
undone.
|
undone.
|
||||||
</DialogDescription>
|
</DialogDescription>
|
||||||
|
|
||||||
{/* footer with confirm and cancel buttons */}
|
|
||||||
<DialogFooter>
|
<DialogFooter>
|
||||||
<Button
|
<Button
|
||||||
className="bg-gray-500 hover:bg-gray-700 text-white"
|
className="bg-gray-500 hover:bg-gray-700 text-white"
|
||||||
|
|||||||
@ -27,47 +27,40 @@ import {
|
|||||||
SelectTrigger,
|
SelectTrigger,
|
||||||
SelectValue,
|
SelectValue,
|
||||||
} from "@/components/ui/select";
|
} from "@/components/ui/select";
|
||||||
import { InventoryStatus, InventoryItemCategory, HarvestUnits } from "@/types";
|
import {
|
||||||
|
InventoryStatus,
|
||||||
|
InventoryItemCategory,
|
||||||
|
HarvestUnits,
|
||||||
|
UpdateInventoryItemInput,
|
||||||
|
} from "@/types";
|
||||||
import { updateInventoryItem } from "@/api/inventory";
|
import { updateInventoryItem } from "@/api/inventory";
|
||||||
import type { UpdateInventoryItemInput } from "@/types";
|
|
||||||
|
|
||||||
export interface EditInventoryItemProps {
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
categoryId: number;
|
|
||||||
statusId: number;
|
|
||||||
unitId: number;
|
|
||||||
quantity: number;
|
|
||||||
fetchedInventoryStatus: InventoryStatus[];
|
|
||||||
fetchedInventoryCategory: InventoryItemCategory[];
|
|
||||||
fetchedHarvestUnits: HarvestUnits[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export function EditInventoryItem({
|
export function EditInventoryItem({
|
||||||
id,
|
item,
|
||||||
name,
|
|
||||||
categoryId,
|
|
||||||
statusId,
|
|
||||||
unitId,
|
|
||||||
quantity,
|
|
||||||
fetchedInventoryStatus,
|
fetchedInventoryStatus,
|
||||||
fetchedInventoryCategory,
|
fetchedInventoryCategory,
|
||||||
fetchedHarvestUnits,
|
fetchedHarvestUnits,
|
||||||
}: EditInventoryItemProps) {
|
}: {
|
||||||
|
item: UpdateInventoryItemInput;
|
||||||
|
fetchedInventoryStatus: InventoryStatus[];
|
||||||
|
fetchedInventoryCategory: InventoryItemCategory[];
|
||||||
|
fetchedHarvestUnits: HarvestUnits[];
|
||||||
|
}) {
|
||||||
|
console.table(item);
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const [itemName, setItemName] = useState(name);
|
const [itemName, setItemName] = useState(item.name);
|
||||||
const [itemCategory, setItemCategory] = useState(
|
const [itemCategory, setItemCategory] = useState(
|
||||||
fetchedInventoryCategory.find(
|
fetchedInventoryCategory.find((x) => x.id === item.categoryId)?.name
|
||||||
(categoryItem) => categoryItem.id === categoryId
|
|
||||||
)?.name
|
|
||||||
);
|
);
|
||||||
const [itemQuantity, setItemQuantity] = useState(quantity);
|
|
||||||
|
const [itemQuantity, setItemQuantity] = useState(item.quantity);
|
||||||
|
|
||||||
const [itemUnit, setItemUnit] = useState(
|
const [itemUnit, setItemUnit] = useState(
|
||||||
fetchedHarvestUnits.find((harvestItem) => harvestItem.id === unitId)?.name
|
fetchedHarvestUnits.find((x) => x.id === item.unitId)?.name
|
||||||
);
|
);
|
||||||
|
|
||||||
const [itemStatus, setItemStatus] = useState(
|
const [itemStatus, setItemStatus] = useState(
|
||||||
fetchedInventoryStatus.find((statusItem) => statusItem.id === statusId)
|
fetchedInventoryStatus.find((x) => x.id === item.statusId)?.name
|
||||||
?.name
|
|
||||||
);
|
);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
|
||||||
@ -75,7 +68,7 @@ export function EditInventoryItem({
|
|||||||
|
|
||||||
const mutation = useMutation({
|
const mutation = useMutation({
|
||||||
mutationFn: (item: UpdateInventoryItemInput) =>
|
mutationFn: (item: UpdateInventoryItemInput) =>
|
||||||
updateInventoryItem(id, item),
|
updateInventoryItem(item.id, item),
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
// invalidate queries to refresh inventory data.
|
// invalidate queries to refresh inventory data.
|
||||||
queryClient.invalidateQueries({ queryKey: ["inventoryItems"] });
|
queryClient.invalidateQueries({ queryKey: ["inventoryItems"] });
|
||||||
@ -108,26 +101,9 @@ export function EditInventoryItem({
|
|||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// console.table({
|
|
||||||
// name: itemName,
|
|
||||||
// categoryId:
|
|
||||||
// fetchedInventoryCategory.find(
|
|
||||||
// (category) => category.name === itemCategory
|
|
||||||
// )?.id ?? 0,
|
|
||||||
// quantity: itemQuantity,
|
|
||||||
// unitId:
|
|
||||||
// fetchedHarvestUnits.find((unit) => unit.name === itemUnit)?.id ?? 0,
|
|
||||||
// statusId:
|
|
||||||
// fetchedInventoryStatus.find((status) => status.name === itemStatus)
|
|
||||||
// ?.id ?? 0,
|
|
||||||
// lastUpdated: new Date().toISOString(),
|
|
||||||
// });
|
|
||||||
mutation.mutate({
|
mutation.mutate({
|
||||||
name: itemName,
|
name: itemName,
|
||||||
categoryId:
|
categoryId: item.categoryId,
|
||||||
fetchedInventoryCategory.find(
|
|
||||||
(category) => category.name === itemCategory
|
|
||||||
)?.id ?? 0,
|
|
||||||
quantity: itemQuantity,
|
quantity: itemQuantity,
|
||||||
unitId:
|
unitId:
|
||||||
fetchedHarvestUnits.find((unit) => unit.name === itemUnit)?.id ?? 0,
|
fetchedHarvestUnits.find((unit) => unit.name === itemUnit)?.id ?? 0,
|
||||||
@ -135,6 +111,7 @@ export function EditInventoryItem({
|
|||||||
fetchedInventoryStatus.find((status) => status.name === itemStatus)
|
fetchedInventoryStatus.find((status) => status.name === itemStatus)
|
||||||
?.id ?? 0,
|
?.id ?? 0,
|
||||||
dateAdded: new Date().toISOString(),
|
dateAdded: new Date().toISOString(),
|
||||||
|
id: "",
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -40,11 +40,9 @@ import {
|
|||||||
fetchInventoryCategory,
|
fetchInventoryCategory,
|
||||||
} from "@/api/inventory";
|
} from "@/api/inventory";
|
||||||
import { AddInventoryItem } from "./add-inventory-item";
|
import { AddInventoryItem } from "./add-inventory-item";
|
||||||
import {
|
import { EditInventoryItem } from "./edit-inventory-item";
|
||||||
EditInventoryItem,
|
|
||||||
EditInventoryItemProps,
|
|
||||||
} from "./edit-inventory-item";
|
|
||||||
import { DeleteInventoryItem } from "./delete-inventory-item";
|
import { DeleteInventoryItem } from "./delete-inventory-item";
|
||||||
|
import { InventoryItem } from "@/types";
|
||||||
|
|
||||||
export default function InventoryPage() {
|
export default function InventoryPage() {
|
||||||
const [sorting, setSorting] = useState<SortingState>([]);
|
const [sorting, setSorting] = useState<SortingState>([]);
|
||||||
@ -105,12 +103,9 @@ export default function InventoryPage() {
|
|||||||
return inventoryItems
|
return inventoryItems
|
||||||
.map((item) => ({
|
.map((item) => ({
|
||||||
...item,
|
...item,
|
||||||
status: item.status.name,
|
status: { id: item.status.id, name: item.status.name },
|
||||||
category: item.category.name,
|
category: { id: item.category.id, name: item.category.name },
|
||||||
categoryId: item.categoryId,
|
unit: { id: item.unit.id, name: item.unit.name },
|
||||||
unit: item.unit.name,
|
|
||||||
unitId: item.unitId,
|
|
||||||
statusId: item.statusId,
|
|
||||||
fetchedInventoryStatus: inventoryStatus,
|
fetchedInventoryStatus: inventoryStatus,
|
||||||
fetchedInventoryCategory: inventoryCategory,
|
fetchedInventoryCategory: inventoryCategory,
|
||||||
fetchedHarvestUnits: harvestUnits,
|
fetchedHarvestUnits: harvestUnits,
|
||||||
@ -132,15 +127,31 @@ export default function InventoryPage() {
|
|||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{ accessorKey: "name", header: "Name" },
|
{ accessorKey: "name", header: "Name" },
|
||||||
{ accessorKey: "category", header: "Category" },
|
{
|
||||||
{ accessorKey: "quantity", header: "Quantity" },
|
accessorKey: "category",
|
||||||
{ accessorKey: "unit", header: "Unit" },
|
header: "Category",
|
||||||
{ accessorKey: "lastUpdated", header: "Last Updated" },
|
cell: ({ row }: { row: { original: InventoryItem } }) =>
|
||||||
|
row.original.category.name,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: "quantity",
|
||||||
|
header: "Quantity",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: "unit",
|
||||||
|
header: "Unit",
|
||||||
|
cell: ({ row }: { row: { original: InventoryItem } }) =>
|
||||||
|
row.original.unit.name,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: "lastUpdated",
|
||||||
|
header: "Last Updated",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
accessorKey: "status",
|
accessorKey: "status",
|
||||||
header: "Status",
|
header: "Status",
|
||||||
cell: (info: { getValue: () => string }) => {
|
cell: ({ row }: { row: { original: InventoryItem } }) => {
|
||||||
const status = info.getValue();
|
const status = row.original.status.name;
|
||||||
|
|
||||||
let statusClass = "";
|
let statusClass = "";
|
||||||
|
|
||||||
@ -166,11 +177,20 @@ export default function InventoryPage() {
|
|||||||
{
|
{
|
||||||
accessorKey: "edit",
|
accessorKey: "edit",
|
||||||
header: "Edit",
|
header: "Edit",
|
||||||
cell: ({ row }: { row: { original: EditInventoryItemProps } }) => (
|
cell: ({ row }: { row: { original: InventoryItem } }) => (
|
||||||
<EditInventoryItem
|
<EditInventoryItem
|
||||||
{...row.original}
|
item={{
|
||||||
|
id: row.original.id,
|
||||||
|
name: row.original.name,
|
||||||
|
categoryId: row.original.categoryId,
|
||||||
|
quantity: row.original.quantity,
|
||||||
|
unitId: row.original.unitId,
|
||||||
|
dateAdded: row.original.dateAdded,
|
||||||
|
statusId: row.original.statusId,
|
||||||
|
}}
|
||||||
fetchedInventoryStatus={inventoryStatus}
|
fetchedInventoryStatus={inventoryStatus}
|
||||||
fetchedInventoryCategory={inventoryCategory}
|
fetchedInventoryCategory={inventoryCategory}
|
||||||
|
fetchedHarvestUnits={harvestUnits}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
enableSorting: false,
|
enableSorting: false,
|
||||||
@ -178,7 +198,7 @@ export default function InventoryPage() {
|
|||||||
{
|
{
|
||||||
accessorKey: "delete",
|
accessorKey: "delete",
|
||||||
header: "Delete",
|
header: "Delete",
|
||||||
cell: ({ row }: { row: { original: EditInventoryItemProps } }) => (
|
cell: ({ row }: { row: { original: InventoryItem } }) => (
|
||||||
<DeleteInventoryItem id={row.original.id} />
|
<DeleteInventoryItem id={row.original.id} />
|
||||||
),
|
),
|
||||||
enableSorting: false,
|
enableSorting: false,
|
||||||
|
|||||||
@ -160,9 +160,12 @@ export type CreateInventoryItemInput = {
|
|||||||
statusId: number;
|
statusId: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type UpdateInventoryItemInput = CreateInventoryItemInput & {};
|
// export type UpdateInventoryItemInput = CreateInventoryItemInput & {};
|
||||||
|
// export type EditInventoryItemInput = CreateInventoryItemInput & { id: number };
|
||||||
|
|
||||||
// export type UpdateInventoryItemInput = Partial<CreateInventoryItemInput> & { id: string };
|
export type UpdateInventoryItemInput = Partial<CreateInventoryItemInput> & {
|
||||||
|
id: string;
|
||||||
|
};
|
||||||
|
|
||||||
export interface Blog {
|
export interface Blog {
|
||||||
id: number;
|
id: number;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user