feat(catalog): Notion-style shared select fields (tag/pacchetto/categoria/fase)

Turn the catalog into Notion/Airtable select properties:
- Tag + Pacchetto: multi-select with a SHARED pool — created values persist and
  are selectable from a dropdown across all services (no more re-typing)
- Categoria + Fase: single-select chips with the same dropdown + create-on-the-fly
- Rename an option once -> propagates to every row (renameServiceOption)
- Deterministic colors per value (shared option-colors util)
- Quick-add row now sets name+description+categoria+fase+prezzo then Enter (active)
- Search broadened to name/categoria/fase/tag/pacchetto

Data model (additive): tag/pacchetto in polymorphic tags table (entity_type
services / services.pacchetto); categoria/fase as single-select columns on
services (new: services.fase). Pools derived from distinct values.

New: OptionSelect, OptionMultiSelect, option-colors. Removed tag-multi-select.
Migration 0007_add_services_fase.sql must be applied before runtime.

tsc + eslint + next build clean. CSV bulk import (OFFER-12) stays Phase 12.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-13 21:40:34 +02:00
parent 42c16e1bab
commit e858a8f577
12 changed files with 834 additions and 249 deletions
+6 -9
View File
@@ -1,10 +1,13 @@
import { getAllServices } from "@/lib/admin-queries";
import { getAllServices, getCatalogFieldOptions } from "@/lib/admin-queries";
import { CatalogSearch } from "./CatalogSearch";
export const revalidate = 0;
export default async function CatalogPage() {
const services = await getAllServices();
const [services, options] = await Promise.all([
getAllServices(),
getCatalogFieldOptions(),
]);
return (
<div>
@@ -12,13 +15,7 @@ export default async function CatalogPage() {
<h1 className="text-2xl font-bold text-[#1a1a1a]">Catalogo Servizi</h1>
</div>
{services.length === 0 ? (
<p className="text-sm text-[#71717a]">
Nessun servizio nel catalogo. Scrivi un nome nella riga in fondo alla tabella e premi invio per crearne uno.
</p>
) : (
<CatalogSearch services={services} />
)}
<CatalogSearch services={services} options={options} />
</div>
);
}