Update frontend to allow categories
This commit is contained in:
@@ -8,7 +8,9 @@ import { Textarea } from "@/components/ui/textarea";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectLabel,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
@@ -21,10 +23,10 @@ import { Plus } from "lucide-react";
|
||||
import { apiRequest } from "@/lib/storeHelper";
|
||||
|
||||
type CategorySelectProps = {
|
||||
categories: { _id: string; name: string }[];
|
||||
categories: { _id: string; name: string; parentId?: string }[];
|
||||
value: string;
|
||||
setProductData: React.Dispatch<React.SetStateAction<ProductData>>;
|
||||
onAddCategory: (newCategory: { _id: string; name: string }) => void;
|
||||
onAddCategory: (newCategory: { _id: string; name: string; parentId?: string }) => void;
|
||||
};
|
||||
|
||||
export const ProductModal: React.FC<ProductModalProps> = ({
|
||||
@@ -101,7 +103,7 @@ export const ProductModal: React.FC<ProductModalProps> = ({
|
||||
onClose();
|
||||
};
|
||||
|
||||
const handleAddCategory = (newCategory: { _id: string; name: string }) => {
|
||||
const handleAddCategory = (newCategory: { _id: string; name: string; parentId?: string }) => {
|
||||
setLocalCategories((prev) => [...prev, newCategory]);
|
||||
};
|
||||
|
||||
@@ -167,9 +169,9 @@ export const ProductModal: React.FC<ProductModalProps> = ({
|
||||
const ProductBasicInfo: React.FC<{
|
||||
productData: ProductData;
|
||||
handleChange: (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => void;
|
||||
categories: { _id: string; name: string }[];
|
||||
categories: { _id: string; name: string; parentId?: string }[];
|
||||
setProductData: React.Dispatch<React.SetStateAction<ProductData>>;
|
||||
onAddCategory: (newCategory: { _id: string; name: string }) => void;
|
||||
onAddCategory: (newCategory: { _id: string; name: string; parentId?: string }) => void;
|
||||
}> = ({ productData, handleChange, categories, setProductData, onAddCategory }) => (
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
@@ -205,6 +207,7 @@ const ProductBasicInfo: React.FC<{
|
||||
<UnitTypeSelect
|
||||
value={productData.unitType}
|
||||
setProductData={setProductData}
|
||||
categories={categories}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
@@ -213,80 +216,65 @@ const CategorySelect: React.FC<CategorySelectProps> = ({
|
||||
categories,
|
||||
value,
|
||||
setProductData,
|
||||
onAddCategory,
|
||||
}) => {
|
||||
const [isAddingCategory, setIsAddingCategory] = useState(false);
|
||||
const [newCategoryName, setNewCategoryName] = useState("");
|
||||
const [selectedMainCategory, setSelectedMainCategory] = useState<string>("");
|
||||
|
||||
const handleAddCategory = async () => {
|
||||
if (!newCategoryName.trim()) {
|
||||
toast.error("Category name cannot be empty");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await apiRequest("/categories", "POST", { name: newCategoryName });
|
||||
const newCategory = response.data;
|
||||
setProductData((prev) => ({ ...prev, category: newCategory._id }));
|
||||
onAddCategory(newCategory);
|
||||
setIsAddingCategory(false);
|
||||
setNewCategoryName("");
|
||||
toast.success("New category added successfully");
|
||||
} catch (error) {
|
||||
console.error("Failed to add new category:", error);
|
||||
toast.error("Failed to add new category");
|
||||
}
|
||||
};
|
||||
// Get root categories (those without parentId)
|
||||
const rootCategories = categories.filter(cat => !cat.parentId);
|
||||
|
||||
// Get subcategories for a given parent
|
||||
const getSubcategories = (parentId: string) =>
|
||||
categories.filter(cat => cat.parentId === parentId);
|
||||
|
||||
return (
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">Category</label>
|
||||
<div className="flex items-center space-x-2">
|
||||
{isAddingCategory ? (
|
||||
<Input
|
||||
value={newCategoryName}
|
||||
onChange={(e) => setNewCategoryName(e.target.value)}
|
||||
placeholder="New category name"
|
||||
className="flex-grow h-9 text-sm"
|
||||
/>
|
||||
) : (
|
||||
<div className="space-y-2">
|
||||
{/* Main Category Select */}
|
||||
<Select
|
||||
value={selectedMainCategory}
|
||||
onValueChange={(val) => {
|
||||
setSelectedMainCategory(val);
|
||||
setProductData((prev) => ({ ...prev, category: "" }));
|
||||
}}
|
||||
>
|
||||
<SelectTrigger className="h-9 text-sm">
|
||||
<SelectValue placeholder="Select main category..." />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="uncategorized">Select main category...</SelectItem>
|
||||
{rootCategories.map((cat) => (
|
||||
<SelectItem key={cat._id} value={cat._id}>
|
||||
{cat.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
|
||||
{/* Subcategory Select */}
|
||||
{selectedMainCategory && selectedMainCategory !== "uncategorized" && (
|
||||
<Select
|
||||
value={value || "placeholder"}
|
||||
value={value || "uncategorized"}
|
||||
onValueChange={(val) =>
|
||||
setProductData((prev) => ({
|
||||
...prev,
|
||||
category: val === "placeholder" ? "" : val,
|
||||
category: val === "uncategorized" ? "" : val,
|
||||
}))
|
||||
}
|
||||
>
|
||||
<SelectTrigger className={"h-9 text-sm"}>
|
||||
<SelectValue placeholder="Select category..." />
|
||||
<SelectTrigger className="h-9 text-sm">
|
||||
<SelectValue placeholder="Select subcategory (optional)..." />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="placeholder">Select category...</SelectItem>
|
||||
{categories.map((cat) => (
|
||||
<SelectItem key={cat._id} value={cat._id}>
|
||||
{cat.name}
|
||||
<SelectItem value="uncategorized">No subcategory</SelectItem>
|
||||
{getSubcategories(selectedMainCategory).map((subCat) => (
|
||||
<SelectItem key={subCat._id} value={subCat._id}>
|
||||
{subCat.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
)}
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
if (isAddingCategory) {
|
||||
handleAddCategory();
|
||||
} else {
|
||||
setIsAddingCategory(true);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Plus className="w-4 h-4 mr-1" />
|
||||
{isAddingCategory ? "Save" : "Add"}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -295,7 +283,8 @@ const CategorySelect: React.FC<CategorySelectProps> = ({
|
||||
const UnitTypeSelect: React.FC<{
|
||||
value: string;
|
||||
setProductData: React.Dispatch<React.SetStateAction<ProductData>>;
|
||||
}> = ({ value, setProductData }) => (
|
||||
categories: { _id: string; name: string; parentId?: string }[];
|
||||
}> = ({ value, setProductData, categories }) => (
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">Unit Type</label>
|
||||
<div className="flex items-center space-x-2">
|
||||
|
||||
Reference in New Issue
Block a user