{
  "name": "wallet-components-donatebutton",
  "type": "registry:component",
  "dependencies": [
    "@radix-ui/react-icons"
  ],
  "devDependencies": [],
  "registryDependencies": [],
  "files": [
    {
      "path": "components/wallet/components/DonateButton.tsx",
      "type": "registry:component",
      "content": "import { CopyIcon, Cross2Icon, HeartIcon } from \"@radix-ui/react-icons\";\n// DonateButton Component - Simple donation interface for Bitcoin applications\nimport { type ChangeEvent, useState } from \"react\";\nimport { useBitcoinAuth } from \"../../../hooks/useBitcoinAuth.js\";\nimport { cn } from \"../../../lib/utils.js\";\nimport { QRCodeRenderer } from \"../../ui-components/QRCodeRenderer.js\";\nimport { Badge } from \"../../ui/badge.js\";\nimport { Button } from \"../../ui/button.js\";\nimport {\n\tDialog,\n\tDialogClose,\n\tDialogContent,\n\tDialogHeader,\n\tDialogTitle,\n\tDialogTrigger,\n} from \"../../ui/dialog.js\";\nimport { Input } from \"../../ui/input.js\";\nimport { Separator } from \"../../ui/separator.js\";\nimport { useSendBSV } from \"../hooks/useSendBSV.js\";\nimport { formatBSV } from \"../utils/currency.js\";\n\nexport interface DonateButtonProps {\n\t// Donation configuration\n\tdonationAddress?: string;\n\tdefaultAmounts?: number[]; // In satoshis\n\tcustomAmountEnabled?: boolean;\n\n\t// UI customization\n\tvariant?: \"default\" | \"secondary\" | \"outline\" | \"ghost\";\n\tsize?: \"sm\" | \"default\" | \"lg\";\n\tbuttonText?: string;\n\tdialogTitle?: string;\n\tdescription?: string;\n\n\t// Callbacks\n\tonDonate?: (amount: number, txid: string) => void;\n\tonError?: (error: Error) => void;\n\n\t// Display options\n\tshowQR?: boolean;\n\tshowCopyAddress?: boolean;\n\tdisabled?: boolean;\n}\n\n// Default donation address (replace with your address)\nconst DEFAULT_DONATION_ADDRESS = \"1BitcoinAuthUi1111111111111111112345\";\n\n// Default donation amounts in satoshis\nconst DEFAULT_AMOUNTS = [\n\t1000000, // 0.01 BSV\n\t5000000, // 0.05 BSV\n\t10000000, // 0.1 BSV\n\t50000000, // 0.5 BSV\n\t100000000, // 1 BSV\n];\n\nexport function DonateButton({\n\tdonationAddress = DEFAULT_DONATION_ADDRESS,\n\tdefaultAmounts = DEFAULT_AMOUNTS,\n\tcustomAmountEnabled = true,\n\tvariant = \"default\",\n\tsize = \"default\",\n\tbuttonText = \"Donate\",\n\tdialogTitle = \"Support the Project\",\n\tdescription = \"Your donation helps support continued development. Thank you!\",\n\tonDonate,\n\tonError,\n\tshowQR = true,\n\tshowCopyAddress = true,\n\tdisabled = false,\n}: DonateButtonProps) {\n\tconst [open, setOpen] = useState(false);\n\tconst [selectedAmount, setSelectedAmount] = useState<number | null>(null);\n\tconst [customAmount, setCustomAmount] = useState(\"\");\n\tconst [copied, setCopied] = useState(false);\n\n\tconst { user, isAuthenticated } = useBitcoinAuth();\n\tconst { sendBSV, isLoading } = useSendBSV({\n\t\tonSuccess: (result) => {\n\t\t\tconst amount =\n\t\t\t\tselectedAmount ||\n\t\t\t\t(customAmount ? Number.parseFloat(customAmount) * 100000000 : 0);\n\t\t\tonDonate?.(amount, result.txid);\n\t\t\tsetOpen(false);\n\t\t\tsetSelectedAmount(null);\n\t\t\tsetCustomAmount(\"\");\n\t\t},\n\t\tonError: (error) => {\n\t\t\tonError?.(error);\n\t\t},\n\t});\n\n\tconst handleDonate = async () => {\n\t\tif (!isAuthenticated || !user) {\n\t\t\tonError?.(new Error(\"Please sign in to donate\"));\n\t\t\treturn;\n\t\t}\n\n\t\tlet amountSats = selectedAmount;\n\n\t\tif (!amountSats && customAmount) {\n\t\t\tconst customBSV = Number.parseFloat(customAmount);\n\t\t\tif (Number.isNaN(customBSV) || customBSV <= 0) {\n\t\t\t\tonError?.(new Error(\"Please enter a valid amount\"));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tamountSats = Math.floor(customBSV * 100000000);\n\t\t}\n\n\t\tif (!amountSats || amountSats <= 0) {\n\t\t\tonError?.(new Error(\"Please select or enter an amount\"));\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tawait sendBSV({\n\t\t\t\ttoAddress: donationAddress,\n\t\t\t\tsatoshis: amountSats,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tonError?.(error as Error);\n\t\t}\n\t};\n\n\tconst copyAddress = async () => {\n\t\ttry {\n\t\t\tawait navigator.clipboard.writeText(donationAddress);\n\t\t\tsetCopied(true);\n\t\t\tsetTimeout(() => setCopied(false), 2000);\n\t\t} catch {\n\t\t\tonError?.(new Error(\"Failed to copy address\"));\n\t\t}\n\t};\n\n\tconst bitcoinUri = `bitcoin:${donationAddress}${selectedAmount ? `?amount=${selectedAmount / 100000000}` : \"\"}`;\n\n\treturn (\n\t\t<Dialog open={open} onOpenChange={setOpen}>\n\t\t\t<DialogTrigger asChild>\n\t\t\t\t<Button variant={variant} size={size} disabled={disabled}>\n\t\t\t\t\t<HeartIcon className=\"h-4 w-4 mr-2\" />\n\t\t\t\t\t{buttonText}\n\t\t\t\t</Button>\n\t\t\t</DialogTrigger>\n\n\t\t\t<DialogContent className=\"max-w-[500px]\">\n\t\t\t\t<DialogHeader>\n\t\t\t\t\t<DialogTitle>{dialogTitle}</DialogTitle>\n\t\t\t\t</DialogHeader>\n\n\t\t\t\t<div className=\"space-y-4\">\n\t\t\t\t\t{/* Description */}\n\t\t\t\t\t<p className=\"text-sm text-muted-foreground\">{description}</p>\n\n\t\t\t\t\t{/* Preset Amounts */}\n\t\t\t\t\t<div className=\"space-y-3\">\n\t\t\t\t\t\t<p className=\"text-sm font-medium\">Choose Amount</p>\n\t\t\t\t\t\t<div className=\"flex flex-wrap gap-2\">\n\t\t\t\t\t\t\t{defaultAmounts.map((amount) => (\n\t\t\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t\t\tkey={amount}\n\t\t\t\t\t\t\t\t\tvariant={selectedAmount === amount ? \"default\" : \"secondary\"}\n\t\t\t\t\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\t\t\tsetSelectedAmount(amount);\n\t\t\t\t\t\t\t\t\t\tsetCustomAmount(\"\");\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{formatBSV(amount)} BSV\n\t\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t{/* Custom Amount */}\n\t\t\t\t\t{customAmountEnabled && (\n\t\t\t\t\t\t<div className=\"space-y-2\">\n\t\t\t\t\t\t\t<p className=\"text-sm font-medium\">Or Enter Custom Amount</p>\n\t\t\t\t\t\t\t<div className=\"relative\">\n\t\t\t\t\t\t\t\t<Input\n\t\t\t\t\t\t\t\t\ttype=\"number\"\n\t\t\t\t\t\t\t\t\tstep=\"0.00000001\"\n\t\t\t\t\t\t\t\t\tmin=\"0\"\n\t\t\t\t\t\t\t\t\tplaceholder=\"0.00000000\"\n\t\t\t\t\t\t\t\t\tvalue={customAmount}\n\t\t\t\t\t\t\t\t\tonChange={(e: ChangeEvent<HTMLInputElement>) => {\n\t\t\t\t\t\t\t\t\t\tsetCustomAmount(e.target.value);\n\t\t\t\t\t\t\t\t\t\tsetSelectedAmount(null);\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\tclassName=\"pr-12\"\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t<span className=\"absolute right-3 top-1/2 -translate-y-1/2 text-xs text-muted-foreground\">\n\t\t\t\t\t\t\t\t\tBSV\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\n\t\t\t\t\t<Separator />\n\n\t\t\t\t\t{/* QR Code */}\n\t\t\t\t\t{showQR && (selectedAmount || customAmount) && (\n\t\t\t\t\t\t<div className=\"flex flex-col gap-2 items-center\">\n\t\t\t\t\t\t\t<p className=\"text-sm font-medium\">Scan to Donate</p>\n\t\t\t\t\t\t\t<div className=\"p-3 border rounded-lg bg-background\">\n\t\t\t\t\t\t\t\t<QRCodeRenderer\n\t\t\t\t\t\t\t\t\tdata={bitcoinUri}\n\t\t\t\t\t\t\t\t\tsize={200}\n\t\t\t\t\t\t\t\t\tqrStyle=\"dots\"\n\t\t\t\t\t\t\t\t\tthemeAware={true}\n\t\t\t\t\t\t\t\t\tbgColor=\"var(--background)\"\n\t\t\t\t\t\t\t\t\tfgColor=\"var(--primary)\"\n\t\t\t\t\t\t\t\t\tlogoImage=\"https://cdn.jsdelivr.net/gh/bitcoinsv/bitcoin-sv@main/assets/bitcoin-sv-logo.svg\"\n\t\t\t\t\t\t\t\t\tlogoWidth={40}\n\t\t\t\t\t\t\t\t\tlogoHeight={40}\n\t\t\t\t\t\t\t\t\tlogoOpacity={0.8}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\n\t\t\t\t\t{/* Donation Address */}\n\t\t\t\t\t{showCopyAddress && (\n\t\t\t\t\t\t<div className=\"space-y-2\">\n\t\t\t\t\t\t\t<p className=\"text-sm font-medium\">Donation Address</p>\n\t\t\t\t\t\t\t<div className=\"p-3 border rounded-lg\">\n\t\t\t\t\t\t\t\t<div className=\"flex items-center justify-between gap-2\">\n\t\t\t\t\t\t\t\t\t<span className=\"text-xs font-mono break-all flex-grow\">\n\t\t\t\t\t\t\t\t\t\t{donationAddress}\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t<Button variant=\"ghost\" size=\"sm\" onClick={copyAddress}>\n\t\t\t\t\t\t\t\t\t\t{copied ? (\n\t\t\t\t\t\t\t\t\t\t\t<Badge variant=\"secondary\" className=\"text-green-600\">\n\t\t\t\t\t\t\t\t\t\t\t\tCopied!\n\t\t\t\t\t\t\t\t\t\t\t</Badge>\n\t\t\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t\t\t<CopyIcon className=\"h-3 w-3\" />\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\n\t\t\t\t\t{/* Actions */}\n\t\t\t\t\t<div className=\"flex gap-3 mt-4 justify-end\">\n\t\t\t\t\t\t<DialogClose asChild>\n\t\t\t\t\t\t\t<Button variant=\"outline\">Cancel</Button>\n\t\t\t\t\t\t</DialogClose>\n\n\t\t\t\t\t\t{isAuthenticated ? (\n\t\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t\tonClick={handleDonate}\n\t\t\t\t\t\t\t\tdisabled={isLoading || (!selectedAmount && !customAmount)}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{isLoading ? (\n\t\t\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t\t\t<svg\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"animate-spin h-4 w-4 mr-2\"\n\t\t\t\t\t\t\t\t\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t\t\t\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\t\t\t\t\t\tviewBox=\"0 0 24 24\"\n\t\t\t\t\t\t\t\t\t\t\trole=\"img\"\n\t\t\t\t\t\t\t\t\t\t\taria-label=\"Loading\"\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t<title>Loading</title>\n\t\t\t\t\t\t\t\t\t\t\t<circle\n\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"opacity-25\"\n\t\t\t\t\t\t\t\t\t\t\t\tcx=\"12\"\n\t\t\t\t\t\t\t\t\t\t\t\tcy=\"12\"\n\t\t\t\t\t\t\t\t\t\t\t\tr=\"10\"\n\t\t\t\t\t\t\t\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\t\t\t\t\t\t\t\tstrokeWidth=\"4\"\n\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t<path\n\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"opacity-75\"\n\t\t\t\t\t\t\t\t\t\t\t\tfill=\"currentColor\"\n\t\t\t\t\t\t\t\t\t\t\t\td=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t</svg>\n\t\t\t\t\t\t\t\t\t\tProcessing...\n\t\t\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t\t\t<HeartIcon className=\"h-4 w-4 mr-2\" />\n\t\t\t\t\t\t\t\t\t\tDonate Now\n\t\t\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t<Button disabled variant=\"secondary\">\n\t\t\t\t\t\t\t\tSign in to Donate\n\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</DialogContent>\n\t\t</Dialog>\n\t);\n}\n\n// Simplified version for quick donations\nexport function QuickDonateButton({\n\tdonationAddress,\n\tamount = 10000000, // 0.1 BSV default\n\t...props\n}: Omit<DonateButtonProps, \"defaultAmounts\" | \"customAmountEnabled\"> & {\n\tamount?: number;\n}) {\n\treturn (\n\t\t<DonateButton\n\t\t\tdonationAddress={donationAddress}\n\t\t\tdefaultAmounts={[amount]}\n\t\t\tcustomAmountEnabled={false}\n\t\t\tbuttonText=\"Quick Donate\"\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n",
      "target": "<%- config.aliases.components %>/donatebutton.tsx"
    }
  ]
}