From 912a892ba5504d765410021f56ebd42b2369c208 Mon Sep 17 00:00:00 2001 From: Simone Cavalli Date: Sat, 13 Jun 2026 16:01:17 +0200 Subject: [PATCH] feat(11-04): add client-side search bar to catalog page, remove ServiceForm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - New CatalogSearch client component: filters ServiceWithTags[] by name/tag, case-insensitive, instant (no reload) - page.tsx now passes filtered services through CatalogSearch -> ServiceTable - ServiceForm.tsx deleted — quick-add row in ServiceTable replaces its create-service UX --- src/app/admin/catalog/CatalogSearch.tsx | 36 +++++++ src/app/admin/catalog/page.tsx | 11 +- src/components/admin/catalog/ServiceForm.tsx | 102 ------------------- 3 files changed, 39 insertions(+), 110 deletions(-) create mode 100644 src/app/admin/catalog/CatalogSearch.tsx delete mode 100644 src/components/admin/catalog/ServiceForm.tsx diff --git a/src/app/admin/catalog/CatalogSearch.tsx b/src/app/admin/catalog/CatalogSearch.tsx new file mode 100644 index 0000000..1d8db30 --- /dev/null +++ b/src/app/admin/catalog/CatalogSearch.tsx @@ -0,0 +1,36 @@ +"use client"; + +import { useState, useMemo } from "react"; +import { Input } from "@/components/ui/input"; +import { Search } from "lucide-react"; +import { ServiceTable } from "@/components/admin/catalog/ServiceTable"; +import type { ServiceWithTags } from "@/lib/admin-queries"; + +export function CatalogSearch({ services }: { services: ServiceWithTags[] }) { + const [query, setQuery] = useState(""); + + const filtered = useMemo(() => { + const q = query.trim().toLowerCase(); + if (!q) return services; + return services.filter((s) => { + if (s.name.toLowerCase().includes(q)) return true; + return s.tags.some((tag) => tag.toLowerCase().includes(q)); + }); + }, [services, query]); + + return ( +
+
+ + setQuery(e.target.value)} + className="pl-9 h-9" + /> +
+ +
+ ); +} diff --git a/src/app/admin/catalog/page.tsx b/src/app/admin/catalog/page.tsx index 0206e20..dcdf6e9 100644 --- a/src/app/admin/catalog/page.tsx +++ b/src/app/admin/catalog/page.tsx @@ -1,6 +1,5 @@ import { getAllServices } from "@/lib/admin-queries"; -import { ServiceTable } from "@/components/admin/catalog/ServiceTable"; -import { ServiceForm } from "@/components/admin/catalog/ServiceForm"; +import { CatalogSearch } from "./CatalogSearch"; export const revalidate = 0; @@ -13,16 +12,12 @@ export default async function CatalogPage() {

Catalogo Servizi

-
- -
- {services.length === 0 ? (

- Nessun servizio nel catalogo. Aggiungi il primo servizio qui sopra. + Nessun servizio nel catalogo. Scrivi un nome nella riga in fondo alla tabella e premi invio per crearne uno.

) : ( - + )} ); diff --git a/src/components/admin/catalog/ServiceForm.tsx b/src/components/admin/catalog/ServiceForm.tsx deleted file mode 100644 index ab77282..0000000 --- a/src/components/admin/catalog/ServiceForm.tsx +++ /dev/null @@ -1,102 +0,0 @@ -"use client"; - -import { useRef, useState, useTransition } from "react"; -import { useRouter } from "next/navigation"; -import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; -import { Label } from "@/components/ui/label"; -import { createService } from "@/app/admin/catalog/actions"; - -export function ServiceForm() { - const [open, setOpen] = useState(false); - const [error, setError] = useState(null); - const [, startTransition] = useTransition(); - const router = useRouter(); - const formRef = useRef(null); - - function handleSubmit(fd: FormData) { - setError(null); - startTransition(async () => { - try { - await createService(fd); - formRef.current?.reset(); - setOpen(false); - router.refresh(); - } catch (e) { - setError(e instanceof Error ? e.message : "Errore nel salvataggio"); - } - }); - } - - if (!open) { - return ( - - ); - } - - return ( -
-

Nuovo servizio

-
-
- - -
-
- - -
-
- - -
-
- - -
- {error &&

{error}

} -
- - -
-
-
- ); -}