From e471ae9c9094aee4fd477b520936c6e0b36615a7 Mon Sep 17 00:00:00 2001 From: toanhoang Date: Mon, 3 Aug 2026 07:09:42 -0400 Subject: [PATCH] feat: add basic list+create UI for AssetCategoryAttributeDef, AssetModel, PurchaseOrder --- .../asset-category-attribute-defs/page.tsx | 256 +++++++++++++++++ src/app/asset-models/page.tsx | 222 +++++++++++++++ src/app/purchase-orders/page.tsx | 258 ++++++++++++++++++ 3 files changed, 736 insertions(+) create mode 100644 src/app/asset-category-attribute-defs/page.tsx create mode 100644 src/app/asset-models/page.tsx create mode 100644 src/app/purchase-orders/page.tsx diff --git a/src/app/asset-category-attribute-defs/page.tsx b/src/app/asset-category-attribute-defs/page.tsx new file mode 100644 index 0000000..b45f1b6 --- /dev/null +++ b/src/app/asset-category-attribute-defs/page.tsx @@ -0,0 +1,256 @@ +"use client"; + +import { useState, type FormEvent } from "react"; +import { useApiList } from "@/hooks/use-api-list"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; + +// Shape returned by GET /api/asset-category-attribute-defs — snake_case per +// this repo's API-boundary convention (see +// src/lib/asset-category-attribute-defs.ts's toRecord()). +interface AssetCategoryAttributeDefRecord { + id: string; + category_id: string; + key: string; + label: string; + data_type: "string" | "number" | "boolean" | "date"; + required: boolean; + sort_order: number; + created_at: string; +} + +// Shape returned by GET /api/asset-categories — snake_case per +// src/lib/asset-categories.ts's toRecord(). Only used here to populate the +// categoryId + + + + + {assetCategories.map((assetCategory) => ( + + {assetCategory.name} + + ))} + + + + +
+ + setKey(event.target.value)} + required + /> +
+ +
+ + setLabel(event.target.value)} + required + /> +
+ +
+ + +
+ +
+ setRequired(event.target.checked)} + className="h-4 w-4" + /> + +
+ +
+ + setSortOrder(event.target.value)} + required + /> +
+ + {submitError ?

{submitError}

: null} + + + + + + ); +} diff --git a/src/app/asset-models/page.tsx b/src/app/asset-models/page.tsx new file mode 100644 index 0000000..88622c5 --- /dev/null +++ b/src/app/asset-models/page.tsx @@ -0,0 +1,222 @@ +"use client"; + +import { useState, type FormEvent } from "react"; +import { useApiList } from "@/hooks/use-api-list"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { Textarea } from "@/components/ui/textarea"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; + +// Shape returned by GET /api/asset-models — snake_case per this repo's +// API-boundary convention (see src/lib/asset-models.ts's toRecord()). +interface AssetModelRecord { + id: string; + category_id: string; + manufacturer: string; + name: string; + specs: Record; + created_at: string; +} + +// Shape returned by GET /api/asset-categories — used only to populate the +// categoryId + + + + + {assetCategories.map((assetCategory) => ( + + {assetCategory.name} + + ))} + + + + +
+ + setManufacturer(event.target.value)} + required + /> +
+ +
+ + setName(event.target.value)} + required + /> +
+ +
+ +