feat: add fetchHarvestUnits API and integrate into inventory management

This commit is contained in:
THIS ONE IS A LITTLE BIT TRICKY KRUB 2025-04-01 18:53:18 +07:00
parent ba8f754d8d
commit bfeda8ce13
5 changed files with 80 additions and 24 deletions

12
frontend/api/harvest.ts Normal file
View File

@ -0,0 +1,12 @@
import axiosInstance from "./config";
import type { HarvestUnits } from "@/types";
export async function fetchHarvestUnits(): Promise<HarvestUnits[]> {
try {
const response = await axiosInstance.get<HarvestUnits[]>("/harvest/units");
return response.data;
} catch (error) {
console.error("Error fetching inventory status:", error);
return [];
}
}

View File

@ -1,7 +1,6 @@
import axiosInstance from "./config"; import axiosInstance from "./config";
import type { import type {
InventoryItem, InventoryItem,
CreateInventoryItemInput,
InventoryItemStatus, InventoryItemStatus,
InventoryItemCategory, InventoryItemCategory,
} from "@/types"; } from "@/types";
@ -50,7 +49,7 @@ export async function fetchInventoryItems(): Promise<InventoryItem[]> {
name: "Tomato Seeds", name: "Tomato Seeds",
category: "1", category: "1",
quantity: 500, quantity: 500,
unit: "packets", unit: "1",
lastUpdated: "2023-03-01", lastUpdated: "2023-03-01",
status: "1", status: "1",
}, },
@ -59,7 +58,7 @@ export async function fetchInventoryItems(): Promise<InventoryItem[]> {
name: "NPK Fertilizer", name: "NPK Fertilizer",
category: "3", category: "3",
quantity: 200, quantity: 200,
unit: "kg", unit: "2",
lastUpdated: "2023-03-05", lastUpdated: "2023-03-05",
status: "2", status: "2",
}, },
@ -68,7 +67,7 @@ export async function fetchInventoryItems(): Promise<InventoryItem[]> {
name: "Corn Seeds", name: "Corn Seeds",
category: "1", category: "1",
quantity: 300, quantity: 300,
unit: "packets", unit: "1",
lastUpdated: "2023-03-10", lastUpdated: "2023-03-10",
status: "3", status: "3",
}, },
@ -77,7 +76,7 @@ export async function fetchInventoryItems(): Promise<InventoryItem[]> {
name: "Organic Compost", name: "Organic Compost",
category: "3", category: "3",
quantity: 150, quantity: 150,
unit: "kg", unit: "2",
lastUpdated: "2023-03-15", lastUpdated: "2023-03-15",
status: "1", status: "1",
}, },
@ -86,7 +85,7 @@ export async function fetchInventoryItems(): Promise<InventoryItem[]> {
name: "Wheat Seeds", name: "Wheat Seeds",
category: "1", category: "1",
quantity: 250, quantity: 250,
unit: "packets", unit: "2",
lastUpdated: "2023-03-20", lastUpdated: "2023-03-20",
status: "2", status: "2",
}, },

View File

