193 lines
5.8 KiB
TypeScript
193 lines
5.8 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from "react";
|
|
import { Button } from "@/components/ui/button";
|
|
import { Input } from "@/components/ui/input";
|
|
import { Label } from "@/components/ui/label";
|
|
import { Badge } from "@/components/ui/badge";
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
} from "@/components/ui/dialog";
|
|
import {
|
|
Select,
|
|
SelectContent,
|
|
SelectItem,
|
|
SelectTrigger,
|
|
SelectValue,
|
|
} from "@/components/ui/select";
|
|
import { Plus, X } from "lucide-react";
|
|
import { cn } from "@/lib/utils";
|
|
import type { Category } from "@/lib/types";
|
|
import { categoryColors } from "./constants";
|
|
|
|
interface CategoryFormData {
|
|
name: string;
|
|
color: string;
|
|
keywords: string[];
|
|
parentId: string | null;
|
|
}
|
|
|
|
interface CategoryEditDialogProps {
|
|
open: boolean;
|
|
onOpenChange: (open: boolean) => void;
|
|
editingCategory: Category | null;
|
|
formData: CategoryFormData;
|
|
onFormDataChange: (data: CategoryFormData) => void;
|
|
parentCategories: Category[];
|
|
onSave: () => void;
|
|
}
|
|
|
|
export function CategoryEditDialog({
|
|
open,
|
|
onOpenChange,
|
|
editingCategory,
|
|
formData,
|
|
onFormDataChange,
|
|
parentCategories,
|
|
onSave,
|
|
}: CategoryEditDialogProps) {
|
|
const [newKeyword, setNewKeyword] = useState("");
|
|
|
|
const addKeyword = () => {
|
|
if (
|
|
newKeyword.trim() &&
|
|
!formData.keywords.includes(newKeyword.trim().toLowerCase())
|
|
) {
|
|
onFormDataChange({
|
|
...formData,
|
|
keywords: [...formData.keywords, newKeyword.trim().toLowerCase()],
|
|
});
|
|
setNewKeyword("");
|
|
}
|
|
};
|
|
|
|
const removeKeyword = (keyword: string) => {
|
|
onFormDataChange({
|
|
...formData,
|
|
keywords: formData.keywords.filter((k) => k !== keyword),
|
|
});
|
|
};
|
|
|
|
return (
|
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
<DialogContent className="sm:max-w-md">
|
|
<DialogHeader>
|
|
<DialogTitle>
|
|
{editingCategory ? "Modifier la catégorie" : "Nouvelle catégorie"}
|
|
</DialogTitle>
|
|
</DialogHeader>
|
|
<div className="space-y-4">
|
|
{/* Catégorie parente */}
|
|
<div className="space-y-2">
|
|
<Label>Catégorie parente</Label>
|
|
<Select
|
|
value={formData.parentId || "none"}
|
|
onValueChange={(value) =>
|
|
onFormDataChange({
|
|
...formData,
|
|
parentId: value === "none" ? null : value,
|
|
})
|
|
}
|
|
>
|
|
<SelectTrigger>
|
|
<SelectValue placeholder="Aucune (catégorie principale)" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="none">
|
|
Aucune (catégorie principale)
|
|
</SelectItem>
|
|
{parentCategories
|
|
.filter((p) => p.id !== editingCategory?.id)
|
|
.map((parent) => (
|
|
<SelectItem key={parent.id} value={parent.id}>
|
|
<div className="flex items-center gap-2">
|
|
<div
|
|
className="w-3 h-3 rounded-full"
|
|
style={{ backgroundColor: parent.color }}
|
|
/>
|
|
{parent.name}
|
|
</div>
|
|
</SelectItem>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
|
|
{/* Nom */}
|
|
<div className="space-y-2">
|
|
<Label>Nom</Label>
|
|
<Input
|
|
value={formData.name}
|
|
onChange={(e) =>
|
|
onFormDataChange({ ...formData, name: e.target.value })
|
|
}
|
|
placeholder="Ex: Alimentation"
|
|
/>
|
|
</div>
|
|
|
|
{/* Couleur */}
|
|
<div className="space-y-2">
|
|
<Label>Couleur</Label>
|
|
<div className="flex flex-wrap gap-2">
|
|
{categoryColors.map((color) => (
|
|
<button
|
|
key={color}
|
|
onClick={() => onFormDataChange({ ...formData, color })}
|
|
className={cn(
|
|
"w-8 h-8 rounded-full transition-transform",
|
|
formData.color === color &&
|
|
"ring-2 ring-offset-2 ring-primary scale-110"
|
|
)}
|
|
style={{ backgroundColor: color }}
|
|
/>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Mots-clés */}
|
|
<div className="space-y-2">
|
|
<Label>Mots-clés pour la catégorisation automatique</Label>
|
|
<div className="flex gap-2">
|
|
<Input
|
|
value={newKeyword}
|
|
onChange={(e) => setNewKeyword(e.target.value)}
|
|
placeholder="Ajouter un mot-clé"
|
|
onKeyDown={(e) =>
|
|
e.key === "Enter" && (e.preventDefault(), addKeyword())
|
|
}
|
|
/>
|
|
<Button type="button" onClick={addKeyword} size="icon">
|
|
<Plus className="w-4 h-4" />
|
|
</Button>
|
|
</div>
|
|
<div className="flex flex-wrap gap-1 mt-2 max-h-32 overflow-y-auto">
|
|
{formData.keywords.map((keyword) => (
|
|
<Badge key={keyword} variant="secondary" className="gap-1">
|
|
{keyword}
|
|
<button onClick={() => removeKeyword(keyword)}>
|
|
<X className="w-3 h-3" />
|
|
</button>
|
|
</Badge>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Actions */}
|
|
<div className="flex justify-end gap-2">
|
|
<Button variant="outline" onClick={() => onOpenChange(false)}>
|
|
Annuler
|
|
</Button>
|
|
<Button onClick={onSave} disabled={!formData.name.trim()}>
|
|
{editingCategory ? "Enregistrer" : "Créer"}
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</DialogContent>
|
|
</Dialog>
|
|
);
|
|
}
|
|
|