From 02d219a5022f6e2b31d8f1b2d10ca1d1eb4e9ca4 Mon Sep 17 00:00:00 2001 From: Sosokker Date: Fri, 7 Mar 2025 02:50:13 +0700 Subject: [PATCH] feat: add dummy api for inventory --- frontend/api/inventory.ts | 97 +++++++++++++++++++ .../inventory/add-inventory-item.tsx | 70 +++++++++++-- frontend/app/(sidebar)/inventory/page.tsx | 84 +++++----------- frontend/types.ts | 13 +++ 4 files changed, 199 insertions(+), 65 deletions(-) create mode 100644 frontend/api/inventory.ts diff --git a/frontend/api/inventory.ts b/frontend/api/inventory.ts new file mode 100644 index 0000000..7d8982d --- /dev/null +++ b/frontend/api/inventory.ts @@ -0,0 +1,97 @@ +import axiosInstance from "./config"; +import type { InventoryItem, CreateInventoryItemInput } 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 fetchInventoryItems(): Promise { + try { + const response = await axiosInstance.get("/api/inventory"); + return response.data; + } catch (error) { + // Fallback dummy data + return [ + { + id: 1, + name: "Tomato Seeds", + category: "Seeds", + type: "Plantation", + quantity: 500, + unit: "packets", + lastUpdated: "2023-03-01", + status: "In Stock", + }, + { + id: 2, + name: "NPK Fertilizer", + category: "Fertilizer", + type: "Fertilizer", + quantity: 200, + unit: "kg", + lastUpdated: "2023-03-05", + status: "Low Stock", + }, + { + id: 3, + name: "Corn Seeds", + category: "Seeds", + type: "Plantation", + quantity: 300, + unit: "packets", + lastUpdated: "2023-03-10", + status: "In Stock", + }, + { + id: 4, + name: "Organic Compost", + category: "Fertilizer", + type: "Fertilizer", + quantity: 150, + unit: "kg", + lastUpdated: "2023-03-15", + status: "In Stock", + }, + { + id: 5, + name: "Wheat Seeds", + category: "Seeds", + type: "Plantation", + quantity: 250, + unit: "packets", + lastUpdated: "2023-03-20", + status: "In Stock", + }, + ]; + } +} + +/** + * Simulates creating a new inventory item. + * Uses axios POST and if unavailable, returns a simulated response. + * + * Note: The function accepts all fields except id, lastUpdated, and status. + */ +export async function createInventoryItem( + item: Omit +): Promise { + // Simulate network delay + await new Promise((resolve) => setTimeout(resolve, 500)); + try { + const response = await axiosInstance.post("/api/inventory", item); + return response.data; + } catch (error) { + // Simulate successful creation if API endpoint is not available + return { + 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(), + status: "In Stock", + }; + } +} diff --git a/frontend/app/(sidebar)/inventory/add-inventory-item.tsx b/frontend/app/(sidebar)/inventory/add-inventory-item.tsx index 34aea60..448097c 100644 --- a/frontend/app/(sidebar)/inventory/add-inventory-item.tsx +++ b/frontend/app/(sidebar)/inventory/add-inventory-item.tsx @@ -3,6 +3,7 @@ import { useState } from "react"; import { CalendarIcon } from "lucide-react"; import { format } from "date-fns"; +import { useMutation, useQueryClient } from "@tanstack/react-query"; import { Button } from "@/components/ui/button"; import { Calendar } from "@/components/ui/calendar"; @@ -28,10 +29,47 @@ import { SelectValue, } from "@/components/ui/select"; import { cn } from "@/lib/utils"; +import { createInventoryItem } from "@/api/inventory"; +import type { CreateInventoryItemInput } from "@/types"; export function AddInventoryItem() { - const [date, setDate] = useState(); + const [date, setDate] = useState(); const [open, setOpen] = useState(false); + const [itemName, setItemName] = useState(""); + const [itemType, setItemType] = useState(""); + const [itemCategory, setItemCategory] = useState(""); + const [itemQuantity, setItemQuantity] = useState(0); + const [itemUnit, setItemUnit] = useState(""); + + const queryClient = useQueryClient(); + + const mutation = useMutation({ + mutationFn: (item: CreateInventoryItemInput) => createInventoryItem(item), + onSuccess: () => { + // Invalidate queries to refresh inventory data. + queryClient.invalidateQueries({ queryKey: ["inventoryItems"] }); + // Reset form fields and close dialog. + setItemName(""); + setItemType(""); + setItemCategory(""); + setItemQuantity(0); + setItemUnit(""); + setDate(undefined); + setOpen(false); + }, + }); + + const handleSave = () => { + // Basic validation (you can extend this as needed) + if (!itemName || !itemType || !itemCategory || !itemUnit) return; + mutation.mutate({ + name: itemName, + type: itemType, + category: itemCategory, + quantity: itemQuantity, + unit: itemUnit, + }); + }; return ( @@ -48,13 +86,13 @@ export function AddInventoryItem() { - + setItemName(e.target.value)} />
- @@ -71,19 +109,37 @@ export function AddInventoryItem() { - + setItemCategory(e.target.value)} + />
- + setItemQuantity(Number(e.target.value))} + />
- + setItemUnit(e.target.value)} + />
- diff --git a/frontend/app/(sidebar)/inventory/page.tsx b/frontend/app/(sidebar)/inventory/page.tsx index eb6fab5..290461b 100644 --- a/frontend/app/(sidebar)/inventory/page.tsx +++ b/frontend/app/(sidebar)/inventory/page.tsx @@ -1,6 +1,7 @@ "use client"; import { useState } from "react"; +import { useQuery } from "@tanstack/react-query"; import { Calendar, ChevronDown, Plus, Search } from "lucide-react"; import { Button } from "@/components/ui/button"; @@ -12,66 +13,36 @@ import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover import { Calendar as CalendarComponent } from "@/components/ui/calendar"; import { Badge } from "@/components/ui/badge"; +import { fetchInventoryItems } from "@/api/inventory"; +import { AddInventoryItem } from "./add-inventory-item"; + export default function InventoryPage() { const [date, setDate] = useState(); const [inventoryType, setInventoryType] = useState("all"); const [currentPage, setCurrentPage] = useState(1); - // Sample inventory data - const inventoryItems = [ - { - id: 1, - name: "Tomato Seeds", - category: "Seeds", - type: "Plantation", - quantity: 500, - unit: "packets", - lastUpdated: "2023-03-01", - status: "In Stock", - }, - { - id: 2, - name: "NPK Fertilizer", - category: "Fertilizer", - type: "Fertilizer", - quantity: 200, - unit: "kg", - lastUpdated: "2023-03-05", - status: "Low Stock", - }, - { - id: 3, - name: "Corn Seeds", - category: "Seeds", - type: "Plantation", - quantity: 300, - unit: "packets", - lastUpdated: "2023-03-10", - status: "In Stock", - }, - { - id: 4, - name: "Organic Compost", - category: "Fertilizer", - type: "Fertilizer", - quantity: 150, - unit: "kg", - lastUpdated: "2023-03-15", - status: "In Stock", - }, - { - id: 5, - name: "Wheat Seeds", - category: "Seeds", - type: "Plantation", - quantity: 250, - unit: "packets", - lastUpdated: "2023-03-20", - status: "In Stock", - }, - ]; + // Fetch inventory items using react-query. + const { + data: inventoryItems, + isLoading, + isError, + } = useQuery({ + queryKey: ["inventoryItems"], + queryFn: fetchInventoryItems, + staleTime: 60 * 1000, + }); - // Filter items based on selected type + if (isLoading) { + return
Loading...
; + } + + if (isError || !inventoryItems) { + return ( +
Error loading inventory data.
+ ); + } + + // Filter items based on selected type. const filteredItems = inventoryType === "all" ? inventoryItems @@ -81,7 +52,6 @@ export default function InventoryPage() { return (
- {/* Main content */}

Inventory

@@ -130,9 +100,7 @@ export default function InventoryPage() {
- +
diff --git a/frontend/types.ts b/frontend/types.ts index e08f7f7..60be4ef 100644 --- a/frontend/types.ts +++ b/frontend/types.ts @@ -58,3 +58,16 @@ export interface User { Avatar: string; IsActive: boolean; } + +export type InventoryItem = { + id: number; + name: string; + category: string; + type: string; + quantity: number; + unit: string; + lastUpdated: string; + status: string; +}; + +export type CreateInventoryItemInput = Omit;