Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 14 additions & 14 deletions new-frontend/src/components/search-bar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@ import { Search } from "lucide-react";
import { Input } from "../ui/input";

export const SearchBar = ({
value,
onChange,
value,
onChange,
}: {
value: string;
onChange: (value: string) => void;
value: string;
onChange: (value: string) => void;
}) => (
<div className="relative max-w-sm">
<Search className="absolute left-2 top-2.5 h-4 w-4 text-muted-foreground" />
<Input
placeholder="Search locations..."
value={value}
onChange={(e) => onChange(e.target.value)}
className="pl-8"
/>
</div>
);
<div className="relative max-w-sm">
<Search className="absolute left-2 top-2.5 h-4 w-4 text-muted-foreground" />
<Input
placeholder="Search locations..."
value={value}
onChange={(e) => onChange(e.target.value)}
className="pl-8 bg-white"
/>
</div>
);
Original file line number Diff line number Diff line change
Expand Up @@ -224,56 +224,22 @@ const MoveDialog: React.FC<MoveDialogProps> = ({
/>
</div>
</div>
<div className="mt-2 p-2 bg-blue-50 rounded-md">
<h4 className="text-sm font-medium mb-1">
Selected Location Path:
</h4>
{selectedLocations.some(Boolean) ? (
<div className="text-sm">
{selectedLocations.filter(Boolean).map((locId, idx) => {
let locationName = "Unknown";
if (idx === 0) {
locationName = getLocationNameById(locId, "");
} else if (idx === 1) {
locationName = getLocationNameById(
locId,
selectedLocations[0],
);
} else if (idx === 2) {
locationName = getLocationNameById(
locId,
selectedLocations[1],
);
}
return (
<div key={`path-${idx}`} className="flex items-center">
{idx > 0 && <span className="mx-1">→</span>}
<span className="truncate">{locationName}</span>
</div>
);
})}
</div>
) : (
<div className="text-sm text-gray-500">
No location selected yet
</div>
)}
</div>
</div>

<DialogFooter className="mt-4">
<DialogFooter className="mt-4 flex flex-row space-x-2">
<Button
variant="outline"
variant="destructive"
onClick={() => onOpenChange(false)}
className="mr-auto"
className="flex-1"
>
Cancel
Cancel
</Button>
<Button
onClick={handleConfirm}
disabled={!selectedLocations.some(Boolean) || isProcessing}
className="flex-1"
>
{isProcessing ? "Processing..." : "Done"}
{isProcessing ? "Processing..." : "Done"}
</Button>
</DialogFooter>
</DialogContent>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import { useEffect, useState } from "react";
import type { Category } from "@/types/category";
import { Card, CardContent } from "@/components/ui/card";
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogDescription,
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogDescription,
} from "@/components/ui/dialog";
import { toast } from "@/hooks/use-toast";
import CategoryForm, { CategoryFormProps } from "./components/category-form";
Expand All @@ -18,131 +18,135 @@ import { useCategories } from "./hooks/use-categories";
import { getAllIcons } from "@/lib/iconLoader";

const CategoryManagement = () => {
const {
categories,
isLoading,
createMutation,
updateMutation,
deleteMutation,
} = useCategories();
const [expandedCategories, setExpandedCategories] = useState<Set<string>>(new Set());
const sortedCategories = [...categories].sort((a, b) => a.name.localeCompare(b.name));
const [globalFilter, setGlobalFilter] = useState("");
const [isDialogOpen, setIsDialogOpen] = useState(false);
const [selectedCategory, setSelectedCategory] = useState<Category | null>(null);


const handleSubmit: CategoryFormProps["onSubmit"] = async (data) => {
try {
if (selectedCategory) {
await updateMutation.mutateAsync({
id: selectedCategory.category_id,
data,
});
} else {
await createMutation.mutateAsync(data);
}
} catch (error) {
console.error('Form submission error:', error);
}
handleClose();
};

const handleDelete = (id: string) => {
// Check if category has any children
const hasChildren = categories.some(category => category.parent_id === id);

if (hasChildren) {
toast({
title: "Cannot Delete",
description: "This category has sub-categories. Please delete or reassign them first.",
variant: "destructive"
});
return;
}

if (window.confirm("Are you sure you want to delete this category?")) {
deleteMutation.mutate(id);
}
};

const handleClose = () => {
setIsDialogOpen(false);
setSelectedCategory(null);

};
const {
categories,
isLoading,
createMutation,
updateMutation,
deleteMutation,
} = useCategories();
const [expandedCategories, setExpandedCategories] = useState<Set<string>>(
new Set(),
);
const sortedCategories = [...categories].sort((a, b) =>
a.name.localeCompare(b.name),
);
const [globalFilter, setGlobalFilter] = useState("");
const [isDialogOpen, setIsDialogOpen] = useState(false);
const [selectedCategory, setSelectedCategory] = useState<Category | null>(
null,
);

const handleSubmit: CategoryFormProps["onSubmit"] = async (data) => {
try {
if (selectedCategory) {
await updateMutation.mutateAsync({
id: selectedCategory.category_id,
data,
});
} else {
await createMutation.mutateAsync(data);
}
} catch (error) {
console.error("Form submission error:", error);
}
handleClose();
};

const handleDelete = (id: string) => {
// Check if category has any children
const hasChildren = categories.some(
(category) => category.parent_id === id,
);

const handleEdit = (category: Category) => {
setSelectedCategory(category); // Update selectedCategory to the full Category
setIsDialogOpen(true); // Open the dialog to edit
if (hasChildren) {
toast({
title: "Cannot Delete",
description:
"This category has sub-categories. Please delete or reassign them first.",
variant: "destructive",
});
return;
}

if (window.confirm("Are you sure you want to delete this category?")) {
deleteMutation.mutate(id);
}
};

const handleClose = () => {
setIsDialogOpen(false);
setSelectedCategory(null);
};

const handleEdit = (category: Category) => {
setSelectedCategory(category); // Update selectedCategory to the full Category
setIsDialogOpen(true); // Open the dialog to edit
};

useEffect(() => {
const fetchIcons = async () => {
getAllIcons();
};

useEffect(() => {
const fetchIcons = async () => {
getAllIcons();

};
fetchIcons();
}, []);


if (isLoading) return <div>Loading...</div>;

return (
<>
<div>
<div className="flex items-center justify-between mb-4">
<div className="relative max-w-sm">
<Search className="absolute left-2 top-2.5 h-4 w-4 text-muted-foreground" />
<Input
placeholder="Search categories..."
value={globalFilter}
onChange={(e) => setGlobalFilter(e.target.value)}
className="pl-8"
/>
</div>
<Button onClick={() => setIsDialogOpen(true)}>
<Plus className="mr-2 h-4 w-4" />
Add Category
</Button>
</div>

<CategoriesTable
data={sortedCategories}
filter={globalFilter}
onEdit={handleEdit}
onDelete={handleDelete}
expandedCategories={expandedCategories}
setExpandedCategories={setExpandedCategories}
/>
</div>
<Dialog open={isDialogOpen} onOpenChange={handleClose}>
<DialogContent className="max-w-4xl">
<DialogHeader>
<DialogTitle>
{selectedCategory ? "Edit Category" : "Create New Category"}
</DialogTitle>
<DialogDescription>
{selectedCategory
? "Edit the details of the existing category"
: "Add a new category to the system"}
</DialogDescription>
</DialogHeader>
<CategoryForm
categories={categories.filter(
(category) => category.category_id !== selectedCategory?.category_id
)}
onSubmit={handleSubmit}
initialData={selectedCategory}
isLoading={createMutation.isPending || updateMutation.isPending}
onClose={handleClose}
/>
</DialogContent>

</Dialog>
</>
);
fetchIcons();
}, []);

if (isLoading) return <div>Loading...</div>;

return (
<>
<div>
<div className="flex items-center justify-between mb-4">
<div className="relative max-w-sm">
<Search className="absolute left-2 top-2.5 h-4 w-4 text-muted-foreground" />
<Input
placeholder="Search categories..."
value={globalFilter}
onChange={(e) => setGlobalFilter(e.target.value)}
className="pl-8 bg-white"
/>
</div>
<Button onClick={() => setIsDialogOpen(true)}>
<Plus className="mr-2 h-4 w-4" />
Add Category
</Button>
</div>

<CategoriesTable
data={sortedCategories}
filter={globalFilter}
onEdit={handleEdit}
onDelete={handleDelete}
expandedCategories={expandedCategories}
setExpandedCategories={setExpandedCategories}
/>
</div>
<Dialog open={isDialogOpen} onOpenChange={handleClose}>
<DialogContent className="max-w-4xl">
<DialogHeader>
<DialogTitle>
{selectedCategory ? "Edit Category" : "Create New Category"}
</DialogTitle>
<DialogDescription>
{selectedCategory
? "Edit the details of the existing category"
: "Add a new category to the system"}
</DialogDescription>
</DialogHeader>
<CategoryForm
categories={categories.filter(
(category) =>
category.category_id !== selectedCategory?.category_id,
)}
onSubmit={handleSubmit}
initialData={selectedCategory}
isLoading={createMutation.isPending || updateMutation.isPending}
onClose={handleClose}
/>
</DialogContent>
</Dialog>
</>
);
};

export default CategoryManagement;

Loading