feat: add fetchInventoryCategory API and integrate into inventory management

This commit is contained in:
THIS ONE IS A LITTLE BIT TRICKY KRUB 2025-04-01 18:39:25 +07:00
parent e7bdb5d6a1
commit ba8f754d8d
4 changed files with 87 additions and 53 deletions

View File

@ -3,14 +3,15 @@ import type {
InventoryItem,
CreateInventoryItemInput,
InventoryItemStatus,
InventoryItemCategory,
} from "@/types";
/**
* Simulates an API call to fetch inventory items.
* Waits for a simulated delay and then attempts an axios GET request.
* If the request fails, returns fallback dummy data.
*
*
*
*
*/
export async function fetchInventoryStatus(): Promise<InventoryItemStatus[]> {
try {
@ -23,6 +24,19 @@ export async function fetchInventoryStatus(): Promise<InventoryItemStatus[]> {
return [];
}
}
export async function fetchInventoryCategory(): Promise<
InventoryItemCategory[]
> {
try {
const response = await axiosInstance.get<InventoryItemCategory[]>(
"/inventory/category"
);
return response.data;
} catch (error) {
console.error("Error fetching inventory status:", error);
return [];
}
}
export async function fetchInventoryItems(): Promise<InventoryItem[]> {
try {
@ -34,52 +48,47 @@ export async function fetchInventoryItems(): Promise<InventoryItem[]> {
{
id: 1,
name: "Tomato Seeds",
category: "Seeds",
type: "Plantation",
category: "1",
quantity: 500,
unit: "packets",
lastUpdated: "2023-03-01",
status: "In Stock",
status: "1",
},
{
id: 2,
name: "NPK Fertilizer",
category: "Fertilizer",
type: "Fertilizer",
category: "3",
quantity: 200,
unit: "kg",
lastUpdated: "2023-03-05",
status: "Low Stock",
status: "2",
},
{
id: 3,
name: "Corn Seeds",
category: "Seeds",
type: "Plantation",
category: "1",
quantity: 300,
unit: "packets",
lastUpdated: "2023-03-10",
status: "In Stock",
status: "3",
},
{
id: 4,
name: "Organic Compost",
category: "Fertilizer",
type: "Fertilizer",
category: "3",
quantity: 150,
unit: "kg",
lastUpdated: "2023-03-15",
status: "Out Of Stock",
status: "1",
},
{
id: 5,
name: "Wheat Seeds",
category: "Seeds",
type: "Plantation",
category: "1",
quantity: 250,
unit: "packets",
lastUpdated: "2023-03-20",
status: "In Stock",
status: "2",
},
];
}
@ -108,7 +117,6 @@ export async function createInventoryItem(
id: Math.floor(Math.random() * 1000),
name: item.name,
category: item.category,
type: item.type,
quantity: item.quantity,
unit: item.unit,
lastUpdated: new Date().toISOString(),

View File

@ -33,6 +33,7 @@ import {
SelectValue,
} from "@/components/ui/select";
import { cn } from "@/lib/utils";
import { InventoryItemStatus, InventoryItemCategory } from "@/types";
// import { updateInventoryItem } from "@/api/inventory";
// import type { UpdateInventoryItemInput } from "@/types";
@ -41,9 +42,10 @@ export interface EditInventoryItemProps {
name: string;
category: string;
status: string;
type: string;
unit: string;
quantity: number;
fetchedInventoryStatus: InventoryItemStatus[];
fetchedInventoryCategory: InventoryItemCategory[];
}
export function EditInventoryItem({
@ -51,13 +53,13 @@ export function EditInventoryItem({
name,
category,
status,
type,
unit,
quantity,
fetchedInventoryStatus,
fetchedInventoryCategory,
}: EditInventoryItemProps) {
const [open, setOpen] = useState(false);
const [itemName, setItemName] = useState(name);
const [itemType, setItemType] = useState(type);
const [itemCategory, setItemCategory] = useState(category);
const [itemQuantity, setItemQuantity] = useState(quantity);
const [itemUnit, setItemUnit] = useState(unit);
@ -119,17 +121,20 @@ export function EditInventoryItem({
</div>
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="type" className="text-right">
Type
Category
</Label>
<Select value={itemType.toLowerCase()} onValueChange={setItemType}>
<Select value={itemCategory} onValueChange={setItemCategory}>
<SelectTrigger className="col-span-3">
<SelectValue placeholder="Select type" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectLabel>Type</SelectLabel>
<SelectItem value="plantation">Plantation</SelectItem>
<SelectItem value="fertilizer">Fertilizer</SelectItem>
<SelectLabel>Category</SelectLabel>
{fetchedInventoryCategory.map((categoryItem, _) => (
<SelectItem key={categoryItem.id} value={categoryItem.name}>
{categoryItem.name}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
@ -138,35 +143,22 @@ export function EditInventoryItem({
<Label htmlFor="type" className="text-right">
Status
</Label>
<Select
value={itemStatus.toLowerCase()}
onValueChange={setItemStatus}
>
<Select value={itemStatus} onValueChange={setItemStatus}>
<SelectTrigger className="col-span-3">
<SelectValue placeholder="Select status" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectLabel>Status</SelectLabel>
<SelectItem value="in stock">In Stock</SelectItem>
<SelectItem value="low stock">Low Stock</SelectItem>
<SelectItem value="out of stock">Out Of Stock</SelectItem>
{fetchedInventoryStatus.map((statusItem, _) => (
<SelectItem key={statusItem.id} value={statusItem.name}>
{statusItem.name}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
</div>
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="category" className="text-right">
Category
</Label>
<Input
id="category"
className="col-span-3"
placeholder="e.g., Seeds, Organic"
value={itemCategory}
onChange={(e) => setItemCategory(e.target.value)}
/>
</div>
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="quantity" className="text-right">
Quantity

View File

@ -31,7 +31,11 @@ import { Search } from "lucide-react";
import { FaSort, FaSortUp, FaSortDown } from "react-icons/fa";
import { Badge } from "@/components/ui/badge";
import { fetchInventoryItems, fetchInventoryStatus } from "@/api/inventory";
import {
fetchInventoryItems,
fetchInventoryStatus,
fetchInventoryCategory,
} from "@/api/inventory";
import { AddInventoryItem } from "./add-inventory-item";
import {
EditInventoryItem,
@ -65,14 +69,33 @@ export default function InventoryPage() {
queryFn: fetchInventoryStatus,
staleTime: 60 * 1000,
});
const {
data: inventoryCategory = [],
isLoading: isLoadingCategory,
isError: isErrorCategory,
} = useQuery({
queryKey: ["inventoryCategory"],
queryFn: fetchInventoryCategory,
staleTime: 60 * 1000,
});
// console.table(inventoryItems);
console.table(inventoryStatus);
// console.table(inventoryStatus);
const [searchTerm, setSearchTerm] = useState("");
const filteredItems = useMemo(() => {
return inventoryItems
.map((item) => ({
...item,
id: String(item.id), // Convert `id` to string here
status:
inventoryStatus.find(
(statusItem) => statusItem.id.toString() === item.status
)?.name || "",
category:
inventoryCategory.find(
(categoryItem) => categoryItem.id.toString() === item.category
)?.name || "",
fetchedInventoryStatus: inventoryStatus,
fetchedInventoryCategory: inventoryCategory,
id: String(item.id),
}))
.filter((item) =>
item.name.toLowerCase().includes(searchTerm.toLowerCase())
@ -110,7 +133,11 @@ export default function InventoryPage() {
accessorKey: "edit",
header: "Edit",
cell: ({ row }: { row: { original: EditInventoryItemProps } }) => (
<EditInventoryItem {...row.original} />
<EditInventoryItem
{...row.original}
fetchedInventoryStatus={inventoryStatus}
fetchedInventoryCategory={inventoryCategory}
/>
),
enableSorting: false,
},
@ -133,13 +160,13 @@ export default function InventoryPage() {
onPaginationChange: setPagination,
});
if (isItemLoading || isLoadingStatus)
if (isItemLoading || isLoadingStatus || isLoadingCategory)
return (
<div className="flex min-h-screen items-center justify-center">
Loading...
</div>
);
if (isItemError || isErrorStatus)
if (isItemError || isErrorStatus || isErrorCategory)
return (
<div className="flex min-h-screen items-center justify-center">
Error loading inventory data.

View File

@ -63,7 +63,6 @@ export type InventoryItem = {
id: number;
name: string;
category: string;
type: string;
quantity: number;
unit: string;
lastUpdated: string;
@ -74,7 +73,15 @@ export type InventoryItemStatus = {
name: string;
};
export type CreateInventoryItemInput = Omit<InventoryItem, "id" | "lastUpdated" | "status">;
export type InventoryItemCategory = {
id: number;
name: string;
};
export type CreateInventoryItemInput = Omit<
InventoryItem,
"id" | "lastUpdated" | "status"
>;
export interface Blog {
id: number;