{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "billing-settings",
  "title": "Billing Settings",
  "description": "A comprehensive billing settings component with tabs for general, payment methods, invoices, and usage limits",
  "dependencies": ["lucide-react", "sonner"],
  "registryDependencies": [
    "button",
    "card",
    "dialog",
    "switch",
    "badge",
    "dropdown-menu",
    "dialog",
    "input",
    "label"
  ],
  "files": [
    {
      "path": "src/registry/billingsdk/billing-settings.tsx",
      "content": "\"use client\";\n\nimport { Button } from \"@/components/ui/button\";\nimport { Card, CardContent, CardHeader, CardTitle } from \"@/components/ui/card\";\nimport { Switch } from \"@/components/ui/switch\";\nimport { Badge } from \"@/components/ui/badge\";\nimport {\n  DropdownMenu,\n  DropdownMenuContent,\n  DropdownMenuItem,\n  DropdownMenuTrigger,\n} from \"@/components/ui/dropdown-menu\";\nimport { ChevronDown, CreditCard, Plus } from \"lucide-react\";\n\nconst tabs = [\n  { id: \"general\", label: \"General\" },\n  { id: \"payment\", label: \"Payment\" },\n  { id: \"invoices\", label: \"Invoices\" },\n  { id: \"limits\", label: \"Limits\" },\n];\n\ninterface CardInfo {\n  id: string;\n  last4: string;\n  brand: string;\n  expiry: string;\n  primary?: boolean;\n}\n\ninterface BillingSettingsProps {\n  activeTab: string;\n  onTabChange: (tab: string) => void;\n\n  emailNotifications: boolean;\n  onEmailNotificationsChange: (value: boolean) => void;\n\n  usageAlerts: boolean;\n  onUsageAlertsChange: (value: boolean) => void;\n\n  invoiceReminders: boolean;\n  onInvoiceRemindersChange: (value: boolean) => void;\n\n  cards: CardInfo[];\n  onAddCard: () => void;\n\n  invoiceFormat: \"PDF\" | \"HTML\";\n  onInvoiceFormatChange: (format: \"PDF\" | \"HTML\") => void;\n  onEditBillingAddress: () => void;\n\n  overageProtection: boolean;\n  onOverageProtectionChange: (value: boolean) => void;\n\n  usageLimitAlerts: boolean;\n  onUsageLimitAlertsChange: (value: boolean) => void;\n  className?: string;\n}\n\ninterface SettingItemProps {\n  title: string;\n  description: string;\n  checked: boolean;\n  onCheckedChange: (checked: boolean) => void;\n}\n\nfunction SettingItem({\n  title,\n  description,\n  checked,\n  onCheckedChange,\n}: SettingItemProps) {\n  const switchId = `switch-${title.toLowerCase().replace(/\\s+/g, \"-\")}`;\n\n  return (\n    <div className=\"flex items-center justify-between gap-4 py-4\">\n      <div className=\"min-w-0 flex-1 space-y-0.5\">\n        <label\n          htmlFor={switchId}\n          className=\"text-sm leading-none font-medium peer-disabled:cursor-not-allowed peer-disabled:opacity-70\"\n        >\n          {title}\n        </label>\n        <p className=\"text-muted-foreground text-sm\">{description}</p>\n      </div>\n      <Switch\n        id={switchId}\n        checked={checked}\n        onCheckedChange={onCheckedChange}\n        className=\"shrink-0\"\n      />\n    </div>\n  );\n}\n\ninterface TabNavigationProps {\n  activeTab: string;\n  onTabChange: (tab: string) => void;\n}\n\nfunction TabNavigation({ activeTab, onTabChange }: TabNavigationProps) {\n  return (\n    <div className=\"bg-muted text-muted-foreground inline-flex h-9 w-full items-center justify-center gap-1 rounded-lg p-1\">\n      {tabs.map((tab) => (\n        <button\n          key={tab.id}\n          onClick={() => onTabChange(tab.id)}\n          className={`ring-offset-background focus-visible:ring-ring inline-flex flex-1 items-center justify-center rounded-md px-2 py-1 text-xs font-medium whitespace-nowrap transition-all focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50 sm:px-3 sm:text-sm ${\n            activeTab === tab.id\n              ? \"bg-background text-foreground shadow\"\n              : \"hover:bg-background/50 hover:text-foreground\"\n          }`}\n        >\n          {tab.label}\n        </button>\n      ))}\n    </div>\n  );\n}\n\nexport function BillingSettings({\n  activeTab,\n  onTabChange,\n  emailNotifications,\n  onEmailNotificationsChange,\n  usageAlerts,\n  onUsageAlertsChange,\n  invoiceReminders,\n  onInvoiceRemindersChange,\n  cards,\n  onAddCard,\n  invoiceFormat,\n  onInvoiceFormatChange,\n  onEditBillingAddress,\n  overageProtection,\n  onOverageProtectionChange,\n  usageLimitAlerts,\n  onUsageLimitAlertsChange,\n  className,\n}: BillingSettingsProps) {\n  const renderGeneralContent = () => (\n    <div className=\"divide-border space-y-0 divide-y\">\n      <SettingItem\n        title=\"Email notifications\"\n        description=\"Receive billing updates via email\"\n        checked={emailNotifications}\n        onCheckedChange={onEmailNotificationsChange}\n      />\n      <SettingItem\n        title=\"Usage alerts\"\n        description=\"Get notified when approaching limits\"\n        checked={usageAlerts}\n        onCheckedChange={onUsageAlertsChange}\n      />\n      <SettingItem\n        title=\"Invoice reminders\"\n        description=\"Remind me before auto-renewal\"\n        checked={invoiceReminders}\n        onCheckedChange={onInvoiceRemindersChange}\n      />\n    </div>\n  );\n\n  const renderPaymentContent = () => (\n    <div className=\"space-y-4\">\n      {cards.map((card) => (\n        <div\n          key={card.id}\n          className=\"flex flex-col justify-between gap-3 rounded-lg border p-3 sm:flex-row sm:items-center sm:p-4\"\n        >\n          <div className=\"flex min-w-0 items-center gap-3\">\n            <CreditCard className=\"text-muted-foreground h-5 w-5 shrink-0\" />\n            <div className=\"min-w-0 flex-1\">\n              <div className=\"flex flex-wrap items-center gap-2\">\n                <span className=\"font-mono text-sm\">•••• {card.last4}</span>\n                {card.primary && <Badge variant=\"secondary\">Primary</Badge>}\n              </div>\n              <p className=\"text-muted-foreground text-sm\">\n                {card.brand} • Expires {card.expiry}\n              </p>\n            </div>\n          </div>\n        </div>\n      ))}\n      <Button variant=\"outline\" className=\"w-full\" onClick={onAddCard}>\n        <Plus className=\"mr-2 h-4 w-4\" />\n        Add new card\n      </Button>\n    </div>\n  );\n\n  const renderInvoicesContent = () => (\n    <div className=\"space-y-6\">\n      <div className=\"flex flex-col justify-between gap-3 sm:flex-row sm:items-center\">\n        <div className=\"flex-1 space-y-0.5\">\n          <h3 className=\"text-sm font-medium\">Invoice format</h3>\n          <p className=\"text-muted-foreground text-sm\">\n            Choose PDF or HTML format\n          </p>\n        </div>\n        <DropdownMenu>\n          <DropdownMenuTrigger asChild>\n            <Button variant=\"outline\" size=\"sm\" className=\"w-full sm:w-auto\">\n              {invoiceFormat}\n              <ChevronDown className=\"ml-2 h-4 w-4\" />\n            </Button>\n          </DropdownMenuTrigger>\n          <DropdownMenuContent align=\"end\">\n            <DropdownMenuItem onClick={() => onInvoiceFormatChange(\"PDF\")}>\n              PDF\n            </DropdownMenuItem>\n            <DropdownMenuItem onClick={() => onInvoiceFormatChange(\"HTML\")}>\n              HTML\n            </DropdownMenuItem>\n          </DropdownMenuContent>\n        </DropdownMenu>\n      </div>\n      <div className=\"flex flex-col justify-between gap-3 sm:flex-row sm:items-center\">\n        <div className=\"flex-1 space-y-0.5\">\n          <h3 className=\"text-sm font-medium\">Billing address</h3>\n          <p className=\"text-muted-foreground text-sm\">\n            Update your billing address\n          </p>\n        </div>\n        <Button\n          variant=\"outline\"\n          size=\"sm\"\n          className=\"w-full sm:w-auto\"\n          onClick={onEditBillingAddress}\n        >\n          Edit\n        </Button>\n      </div>\n    </div>\n  );\n\n  const renderLimitsContent = () => (\n    <div className=\"divide-border space-y-0 divide-y\">\n      <SettingItem\n        title=\"Overage protection\"\n        description=\"Prevent accidental overages\"\n        checked={overageProtection}\n        onCheckedChange={onOverageProtectionChange}\n      />\n      <SettingItem\n        title=\"Usage limit alerts\"\n        description=\"Alert at 80% and 95% usage\"\n        checked={usageLimitAlerts}\n        onCheckedChange={onUsageLimitAlertsChange}\n      />\n    </div>\n  );\n\n  const renderTabContent = () => {\n    switch (activeTab) {\n      case \"general\":\n        return renderGeneralContent();\n      case \"payment\":\n        return renderPaymentContent();\n      case \"invoices\":\n        return renderInvoicesContent();\n      case \"limits\":\n        return renderLimitsContent();\n      default:\n        return renderGeneralContent();\n    }\n  };\n\n  return (\n    <div className={`w-full px-4 sm:px-0 ${className || \"\"}`}>\n      <Card className=\"mx-auto w-full max-w-2xl\">\n        <CardHeader className=\"px-4 sm:px-6\">\n          <CardTitle>Billing Settings</CardTitle>\n        </CardHeader>\n        <CardContent className=\"space-y-6 px-4 sm:px-6\">\n          <TabNavigation activeTab={activeTab} onTabChange={onTabChange} />\n          {renderTabContent()}\n        </CardContent>\n      </Card>\n    </div>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/billingsdk/billing-settings.tsx"
    },
    {
      "path": "src/registry/billingsdk/demo/billing-settings-demo.tsx",
      "content": "\"use client\";\n\nimport { useState } from \"react\";\nimport {\n  Dialog,\n  DialogContent,\n  DialogDescription,\n  DialogFooter,\n  DialogHeader,\n  DialogTitle,\n} from \"@/components/ui/dialog\";\nimport { Button } from \"@/components/ui/button\";\nimport { Input } from \"@/components/ui/input\";\nimport { Label } from \"@/components/ui/label\";\nimport { Toaster, toast } from \"sonner\";\nimport { BillingSettings } from \"@/components/billingsdk/billing-settings\";\nimport { CreditCard } from \"lucide-react\";\n\ntype InvoiceFormat = \"PDF\" | \"HTML\";\n\ninterface Card {\n  id: string;\n  last4: string;\n  brand: \"Visa\" | \"MasterCard\" | \"Amex\" | \"Other\";\n  expiry: string;\n  primary: boolean;\n}\n\ninterface NewCardForm {\n  number: string;\n  expiry: string;\n  cvc: string;\n}\n\nexport default function BillingSettingsDemo() {\n  const [activeTab, setActiveTab] = useState<\n    \"general\" | \"payment\" | \"invoices\" | \"limits\"\n  >(\"general\");\n  const [emailNotifications, setEmailNotifications] = useState<boolean>(true);\n  const [usageAlerts, setUsageAlerts] = useState<boolean>(true);\n  const [invoiceReminders, setInvoiceReminders] = useState<boolean>(false);\n  const [cards, setCards] = useState<Card[]>([\n    { id: \"1\", last4: \"4242\", brand: \"Visa\", expiry: \"12/25\", primary: true },\n  ]);\n  const [invoiceFormat, setInvoiceFormat] = useState<InvoiceFormat>(\"PDF\");\n  const [overageProtection, setOverageProtection] = useState<boolean>(true);\n  const [usageLimitAlerts, setUsageLimitAlerts] = useState<boolean>(true);\n  const [newCard, setNewCard] = useState<NewCardForm>({\n    number: \"\",\n    expiry: \"\",\n    cvc: \"\",\n  });\n  const [open, setOpen] = useState<boolean>(false);\n\n  const handleToggleEmailNotifications = (checked: boolean) => {\n    console.log(`Email notifications toggled to: ${checked}`);\n    setEmailNotifications(checked);\n  };\n\n  const handleToggleUsageAlerts = (checked: boolean) => {\n    console.log(`Usage alerts toggled to: ${checked}`);\n    setUsageAlerts(checked);\n  };\n\n  const handleToggleInvoiceReminders = (checked: boolean) => {\n    console.log(`Invoice reminders toggled to: ${checked}`);\n    setInvoiceReminders(checked);\n  };\n\n  const handleChangeInvoiceFormat = (format: InvoiceFormat) => {\n    console.log(`Invoice format changed to: ${format}`);\n    setInvoiceFormat(format);\n  };\n\n  const handleEditBillingAddress = () => {\n    console.log(\"Edit billing address button clicked\");\n    toast.info(\"Edit billing address clicked!\");\n  };\n\n  const handleToggleOverageProtection = (checked: boolean) => {\n    console.log(`Overage protection toggled to: ${checked}`);\n    setOverageProtection(checked);\n  };\n\n  const handleToggleUsageLimitAlerts = (checked: boolean) => {\n    console.log(`Usage limit alerts toggled to: ${checked}`);\n    setUsageLimitAlerts(checked);\n  };\n\n  const isValidCardNumber = (number: string): boolean => {\n    const normalized = number.replace(/\\s/g, \"\");\n    return (\n      normalized.length >= 13 &&\n      normalized.length <= 19 &&\n      /^\\d+$/.test(normalized)\n    );\n  };\n\n  const isValidExpiry = (expiry: string): boolean => {\n    if (!/^(0[1-9]|1[0-2])\\/?([0-9]{2})$/.test(expiry)) {\n      return false;\n    }\n    const [month, year] = expiry.split(\"/\").map(Number);\n    const currentYear = Number(String(new Date().getFullYear()).slice(-2));\n    const currentMonth = new Date().getMonth() + 1;\n    if (year < currentYear || (year === currentYear && month < currentMonth)) {\n      return false;\n    }\n    return true;\n  };\n\n  const isValidCvc = (cvc: string): boolean => {\n    return /^\\d{3,4}$/.test(cvc);\n  };\n\n  const detectCardBrand = (number: string): Card[\"brand\"] => {\n    if (number.startsWith(\"4\")) return \"Visa\";\n    if (/^5[1-5]/.test(number)) return \"MasterCard\";\n    if (/^3[47]/.test(number)) return \"Amex\";\n    return \"Other\";\n  };\n\n  const handleAddCard = (): void => {\n    if (!isValidCardNumber(newCard.number)) {\n      toast.error(\"Please enter a valid card number.\");\n      return;\n    }\n    if (!isValidExpiry(newCard.expiry)) {\n      toast.error(\n        \"Please enter a valid expiry date (MM/YY) that's not in the past.\",\n      );\n      return;\n    }\n    if (!isValidCvc(newCard.cvc)) {\n      toast.error(\"Please enter a valid CVC.\");\n      return;\n    }\n    const last4 = newCard.number.slice(-4);\n    const brand = detectCardBrand(newCard.number);\n    const newCardData: Card = {\n      id: String(cards.length + 1),\n      last4,\n      brand,\n      expiry: newCard.expiry,\n      primary: cards.length === 0,\n    };\n    setCards([...cards, newCardData]);\n    setNewCard({ number: \"\", expiry: \"\", cvc: \"\" });\n    setOpen(false);\n    toast.success(\"Card added successfully!\");\n  };\n\n  const formatCardNumber = (value: string): string => {\n    const rawValue = value.replace(/\\D/g, \"\");\n    const formattedValue = rawValue.match(/.{1,4}/g)?.join(\" \") || \"\";\n    return formattedValue;\n  };\n\n  return (\n    <div className=\"p-6\">\n      <BillingSettings\n        activeTab={activeTab}\n        onTabChange={(tab: string) =>\n          setActiveTab(tab as \"general\" | \"payment\" | \"invoices\" | \"limits\")\n        }\n        emailNotifications={emailNotifications}\n        onEmailNotificationsChange={handleToggleEmailNotifications}\n        usageAlerts={usageAlerts}\n        onUsageAlertsChange={handleToggleUsageAlerts}\n        invoiceReminders={invoiceReminders}\n        onInvoiceRemindersChange={handleToggleInvoiceReminders}\n        cards={cards}\n        onAddCard={() => setOpen(true)}\n        invoiceFormat={invoiceFormat}\n        onInvoiceFormatChange={handleChangeInvoiceFormat}\n        onEditBillingAddress={handleEditBillingAddress}\n        overageProtection={overageProtection}\n        onOverageProtectionChange={handleToggleOverageProtection}\n        usageLimitAlerts={usageLimitAlerts}\n        onUsageLimitAlertsChange={handleToggleUsageLimitAlerts}\n      />\n      <Dialog open={open} onOpenChange={setOpen}>\n        <DialogContent className=\"sm:max-w-md\">\n          <DialogHeader>\n            <DialogTitle>Add Payment Card</DialogTitle>\n            <DialogDescription>\n              Enter your card details to add a new payment method\n            </DialogDescription>\n          </DialogHeader>\n          <div className=\"space-y-4 py-4\">\n            <div className=\"space-y-2\">\n              <Label htmlFor=\"number\">Card Number</Label>\n              <div className=\"relative\">\n                <Input\n                  id=\"number\"\n                  value={formatCardNumber(newCard.number)}\n                  onChange={(e) => {\n                    const rawValue = e.target.value.replace(/\\s/g, \"\");\n                    if (rawValue.length <= 19) {\n                      setNewCard({ ...newCard, number: rawValue });\n                    }\n                  }}\n                  placeholder=\"1234 5678 9012 3456\"\n                  className=\"pr-10\"\n                  maxLength={19}\n                />\n                <CreditCard className=\"text-muted-foreground absolute top-1/2 right-3 h-4 w-4 -translate-y-1/2\" />\n              </div>\n            </div>\n            <div className=\"grid grid-cols-2 gap-4\">\n              <div className=\"space-y-2\">\n                <Label htmlFor=\"expiry\">Expiry Date</Label>\n                <Input\n                  id=\"expiry\"\n                  value={newCard.expiry}\n                  onChange={(e) => {\n                    let value = e.target.value.replace(/\\D/g, \"\");\n                    if (value.length >= 2) {\n                      value = value.slice(0, 2) + \"/\" + value.slice(2, 4);\n                    }\n                    if (value.length <= 5) {\n                      setNewCard({ ...newCard, expiry: value });\n                    }\n                  }}\n                  placeholder=\"MM/YY\"\n                  maxLength={5}\n                />\n              </div>\n              <div className=\"space-y-2\">\n                <Label htmlFor=\"cvc\">CVC</Label>\n                <Input\n                  id=\"cvc\"\n                  type=\"password\"\n                  value={newCard.cvc}\n                  onChange={(e) => {\n                    const value = e.target.value.replace(/\\D/g, \"\");\n                    if (value.length <= 4) {\n                      setNewCard({ ...newCard, cvc: value });\n                    }\n                  }}\n                  placeholder=\"123\"\n                  maxLength={4}\n                />\n              </div>\n            </div>\n          </div>\n          <DialogFooter className=\"gap-2 sm:gap-0\">\n            <Button variant=\"outline\" onClick={() => setOpen(false)}>\n              Cancel\n            </Button>\n            <Button onClick={handleAddCard}>Add Card</Button>\n          </DialogFooter>\n        </DialogContent>\n      </Dialog>\n      <Toaster />\n    </div>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/billing-settings-demo.tsx"
    }
  ],
  "type": "registry:block"
}
