feat: add full CRUD management for product categories in admin panel
This commit is contained in:
160
shop/components/admin/category-dialog.tsx
Normal file
160
shop/components/admin/category-dialog.tsx
Normal file
@@ -0,0 +1,160 @@
|
||||
'use client'
|
||||
|
||||
import { useState } from 'react'
|
||||
import { useForm } from 'react-hook-form'
|
||||
import { zodResolver } from '@hookform/resolvers/zod'
|
||||
import * as z from 'zod'
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from '@/components/ui/dialog'
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from '@/components/ui/form'
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { createCategory, updateCategory } from '@/lib/actions/products'
|
||||
import { Category } from '@/lib/types'
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue
|
||||
} from '@/components/ui/select'
|
||||
import { Cloud, Utensils, HardDrive, Package } from 'lucide-react'
|
||||
|
||||
const categorySchema = z.object({
|
||||
name: z.string().min(2, 'Name muss mindestens 2 Zeichen lang sein'),
|
||||
description: z.string().optional(),
|
||||
icon: z.string().default('Package'),
|
||||
})
|
||||
|
||||
type CategoryFormValues = z.infer<typeof categorySchema>
|
||||
|
||||
export function CategoryDialog({
|
||||
children,
|
||||
category
|
||||
}: {
|
||||
children: React.ReactNode,
|
||||
category?: Category
|
||||
}) {
|
||||
const [open, setOpen] = useState(false)
|
||||
|
||||
const form = useForm<CategoryFormValues>({
|
||||
resolver: zodResolver(categorySchema) as any,
|
||||
defaultValues: {
|
||||
name: category?.name || '',
|
||||
description: category?.description || '',
|
||||
icon: category?.icon || 'Package',
|
||||
},
|
||||
})
|
||||
|
||||
async function onSubmit(values: CategoryFormValues) {
|
||||
try {
|
||||
if (category) {
|
||||
await updateCategory(category.id, values)
|
||||
} else {
|
||||
await createCategory(values)
|
||||
}
|
||||
setOpen(false)
|
||||
form.reset()
|
||||
} catch (error) {
|
||||
console.error('Error saving category:', error)
|
||||
}
|
||||
}
|
||||
|
||||
const icons = [
|
||||
{ name: 'Cloud', Icon: Cloud },
|
||||
{ name: 'Utensils', Icon: Utensils },
|
||||
{ name: 'HardDrive', Icon: HardDrive },
|
||||
{ name: 'Package', Icon: Package },
|
||||
]
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogTrigger asChild>{children}</DialogTrigger>
|
||||
<DialogContent className="glass-dark border-white/10 text-white shadow-2xl">
|
||||
<DialogHeader>
|
||||
<DialogTitle>{category ? 'Kategorie bearbeiten' : 'Neue Kategorie erstellen'}</DialogTitle>
|
||||
<DialogDescription>
|
||||
Definieren Sie eine Kategorie für Ihre Produkte.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="name"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Name</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="z.B. Software" className="bg-white/5 border-white/10" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="description"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Beschreibung</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="Kurze Beschreibung" className="bg-white/5 border-white/10" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="icon"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Icon</FormLabel>
|
||||
<Select onValueChange={field.onChange} defaultValue={field.value}>
|
||||
<FormControl>
|
||||
<SelectTrigger className="bg-white/5 border-white/10">
|
||||
<SelectValue placeholder="Icon wählen" />
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent className="glass-dark border-white/10 text-white">
|
||||
{icons.map(({ name, Icon }) => (
|
||||
<SelectItem key={name} value={name}>
|
||||
<div className="flex items-center gap-2">
|
||||
<Icon className="w-4 h-4" />
|
||||
{name}
|
||||
</div>
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<DialogFooter>
|
||||
<Button type="submit" className="w-full bg-primary hover:bg-primary/90">
|
||||
{category ? 'Aktualisieren' : 'Erstellen'}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</form>
|
||||
</Form>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user