{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "booking4",
  "title": "Service Selector",
  "description": "Service selection grid with category filter tabs, service cards showing icon, name, description, duration, price, and selected state. Ideal for spa, salon, clinic, and fitness booking flows.",
  "dependencies": [
    "clsx",
    "tailwind-merge",
    "lucide-react"
  ],
  "registryDependencies": [
    "badge",
    "button"
  ],
  "files": [
    {
      "path": "registry/booking4/booking4.tsx",
      "content": "\"use client\";\n\nimport {\n  Check,\n  ChevronRight,\n  Clock,\n  Dumbbell,\n  Hand,\n  Heart,\n  type LucideIcon,\n  Scissors,\n  Sparkles,\n  Star,\n  Waves,\n} from \"lucide-react\";\nimport { useMemo, useState } from \"react\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { Button } from \"@/components/ui/button\";\nimport { cn } from \"@/lib/utils\";\n\ninterface Service {\n  name: string;\n  description: string;\n  duration: string;\n  price: string;\n  category: string;\n  icon: LucideIcon;\n  badge?: string;\n}\n\ninterface Booking4Labels {\n  allCategory?: string;\n  noSelection?: string;\n  nextButton?: string;\n}\n\ninterface Booking4Props {\n  badge?: {\n    label: string;\n    variant?: \"default\" | \"secondary\" | \"outline\";\n  };\n  heading?: string;\n  description?: string;\n  services?: Service[];\n  labels?: Booking4Labels;\n  className?: string;\n}\n\nexport const booking4Demo: Booking4Props = {\n  badge: { label: \"Step 1 of 3\", variant: \"secondary\" },\n  heading: \"Choose your <strong>service</strong>\",\n  description: \"Browse our menu and pick the treatment that suits you best.\",\n  services: [\n    {\n      name: \"Swedish Massage\",\n      description: \"Gentle full-body massage for relaxation and stress relief\",\n      duration: \"60 min\",\n      price: \"$89\",\n      category: \"Massage\",\n      icon: Hand,\n      badge: \"Popular\",\n    },\n    {\n      name: \"Deep Tissue Massage\",\n      description: \"Targeted pressure for chronic muscle tension and pain\",\n      duration: \"60 min\",\n      price: \"$120\",\n      category: \"Massage\",\n      icon: Hand,\n    },\n    {\n      name: \"Hot Stone Therapy\",\n      description: \"Heated stones placed on key points for deep relaxation\",\n      duration: \"75 min\",\n      price: \"$140\",\n      category: \"Massage\",\n      icon: Sparkles,\n    },\n    {\n      name: \"Classic Facial\",\n      description: \"Deep cleansing facial with extraction and hydration\",\n      duration: \"45 min\",\n      price: \"$75\",\n      category: \"Skincare\",\n      icon: Heart,\n    },\n    {\n      name: \"Anti-Aging Treatment\",\n      description: \"Advanced serum and LED therapy for youthful skin\",\n      duration: \"60 min\",\n      price: \"$150\",\n      category: \"Skincare\",\n      icon: Star,\n      badge: \"Popular\",\n    },\n    {\n      name: \"Haircut & Styling\",\n      description: \"Precision cut with wash, blow-dry, and styling\",\n      duration: \"45 min\",\n      price: \"$65\",\n      category: \"Hair\",\n      icon: Scissors,\n    },\n    {\n      name: \"Color Treatment\",\n      description: \"Full or partial color with premium products\",\n      duration: \"120 min\",\n      price: \"$180\",\n      category: \"Hair\",\n      icon: Waves,\n    },\n    {\n      name: \"Personal Training\",\n      description: \"One-on-one session tailored to your fitness goals\",\n      duration: \"50 min\",\n      price: \"$95\",\n      category: \"Fitness\",\n      icon: Dumbbell,\n    },\n  ],\n  labels: {\n    allCategory: \"All\",\n    noSelection: \"No service selected\",\n    nextButton: \"Next Step\",\n  },\n};\n\nexport function Booking4({\n  badge,\n  heading,\n  description,\n  services = [],\n  labels = {},\n  className,\n}: Booking4Props) {\n  const { allCategory = \"All\", noSelection, nextButton } = labels;\n\n  const [selectedService, setSelectedService] = useState<string | null>(null);\n  const [activeCategory, setActiveCategory] = useState<string>(allCategory);\n\n  const categories = useMemo(\n    () => [allCategory, ...new Set(services.map((s) => s.category))],\n    [services, allCategory]\n  );\n\n  const filteredServices = useMemo(() => {\n    if (activeCategory === allCategory) return services;\n    return services.filter((s) => s.category === activeCategory);\n  }, [services, activeCategory, allCategory]);\n\n  const selected = services.find((s) => s.name === selectedService);\n\n  return (\n    <section className={cn(\"py-16 md:py-24 w-full\", className)}>\n      <div className=\"mx-auto max-w-lg px-4 md:px-6\">\n        {(badge || heading || description) && (\n          <div className=\"mx-auto mb-12 max-w-3xl text-center\">\n            {badge && (\n              <div className=\"mb-4 flex justify-center\">\n                <Badge variant={badge.variant ?? \"default\"}>{badge.label}</Badge>\n              </div>\n            )}\n            {heading && (\n              <h2\n                className=\"text-2xl font-semibold md:text-4xl [&>strong]:font-bold [&>strong]:text-primary\"\n                dangerouslySetInnerHTML={{ __html: heading }}\n              />\n            )}\n            {description && (\n              <p className=\"mt-4 text-base text-muted-foreground md:text-lg\">{description}</p>\n            )}\n          </div>\n        )}\n\n        <div className=\"group/booking4 overflow-hidden rounded-md border bg-card shadow-sm\">\n          {categories.length > 2 && (\n            <div className=\"border-b p-4\">\n              <div className=\"flex gap-2 overflow-x-auto\">\n                {categories.map((cat) => (\n                  <button\n                    key={cat}\n                    type=\"button\"\n                    onClick={() => setActiveCategory(cat)}\n                    className={cn(\n                      \"shrink-0 cursor-pointer rounded-full px-4 py-1.5 text-sm font-medium transition-all\",\n                      activeCategory === cat\n                        ? \"bg-primary text-primary-foreground shadow-sm\"\n                        : \"bg-muted text-muted-foreground hover:text-foreground\"\n                    )}\n                  >\n                    {cat}\n                  </button>\n                ))}\n              </div>\n            </div>\n          )}\n\n          <div className=\"max-h-[480px] divide-y overflow-y-auto\">\n            {filteredServices.map((service, index) => {\n              const isSelected = selectedService === service.name;\n              const Icon = service.icon;\n\n              return (\n                <button\n                  key={index}\n                  type=\"button\"\n                  onClick={() => setSelectedService(service.name)}\n                  className={cn(\n                    \"flex w-full cursor-pointer items-start gap-3 px-5 py-4 text-left transition-all\",\n                    isSelected ? \"bg-primary/5\" : \"hover:bg-muted/50\"\n                  )}\n                >\n                  <div\n                    className={cn(\n                      \"mt-0.5 flex size-11 shrink-0 items-center justify-center rounded-md transition-colors\",\n                      isSelected\n                        ? \"bg-primary text-primary-foreground\"\n                        : \"bg-muted text-muted-foreground\"\n                    )}\n                  >\n                    <Icon className=\"size-5\" />\n                  </div>\n\n                  <div className=\"min-w-0 flex-1\">\n                    <div className=\"flex items-center gap-2\">\n                      <h3 className=\"text-base font-semibold\">{service.name}</h3>\n                      {service.badge && (\n                        <Badge variant=\"secondary\" className=\"text-xs\">\n                          {service.badge}\n                        </Badge>\n                      )}\n                    </div>\n                    <p className=\"mt-0.5 line-clamp-1 text-sm text-muted-foreground\">\n                      {service.description}\n                    </p>\n                    <div className=\"mt-2 flex items-center gap-3 text-sm text-muted-foreground\">\n                      <span className=\"flex items-center gap-1\">\n                        <Clock className=\"size-4\" />\n                        {service.duration}\n                      </span>\n                      <span className=\"font-semibold text-foreground\">{service.price}</span>\n                    </div>\n                  </div>\n\n                  <div className=\"mt-1 shrink-0\">\n                    {isSelected ? (\n                      <div className=\"flex size-6 items-center justify-center rounded-full bg-primary text-primary-foreground\">\n                        <Check className=\"size-4\" />\n                      </div>\n                    ) : (\n                      <div className=\"size-6 rounded-full border-2 border-muted-foreground/20\" />\n                    )}\n                  </div>\n                </button>\n              );\n            })}\n          </div>\n\n          <div className=\"flex flex-wrap items-center justify-between gap-3 border-t bg-muted/30 px-5 py-4\">\n            <div className=\"text-base\">\n              {selected ? (\n                <span>\n                  <span className=\"font-medium\">{selected.name}</span>\n                  <span className=\"text-muted-foreground\"> · {selected.price}</span>\n                </span>\n              ) : (\n                <span className=\"text-muted-foreground\">{noSelection}</span>\n              )}\n            </div>\n            <Button\n              disabled={!selected}\n              className=\"cursor-pointer\"\n              onClick={() => {\n                if (selected) console.log(\"Selected service:\", selected);\n              }}\n            >\n              {nextButton}\n              <ChevronRight className=\"size-5\" />\n            </Button>\n          </div>\n        </div>\n      </div>\n    </section>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/beste/block/booking4.tsx"
    }
  ],
  "type": "registry:block"
}