@ -18,11 +18,6 @@ import {
} from "@/components/ui/dialog"; } from "@/components/ui/dialog";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label"; import { Label } from "@/components/ui/label";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
import { import {
Select, Select,
SelectContent, SelectContent,
@ -32,8 +27,11 @@ import {
SelectTrigger, SelectTrigger,
SelectValue, SelectValue,
} from "@/components/ui/select"; } from "@/components/ui/select";
import { cn } from "@/lib/utils"; import {
import { InventoryItemStatus, InventoryItemCategory } from "@/types"; InventoryItemStatus,
InventoryItemCategory,
HarvestUnits,
} from "@/types";
// import { updateInventoryItem } from "@/api/inventory"; // import { updateInventoryItem } from "@/api/inventory";
// import type { UpdateInventoryItemInput } from "@/types"; // import type { UpdateInventoryItemInput } from "@/types";
@ -46,6 +44,7 @@ export interface EditInventoryItemProps {
quantity: number; quantity: number;
fetchedInventoryStatus: InventoryItemStatus[]; fetchedInventoryStatus: InventoryItemStatus[];
fetchedInventoryCategory: InventoryItemCategory[]; fetchedInventoryCategory: InventoryItemCategory[];
fetchedHarvestUnits: HarvestUnits[];
} }
export function EditInventoryItem({ export function EditInventoryItem({
@ -57,6 +56,7 @@ export function EditInventoryItem({
quantity, quantity,
fetchedInventoryStatus, fetchedInventoryStatus,
fetchedInventoryCategory, fetchedInventoryCategory,
fetchedHarvestUnits,
}: EditInventoryItemProps) { }: EditInventoryItemProps) {
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const [itemName, setItemName] = useState(name); const [itemName, setItemName] = useState(name);
@ -172,16 +172,24 @@ export function EditInventoryItem({
/> />
</div> </div>
<div className="grid grid-cols-4 items-center gap-4"> <div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="unit" className="text-right"> <Label htmlFor="type" className="text-right">
Unit Unit
</Label> </Label>
<Input <Select value={itemUnit} onValueChange={setItemUnit}>
id="unit" <SelectTrigger className="col-span-3">
className="col-span-3" <SelectValue placeholder="Select status" />
placeholder="e.g., kg, packets" </SelectTrigger>
value={itemUnit} <SelectContent>
onChange={(e) => setItemUnit(e.target.value)} <SelectGroup>
/> <SelectLabel>Unit</SelectLabel>
{fetchedHarvestUnits.map((unit, _) => (
<SelectItem key={unit.id} value={unit.name}>
{unit.name}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
</div> </div>
</div> </div>
<DialogFooter> <DialogFooter>

View File

@ -29,6 +29,7 @@ import {
} from "@/components/ui/pagination"; } from "@/components/ui/pagination";
import { Search } from "lucide-react"; import { Search } from "lucide-react";
import { FaSort, FaSortUp, FaSortDown } from "react-icons/fa"; import { FaSort, FaSortUp, FaSortDown } from "react-icons/fa";
import { fetchHarvestUnits } from "@/api/harvest";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";
import { import {
@ -49,7 +50,8 @@ export default function InventoryPage() {
pageIndex: 0, pageIndex: 0,
pageSize: 10, pageSize: 10,
}); });
//////////////////////////////
// query the necessary data for edit and etc.
const { const {
data: inventoryItems = [], data: inventoryItems = [],
isLoading: isItemLoading, isLoading: isItemLoading,
@ -78,6 +80,16 @@ export default function InventoryPage() {
queryFn: fetchInventoryCategory, queryFn: fetchInventoryCategory,
staleTime: 60 * 1000, staleTime: 60 * 1000,
}); });
const {
data: harvestUnits = [],
isLoading: isLoadingHarvestUnits,
isError: isErrorHarvestUnits,
} = useQuery({
queryKey: ["harvestUnits"],
queryFn: fetchHarvestUnits,
staleTime: 60 * 1000,
});
//////////////////////////////
// console.table(inventoryItems); // console.table(inventoryItems);
// console.table(inventoryStatus); // console.table(inventoryStatus);
const [searchTerm, setSearchTerm] = useState(""); const [searchTerm, setSearchTerm] = useState("");
@ -93,8 +105,12 @@ export default function InventoryPage() {
inventoryCategory.find( inventoryCategory.find(
(categoryItem) => categoryItem.id.toString() === item.category (categoryItem) => categoryItem.id.toString() === item.category
)?.name || "", )?.name || "",
unit:
harvestUnits.find((unit) => unit.id.toString() === item.unit)?.name ||
"",
fetchedInventoryStatus: inventoryStatus, fetchedInventoryStatus: inventoryStatus,
fetchedInventoryCategory: inventoryCategory, fetchedInventoryCategory: inventoryCategory,
fetchedHarvestUnits: harvestUnits,
id: String(item.id), id: String(item.id),
})) }))
.filter((item) => .filter((item) =>
@ -102,6 +118,8 @@ export default function InventoryPage() {
); );
}, [inventoryItems, searchTerm]); }, [inventoryItems, searchTerm]);
// prepare columns for table
const columns = [ const columns = [
{ accessorKey: "name", header: "Name" }, { accessorKey: "name", header: "Name" },
{ accessorKey: "category", header: "Category" }, { accessorKey: "category", header: "Category" },
@ -159,14 +177,29 @@ export default function InventoryPage() {
onSortingChange: setSorting, onSortingChange: setSorting,
onPaginationChange: setPagination, onPaginationChange: setPagination,
}); });
const loadingStates = [
isItemLoading,
isLoadingStatus,
isLoadingCategory,
isLoadingHarvestUnits,
];
const errorStates = [
isItemError,
isErrorStatus,
isErrorCategory,
isErrorHarvestUnits,
];
if (isItemLoading || isLoadingStatus || isLoadingCategory) const isLoading = loadingStates.some((loading) => loading);
const isError = errorStates.some((error) => error);
if (isLoading)
return ( return (
<div className="flex min-h-screen items-center justify-center"> <div className="flex min-h-screen items-center justify-center">
Loading... Loading...
</div> </div>
); );
if (isItemError || isErrorStatus || isErrorCategory) if (isError)
return ( return (
<div className="flex min-h-screen items-center justify-center"> <div className="flex min-h-screen items-center justify-center">
Error loading inventory data. Error loading inventory data.

View File

@ -77,6 +77,10 @@ export type InventoryItemCategory = {
id: number; id: number;
name: string; name: string;
}; };
export type HarvestUnits = {
id: number;
name: string;
};
export type CreateInventoryItemInput = Omit< export type CreateInventoryItemInput = Omit<
InventoryItem, InventoryItem,