{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "billing-usage-alerts",
  "title": "Billing Usage Alerts",
  "description": "Configure and manage usage alerts with notification channels.",
  "registryDependencies": [
    "badge",
    "button",
    "card",
    "separator",
    "switch"
  ],
  "files": [
    {
      "path": "registry/new-york/blocks/billing/billing-usage-alerts.tsx",
      "content": "\"use client\";\n\nimport { Bell, Loader2, Settings, X } from \"lucide-react\";\nimport { useState } from \"react\";\nimport { cn } from \"@/lib/utils\";\nimport { Badge } from \"@/registry/new-york/ui/badge\";\nimport { Button } from \"@/registry/new-york/ui/button\";\nimport {\n  Card,\n  CardContent,\n  CardDescription,\n  CardHeader,\n  CardTitle,\n} from \"@/registry/new-york/ui/card\";\nimport { Separator } from \"@/registry/new-york/ui/separator\";\nimport { Switch } from \"@/registry/new-york/ui/switch\";\n\nexport interface UsageAlert {\n  id: string;\n  name: string;\n  category: string;\n  threshold: number;\n  thresholdType: \"percentage\" | \"absolute\";\n  enabled: boolean;\n  channels: (\"email\" | \"sms\" | \"in_app\")[];\n  lastTriggered?: Date;\n  triggerCount?: number;\n}\n\nexport interface BillingUsageAlertsProps {\n  alerts?: UsageAlert[];\n  onToggle?: (alertId: string, enabled: boolean) => Promise<void>;\n  onEdit?: (alertId: string) => void;\n  onDelete?: (alertId: string) => Promise<void>;\n  onCreate?: () => void;\n  className?: string;\n}\n\nfunction formatDate(date: Date): string {\n  const year = date.getFullYear();\n  const month = date.toLocaleString(\"en-US\", { month: \"short\" });\n  const day = date.getDate();\n  return `${month} ${day}, ${year}`;\n}\n\nfunction getChannelIcon(channel: string) {\n  switch (channel) {\n    case \"email\":\n      return \"📧\";\n    case \"sms\":\n      return \"💬\";\n    case \"in_app\":\n      return \"🔔\";\n    default:\n      return \"🔔\";\n  }\n}\n\nfunction getChannelLabel(channel: string) {\n  switch (channel) {\n    case \"email\":\n      return \"Email\";\n    case \"sms\":\n      return \"SMS\";\n    case \"in_app\":\n      return \"In-App\";\n    default:\n      return channel;\n  }\n}\n\nexport default function BillingUsageAlerts({\n  alerts = [],\n  onToggle,\n  onEdit,\n  onDelete,\n  onCreate,\n  className,\n}: BillingUsageAlertsProps) {\n  const [isLoading, setIsLoading] = useState<string | null>(null);\n\n  const handleToggle = async (alertId: string, enabled: boolean) => {\n    if (!onToggle) return;\n\n    setIsLoading(alertId);\n    try {\n      await onToggle(alertId, enabled);\n    } finally {\n      setIsLoading(null);\n    }\n  };\n\n  const handleDelete = async (alertId: string) => {\n    if (!onDelete) return;\n\n    setIsLoading(alertId);\n    try {\n      await onDelete(alertId);\n    } finally {\n      setIsLoading(null);\n    }\n  };\n\n  if (alerts.length === 0) {\n    return (\n      <Card className={cn(\"w-full shadow-xs\", className)}>\n        <CardHeader>\n          <div className=\"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n            <div className=\"flex flex-col gap-1\">\n              <CardTitle>Usage Alerts</CardTitle>\n              <CardDescription>\n                Get notified when you approach your usage limits\n              </CardDescription>\n            </div>\n            {onCreate && (\n              <Button\n                className=\"w-full sm:w-auto\"\n                onClick={onCreate}\n                type=\"button\"\n              >\n                <Bell className=\"size-4\" />\n                Create Alert\n              </Button>\n            )}\n          </div>\n        </CardHeader>\n        <CardContent>\n          <div className=\"flex flex-col items-center justify-center gap-4 py-12 text-center\">\n            <div className=\"flex size-12 items-center justify-center rounded-full bg-muted\">\n              <Bell className=\"size-6 text-muted-foreground\" />\n            </div>\n            <div className=\"flex flex-col gap-2\">\n              <p className=\"font-medium text-sm\">No alerts configured</p>\n              <p className=\"text-muted-foreground text-sm\">\n                Create alerts to get notified when you approach your usage\n                limits\n              </p>\n            </div>\n            {onCreate && (\n              <Button onClick={onCreate} type=\"button\" variant=\"outline\">\n                <Bell className=\"size-4\" />\n                Create Your First Alert\n              </Button>\n            )}\n          </div>\n        </CardContent>\n      </Card>\n    );\n  }\n\n  return (\n    <Card className={cn(\"w-full shadow-xs\", className)}>\n      <CardHeader>\n        <div className=\"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n          <div className=\"flex flex-col gap-1\">\n            <CardTitle>Usage Alerts</CardTitle>\n            <CardDescription>\n              Get notified when you approach your usage limits\n            </CardDescription>\n          </div>\n          {onCreate && (\n            <Button\n              className=\"w-full sm:w-auto\"\n              onClick={onCreate}\n              type=\"button\"\n            >\n              <Bell className=\"size-4\" />\n              Create Alert\n            </Button>\n          )}\n        </div>\n      </CardHeader>\n      <CardContent>\n        <div className=\"flex flex-col gap-4\">\n          {alerts.map((alert, idx) => (\n            <div key={alert.id}>\n              <div className=\"flex flex-col gap-4 rounded-lg border bg-card p-4\">\n                <div className=\"flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between\">\n                  <div className=\"flex min-w-0 flex-1 flex-col gap-2\">\n                    <div className=\"flex flex-wrap items-center gap-2\">\n                      <h3 className=\"wrap-break-word font-medium text-sm\">\n                        {alert.name}\n                      </h3>\n                      {alert.enabled ? (\n                        <Badge className=\"shrink-0 text-xs\" variant=\"default\">\n                          Active\n                        </Badge>\n                      ) : (\n                        <Badge className=\"shrink-0 text-xs\" variant=\"secondary\">\n                          Disabled\n                        </Badge>\n                      )}\n                    </div>\n                    <div className=\"flex flex-wrap items-center gap-2 text-muted-foreground text-sm\">\n                      <span className=\"wrap-break-word\">{alert.category}</span>\n                      <span aria-hidden=\"true\">•</span>\n                      <span>\n                        Alert at{\" \"}\n                        {alert.thresholdType === \"percentage\"\n                          ? `${alert.threshold}%`\n                          : alert.threshold.toLocaleString()}\n                      </span>\n                    </div>\n                    <div className=\"flex flex-wrap items-center gap-2 text-muted-foreground text-xs\">\n                      <span>Notify via:</span>\n                      {alert.channels.map((channel, channelIdx) => (\n                        <div\n                          className=\"flex items-center gap-1\"\n                          key={channelIdx}\n                        >\n                          <span>{getChannelIcon(channel)}</span>\n                          <span>{getChannelLabel(channel)}</span>\n                        </div>\n                      ))}\n                      {alert.lastTriggered && (\n                        <>\n                          <span aria-hidden=\"true\">•</span>\n                          <span>\n                            Last triggered: {formatDate(alert.lastTriggered)}\n                          </span>\n                        </>\n                      )}\n                      {alert.triggerCount !== undefined &&\n                        alert.triggerCount > 0 && (\n                          <>\n                            <span aria-hidden=\"true\">•</span>\n                            <span>\n                              Triggered {alert.triggerCount} time\n                              {alert.triggerCount !== 1 ? \"s\" : \"\"}\n                            </span>\n                          </>\n                        )}\n                    </div>\n                  </div>\n                  <div className=\"flex shrink-0 items-center gap-3\">\n                    {onToggle && (\n                      <div className=\"flex items-center gap-2\">\n                        {isLoading === alert.id ? (\n                          <Loader2 className=\"size-4 animate-spin text-muted-foreground\" />\n                        ) : (\n                          <Switch\n                            checked={alert.enabled}\n                            disabled={isLoading !== null}\n                            onCheckedChange={(checked) =>\n                              handleToggle(alert.id, checked)\n                            }\n                          />\n                        )}\n                      </div>\n                    )}\n                    {onEdit && (\n                      <Button\n                        aria-label={`Edit alert ${alert.name}`}\n                        onClick={() => onEdit(alert.id)}\n                        size=\"icon\"\n                        type=\"button\"\n                        variant=\"ghost\"\n                      >\n                        <Settings className=\"size-4\" />\n                      </Button>\n                    )}\n                    {onDelete && (\n                      <Button\n                        aria-label={`Delete alert ${alert.name}`}\n                        disabled={isLoading !== null}\n                        onClick={() => handleDelete(alert.id)}\n                        size=\"icon\"\n                        type=\"button\"\n                        variant=\"ghost\"\n                      >\n                        {isLoading === alert.id ? (\n                          <Loader2 className=\"size-4 animate-spin\" />\n                        ) : (\n                          <X className=\"size-4\" />\n                        )}\n                      </Button>\n                    )}\n                  </div>\n                </div>\n              </div>\n              {idx < alerts.length - 1 && <Separator className=\"my-4\" />}\n            </div>\n          ))}\n        </div>\n      </CardContent>\n    </Card>\n  );\n}\n",
      "type": "registry:ui"
    }
  ],
  "categories": [
    "block",
    "billing"
  ],
  "type": "registry:ui"
}