feat: add Kaufprodukte and Mietprodukte filter checkboxes in products view
All checks were successful
Staging Build / build (push) Successful in 2m48s
All checks were successful
Staging Build / build (push) Successful in 2m48s
This commit is contained in:
@@ -13,6 +13,7 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/com
|
|||||||
import { Badge } from '@/components/ui/badge'
|
import { Badge } from '@/components/ui/badge'
|
||||||
import { Edit2, Trash2, Layers, ArrowUpDown } from 'lucide-react'
|
import { Edit2, Trash2, Layers, ArrowUpDown } from 'lucide-react'
|
||||||
import { Button } from '@/components/ui/button'
|
import { Button } from '@/components/ui/button'
|
||||||
|
import { Checkbox } from '@/components/ui/checkbox'
|
||||||
import { deleteProduct } from '@/lib/actions/products'
|
import { deleteProduct } from '@/lib/actions/products'
|
||||||
import { useState, useEffect, useMemo, Fragment } from 'react'
|
import { useState, useEffect, useMemo, Fragment } from 'react'
|
||||||
import { CreateProductDialog } from './create-product-dialog'
|
import { CreateProductDialog } from './create-product-dialog'
|
||||||
@@ -20,6 +21,8 @@ import { CreateProductDialog } from './create-product-dialog'
|
|||||||
export function ProductList({ initialProducts, categories }: { initialProducts: Product[], categories: Category[] }) {
|
export function ProductList({ initialProducts, categories }: { initialProducts: Product[], categories: Category[] }) {
|
||||||
const [products, setProducts] = useState(initialProducts)
|
const [products, setProducts] = useState(initialProducts)
|
||||||
const [isGroupedByCategory, setIsGroupedByCategory] = useState(false)
|
const [isGroupedByCategory, setIsGroupedByCategory] = useState(false)
|
||||||
|
const [showKauf, setShowKauf] = useState(true)
|
||||||
|
const [showAbo, setShowAbo] = useState(true)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setProducts(initialProducts)
|
setProducts(initialProducts)
|
||||||
@@ -36,9 +39,17 @@ export function ProductList({ initialProducts, categories }: { initialProducts:
|
|||||||
setIsGroupedByCategory(!isGroupedByCategory)
|
setIsGroupedByCategory(!isGroupedByCategory)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const filteredProducts = useMemo(() => {
|
||||||
|
return products.filter(p => {
|
||||||
|
if (p.billing_interval === 'one_time') return showKauf
|
||||||
|
if (p.billing_interval === 'monthly') return showAbo
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}, [products, showKauf, showAbo])
|
||||||
|
|
||||||
const groupedProducts = useMemo(() => {
|
const groupedProducts = useMemo(() => {
|
||||||
const groups: Record<string, { category: Category | null; products: Product[] }> = {}
|
const groups: Record<string, { category: Category | null; products: Product[] }> = {}
|
||||||
products.forEach(p => {
|
filteredProducts.forEach(p => {
|
||||||
const catId = p.category_id || 'no-category'
|
const catId = p.category_id || 'no-category'
|
||||||
if (!groups[catId]) {
|
if (!groups[catId]) {
|
||||||
groups[catId] = {
|
groups[catId] = {
|
||||||
@@ -53,7 +64,7 @@ export function ProductList({ initialProducts, categories }: { initialProducts:
|
|||||||
const orderB = b.category?.sort_order ?? 9999
|
const orderB = b.category?.sort_order ?? 9999
|
||||||
return orderA - orderB
|
return orderA - orderB
|
||||||
})
|
})
|
||||||
}, [products])
|
}, [filteredProducts])
|
||||||
|
|
||||||
const renderProductRow = (product: Product) => (
|
const renderProductRow = (product: Product) => (
|
||||||
<TableRow key={product.id} className="border-slate-100 dark:border-white/5 hover:bg-slate-50 dark:hover:bg-white/5 transition-colors">
|
<TableRow key={product.id} className="border-slate-100 dark:border-white/5 hover:bg-slate-50 dark:hover:bg-white/5 transition-colors">
|
||||||
@@ -110,13 +121,28 @@ export function ProductList({ initialProducts, categories }: { initialProducts:
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Card className="bg-white dark:bg-slate-900/50 border border-slate-200 dark:border-white/10 shadow-sm overflow-hidden text-slate-900 dark:text-white">
|
<Card className="bg-white dark:bg-slate-900/50 border border-slate-200 dark:border-white/10 shadow-sm overflow-hidden text-slate-900 dark:text-white">
|
||||||
<CardHeader className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
|
<CardHeader className="flex flex-col lg:flex-row lg:items-center lg:justify-between gap-4">
|
||||||
<div>
|
<div>
|
||||||
<CardTitle>Produktübersicht</CardTitle>
|
<CardTitle>Produktübersicht</CardTitle>
|
||||||
<CardDescription className="text-slate-500 dark:text-slate-400">
|
<CardDescription className="text-slate-500 dark:text-slate-400">
|
||||||
Alle konfigurierten Software-Lösungen und Erweiterungen.
|
Alle konfigurierten Software-Lösungen und Erweiterungen.
|
||||||
</CardDescription>
|
</CardDescription>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="flex flex-wrap items-center gap-6">
|
||||||
|
<label className="flex items-center gap-2 text-sm font-medium text-slate-700 dark:text-slate-300 cursor-pointer select-none">
|
||||||
|
<Checkbox
|
||||||
|
checked={showKauf}
|
||||||
|
onCheckedChange={(checked) => setShowKauf(!!checked)}
|
||||||
|
/>
|
||||||
|
Kaufprodukte
|
||||||
|
</label>
|
||||||
|
<label className="flex items-center gap-2 text-sm font-medium text-slate-700 dark:text-slate-300 cursor-pointer select-none">
|
||||||
|
<Checkbox
|
||||||
|
checked={showAbo}
|
||||||
|
onCheckedChange={(checked) => setShowAbo(!!checked)}
|
||||||
|
/>
|
||||||
|
Mietprodukte
|
||||||
|
</label>
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
size="sm"
|
size="sm"
|
||||||
@@ -128,6 +154,7 @@ export function ProductList({ initialProducts, categories }: { initialProducts:
|
|||||||
<ArrowUpDown className="w-4 h-4 mr-2" />
|
<ArrowUpDown className="w-4 h-4 mr-2" />
|
||||||
{isGroupedByCategory ? 'Kategoriengruppierung aktiv' : 'Nach Kategorien gruppieren'}
|
{isGroupedByCategory ? 'Kategoriengruppierung aktiv' : 'Nach Kategorien gruppieren'}
|
||||||
</Button>
|
</Button>
|
||||||
|
</div>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<Table>
|
<Table>
|
||||||
@@ -153,12 +180,12 @@ export function ProductList({ initialProducts, categories }: { initialProducts:
|
|||||||
</Fragment>
|
</Fragment>
|
||||||
))
|
))
|
||||||
) : (
|
) : (
|
||||||
products.map((product) => renderProductRow(product))
|
filteredProducts.map((product) => renderProductRow(product))
|
||||||
)}
|
)}
|
||||||
{products.length === 0 && (
|
{filteredProducts.length === 0 && (
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell colSpan={5} className="text-center py-10 text-slate-500 dark:text-slate-400">
|
<TableCell colSpan={5} className="text-center py-10 text-slate-500 dark:text-slate-400">
|
||||||
Keine Produkte gefunden. Erstellen Sie Ihr erstes Produkt!
|
Keine Produkte gefunden. Passen Sie Ihre Filter an.
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
)}
|
)}
|
||||||
|
|||||||
Reference in New Issue
Block a user