UNPKG

bigblocks

Version:

Complete Bitcoin UI component library - authentication, social, wallet, market, inscriptions, and blockchain interactions for React

149 lines (148 loc) 8.65 kB
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; /** * Yours Wallet Connector Component * * Provides a complete UI for connecting to Yours Wallet with: * - Installation detection and prompts * - Connection management * - Error handling * - Loading states */ import React from "react"; import { cn } from "../../lib/utils.js"; import { Button } from "../ui/button.js"; import { Card, CardContent } from "../ui/card.js"; export function YoursWalletConnector({ onSuccess, onError, className = "", }) { const [state, setState] = React.useState({ isLoading: false, isInstalled: null, isConnected: false, publicKey: null, error: null, }); // Lazy load the Yours integration const [yoursModule, setYoursModule] = React.useState(null); React.useEffect(() => { // Check if Yours is installed on mount checkInstallation(); }, []); const checkInstallation = async () => { setState((prev) => ({ ...prev, isLoading: true, error: null })); try { // Check if window.yours is available const isInstalled = typeof window !== "undefined" && !!window.yours; if (isInstalled) { // Lazy load the module only if Yours is installed const module = await import("../../lib/yours-wallet-provider.js"); setYoursModule(module); setState((prev) => ({ ...prev, isInstalled: true, isLoading: false, })); } else { setState((prev) => ({ ...prev, isInstalled: false, isLoading: false, })); } } catch { setState((prev) => ({ ...prev, isInstalled: false, isLoading: false, error: "Failed to check Yours Wallet installation", })); } }; const handleConnect = async () => { if (!yoursModule) { setState((prev) => ({ ...prev, error: "Yours Wallet module not loaded", })); return; } setState((prev) => ({ ...prev, isLoading: true, error: null })); try { const result = await yoursModule.createYoursAuthHandler(); if (result.success) { setState((prev) => ({ ...prev, isConnected: true, publicKey: result.profile?.publicKey || null, isLoading: false, })); onSuccess?.({ publicKey: result.profile?.publicKey ?? "", idKey: result.idKey, encryptedBackup: result.encryptedBackup, }); } else { const errorMsg = result.error || "Connection failed"; setState((prev) => ({ ...prev, isLoading: false, error: errorMsg, })); onError?.(errorMsg); } } catch (error) { const errorMsg = error instanceof Error ? error.message : "Unknown error occurred"; setState((prev) => ({ ...prev, isLoading: false, error: errorMsg, })); onError?.(errorMsg); } }; const handleInstallComplete = () => { // Re-check installation after user says they've installed it checkInstallation(); }; // Loading state if (state.isInstalled === null || state.isLoading) { return (_jsxs("div", { className: cn("flex flex-col items-center gap-4", className), children: [_jsx("div", { className: "animate-spin h-8 w-8 border-4 border-primary border-t-transparent rounded-full" }), _jsx("p", { className: "text-muted-foreground", children: state.isInstalled === null ? "Checking for Yours Wallet..." : "Connecting..." })] })); } // Not installed state if (!state.isInstalled) { return (_jsx(YoursInstallPrompt, { onInstalled: handleInstallComplete, className: className })); } // Connected state if (state.isConnected && state.publicKey) { return (_jsx("div", { className: cn("flex flex-col items-center gap-4", className), children: _jsx(Card, { className: "w-full", children: _jsxs(CardContent, { className: "flex flex-col items-center gap-3 p-6", children: [_jsx("div", { className: "w-12 h-12 rounded-full bg-primary flex items-center justify-center", children: _jsxs("svg", { width: "24", height: "24", fill: "none", stroke: "white", viewBox: "0 0 24 24", children: [_jsx("title", { children: "Check Mark" }), _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 13l4 4L19 7" })] }) }), _jsx("h2", { className: "text-2xl font-bold", children: "Connected to Yours Wallet" }), _jsxs("p", { className: "text-sm text-muted-foreground", children: ["Public Key: ", state.publicKey.slice(0, 16), "...", state.publicKey.slice(-8)] })] }) }) })); } // Ready to connect state return (_jsx("div", { className: cn("flex flex-col items-center gap-4", className), children: _jsx(Card, { className: "w-full", children: _jsxs(CardContent, { className: "flex flex-col items-center gap-4 p-6", children: [_jsx("div", { className: "w-12 h-12 rounded-full bg-primary flex items-center justify-center", children: _jsxs("svg", { width: "24", height: "24", viewBox: "0 0 24 24", children: [_jsx("title", { children: "Shield" }), _jsx("path", { fill: "white", d: "M12 2L2 7v10c0 5.55 3.84 10.74 9 12 5.16-1.26 9-6.45 9-12V7l-10-5z" })] }) }), _jsx("h2", { className: "text-2xl font-bold", children: "Connect with Yours Wallet" }), _jsx("p", { className: "text-sm text-muted-foreground text-center", children: "Connect your Yours Wallet to authenticate with your Bitcoin identity." }), state.error && (_jsx(Card, { className: "w-full border-destructive", children: _jsx(CardContent, { className: "p-3", children: _jsx("p", { className: "text-sm text-destructive", children: state.error }) }) })), _jsx(Button, { onClick: handleConnect, disabled: state.isLoading, size: "lg", className: "w-full", children: state.isLoading ? "Connecting..." : "Connect Wallet" })] }) }) })); } // Install prompt component (re-exported for convenience) function YoursInstallPrompt({ onInstalled, className = "", }) { const handleInstall = () => { window.open("https://chromewebstore.google.com/detail/yours-wallet/mlbnicldlpdimbjdcncnklfempedeipj", "_blank"); }; const handleCheckInstalled = () => { // Re-check after potential installation setTimeout(() => { if (typeof window !== "undefined" && window.yours) { onInstalled?.(); } else { // In Storybook or development, simulate successful installation if (process.env.NODE_ENV === "development" || window.location.hostname === "localhost") { console.log("Simulating Yours Wallet installation for Storybook/development"); onInstalled?.(); } } }, 1000); }; return (_jsx("div", { className: cn("flex flex-col items-center gap-4", className), children: _jsx(Card, { className: "w-full", children: _jsxs(CardContent, { className: "flex flex-col items-center gap-4 p-6", children: [_jsx("div", { className: "w-12 h-12 rounded-full bg-primary flex items-center justify-center", children: _jsxs("svg", { width: "24", height: "24", fill: "none", stroke: "white", viewBox: "0 0 24 24", children: [_jsx("title", { children: "Install Yours Wallet" }), _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 9v3m0 0v3m0-3h3m-3 0H9m12 0a9 9 0 11-18 0 9 9 0 0118 0z" })] }) }), _jsx("h2", { className: "text-2xl font-bold", children: "Yours Wallet Required" }), _jsx("p", { className: "text-sm text-muted-foreground text-center", children: "To use Yours Wallet authentication, please install the browser extension." }), _jsxs("div", { className: "flex flex-col gap-2 w-full", children: [_jsx(Button, { onClick: handleInstall, size: "lg", className: "w-full", children: "Install Yours Wallet" }), _jsx(Button, { onClick: handleCheckInstalled, size: "lg", variant: "secondary", className: "w-full", children: "I've Installed It" })] })] }) }) })); }