{
  "name": "resource-picker",
  "title": "ResourcePicker",
  "description": "Staff / room / resource picker for bookable services — used by services and restaurant reservation flows.",
  "type": "component",
  "registryDependencies": [
    "cn"
  ],
  "files": [
    {
      "path": "resource-picker.tsx",
      "content": "\"use client\";\n\nimport { Radio } from \"@base-ui/react/radio\";\nimport { RadioGroup } from \"@base-ui/react/radio-group\";\nimport React from \"react\";\nimport type { Room } from \"../types/business\";\nimport { cn } from \"@cimplify/sdk/react\";\n\nconst ANY_VALUE = \"__any__\";\n\nexport interface Resource {\n  id: string;\n  name: string;\n  description?: string;\n  capacity?: number;\n  floor?: string;\n  image_url?: string;\n  is_available?: boolean;\n}\n\nexport interface ResourcePickerClassNames {\n  root?: string;\n  option?: string;\n  image?: string;\n  name?: string;\n  description?: string;\n  meta?: string;\n  capacity?: string;\n  floor?: string;\n  unavailable?: string;\n}\n\nexport interface ResourcePickerProps {\n  /** List of available resources (rooms, equipment, etc.). */\n  resources: Resource[];\n  /** Currently selected resource ID, or null for \"Any available\". */\n  selectedResourceId?: string | null;\n  /** Called when a resource is selected. Passes null for \"Any available\". */\n  onResourceSelect?: (resourceId: string | null) => void;\n  /** Show \"Any available\" option. Default: true. */\n  showAnyOption?: boolean;\n  /** Label for the \"Any available\" option. */\n  anyLabel?: string;\n  /** Custom image renderer (e.g. Next.js Image). */\n  renderImage?: (props: {\n    src: string;\n    alt: string;\n    className?: string;\n  }) => React.ReactNode;\n  className?: string;\n  classNames?: ResourcePickerClassNames;\n}\n\nexport function roomToResource(room: Room): Resource {\n  return {\n    id: room.id,\n    name: room.name,\n    capacity: room.capacity,\n    floor: room.floor,\n    is_available: room.status === \"available\",\n  };\n}\n\nexport function ResourcePicker({\n  resources,\n  selectedResourceId,\n  onResourceSelect,\n  showAnyOption = true,\n  anyLabel = \"Any available\",\n  renderImage,\n  className,\n  classNames,\n}: ResourcePickerProps): React.ReactElement {\n  const groupValue =\n    selectedResourceId === null ? ANY_VALUE : (selectedResourceId ?? \"\");\n\n  return (\n    <RadioGroup\n      data-cimplify-resource-picker\n      className={cn(\"flex flex-col gap-2\", className, classNames?.root)}\n      value={groupValue}\n      onValueChange={(value) => {\n        onResourceSelect?.(value === ANY_VALUE ? null : value);\n      }}\n    >\n      {showAnyOption && (\n        <Radio.Root\n          value={ANY_VALUE}\n          data-cimplify-resource-option\n          data-selected={selectedResourceId === null || undefined}\n          data-any\n          className={cn(\n            \"flex items-center gap-3 rounded-lg border border-border p-3 transition-colors cursor-pointer\",\n            \"hover:bg-muted data-[checked]:border-primary data-[checked]:bg-primary/5\",\n            classNames?.option,\n          )}\n        >\n          <span data-cimplify-resource-name className={cn(\"font-medium text-foreground\", classNames?.name)}>\n            {anyLabel}\n          </span>\n        </Radio.Root>\n      )}\n      {resources.map((resource) => {\n        const unavailable = resource.is_available === false;\n        return (\n          <Radio.Root\n            key={resource.id}\n            value={resource.id}\n            disabled={unavailable}\n            data-cimplify-resource-option\n            data-selected={selectedResourceId === resource.id || undefined}\n            data-unavailable={unavailable || undefined}\n            className={cn(\n              \"flex items-center gap-3 rounded-lg border border-border p-3 transition-colors cursor-pointer\",\n              \"hover:bg-muted data-[checked]:border-primary data-[checked]:bg-primary/5\",\n              unavailable && \"opacity-50 cursor-not-allowed\",\n              classNames?.option,\n              unavailable ? classNames?.unavailable : undefined,\n            )}\n          >\n            {resource.image_url && (\n              renderImage ? (\n                renderImage({\n                  src: resource.image_url,\n                  alt: resource.name,\n                  className: classNames?.image,\n                })\n              ) : (\n                <img\n                  src={resource.image_url}\n                  alt={resource.name}\n                  data-cimplify-resource-image\n                  className={cn(\"w-10 h-10 rounded-lg object-cover\", classNames?.image)}\n                />\n              )\n            )}\n            <div className=\"flex flex-col gap-0.5 flex-1 min-w-0\">\n              <span data-cimplify-resource-name className={cn(\"font-medium text-foreground\", classNames?.name)}>\n                {resource.name}\n              </span>\n              {resource.description && (\n                <span data-cimplify-resource-description className={cn(\"text-sm text-muted-foreground truncate\", classNames?.description)}>\n                  {resource.description}\n                </span>\n              )}\n              <div data-cimplify-resource-meta className={cn(\"flex items-center gap-2 text-xs text-muted-foreground\", classNames?.meta)}>\n                {resource.capacity !== undefined && (\n                  <span data-cimplify-resource-capacity className={classNames?.capacity}>\n                    Up to {resource.capacity}\n                  </span>\n                )}\n                {resource.floor && (\n                  <span data-cimplify-resource-floor className={classNames?.floor}>\n                    {resource.floor}\n                  </span>\n                )}\n              </div>\n            </div>\n          </Radio.Root>\n        );\n      })}\n    </RadioGroup>\n  );\n}\n"
    }
  ]
}
