UNPKG

bigblocks

Version:

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

106 lines (105 loc) 10.1 kB
"use client"; import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { useState } from "react"; import { cn } from "../../lib/utils.js"; import { ErrorDisplay } from "../ui-components/ErrorDisplay.js"; import { LoadingButton } from "../ui-components/LoadingButton.js"; import { PasswordInput } from "../ui-components/PasswordInput.js"; import { AlertDialog, AlertDialogContent, AlertDialogDescription, AlertDialogTitle, } from "../ui/alert-dialog.js"; import { Alert, AlertDescription, AlertTitle } from "../ui/alert.js"; import { Button } from "../ui/button.js"; import { Card, CardContent } from "../ui/card.js"; export function OAuthConflictModal({ isOpen, onClose, provider, existingBapId, currentBapId, onTransferComplete, onSwitchAccount, onTransferOAuth, onSwitchToExisting, className = "", }) { const [mode, setMode] = useState("choose"); const [password, setPassword] = useState(""); const [loading, setLoading] = useState(false); const [error, setError] = useState(""); const handleTransfer = async (e) => { e.preventDefault(); setLoading(true); setError(""); try { if (onTransferOAuth) { await onTransferOAuth(existingBapId, currentBapId, password); } else { // Default transfer logic - can be overridden by parent const response = await fetch("/api/users/transfer-oauth", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ provider, fromBapId: existingBapId, toBapId: currentBapId, verificationPassword: password, }), }); if (!response.ok) { const data = await response.json(); throw new Error(data.error || "Failed to transfer OAuth link"); } } onTransferComplete(); } catch (err) { console.error("Transfer error:", err); setError(err instanceof Error ? err.message : "Failed to transfer OAuth link"); setLoading(false); } }; const handleSwitchAccount = async () => { setMode("switching"); setLoading(true); try { if (onSwitchToExisting) { await onSwitchToExisting(existingBapId); } else { // Default switch logic - can be overridden by parent const response = await fetch(`/api/backup?bapid=${existingBapId}`); if (!response.ok) { throw new Error("Failed to fetch existing account"); } const { backup: encryptedBackup } = await response.json(); localStorage.setItem("encryptedBackup", encryptedBackup); } onSwitchAccount(); } catch (err) { console.error("Switch account error:", err); setError("Failed to switch accounts. Please try signing in manually."); setLoading(false); setMode("choose"); } }; const resetForm = () => { setMode("choose"); setPassword(""); setError(""); setLoading(false); }; const handleClose = () => { resetForm(); onClose(); }; const renderChooseMode = () => (_jsxs("div", { className: "flex flex-col gap-6", children: [_jsxs(Alert, { className: "border-amber-200 bg-amber-50", children: [_jsxs("svg", { width: "16", height: "16", fill: "currentColor", viewBox: "0 0 20 20", "aria-label": "Information", className: "text-amber-600", children: [_jsx("title", { children: "Information" }), _jsx("path", { fillRule: "evenodd", d: "M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z", clipRule: "evenodd" })] }), _jsx(AlertTitle, { className: "font-medium", children: "Account Already Linked" }), _jsxs(AlertDescription, { children: ["This ", provider, " account is already linked to another Bitcoin identity. Choose how you'd like to proceed:"] })] }), _jsxs("div", { className: "flex flex-col gap-3", children: [_jsx(Card, { className: "cursor-pointer hover:bg-accent/50 transition-colors", onClick: () => setMode("transfer"), children: _jsx(CardContent, { className: "p-4", children: _jsxs("div", { className: "flex items-start gap-3", children: [_jsxs("svg", { width: "20", height: "20", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-label": "Transfer", className: "text-blue-600", children: [_jsx("title", { children: "Transfer" }), _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8 7h12m0 0l-4-4m4 4l-4 4m0 6H4m0 0l4 4m-4-4l4-4" })] }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsxs("p", { className: "font-medium", children: ["Transfer ", provider, " Link"] }), _jsxs("p", { className: "text-sm text-muted-foreground", children: ["Move the ", provider, " connection from your other account to this one. You'll need the password for verification."] })] })] }) }) }), _jsx(Card, { className: cn("transition-colors", loading ? "cursor-not-allowed opacity-50" : "cursor-pointer hover:bg-accent/50"), onClick: loading ? undefined : handleSwitchAccount, children: _jsx(CardContent, { className: "p-4", children: _jsxs("div", { className: "flex items-start gap-3", children: [_jsxs("svg", { width: "20", height: "20", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-label": "Use existing account", className: "text-green-600", children: [_jsx("title", { children: "Use existing account" }), _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" })] }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx("p", { className: "font-medium", children: "Use Existing Account" }), _jsx("p", { className: "text-sm text-muted-foreground", children: "Discard this new identity and continue with your existing account." })] })] }) }) })] }), _jsx("div", { className: "flex justify-center pt-4", children: _jsx(Button, { variant: "ghost", size: "sm", onClick: handleClose, children: "Cancel" }) })] })); const renderTransferMode = () => (_jsx("form", { onSubmit: handleTransfer, children: _jsxs("div", { className: "flex flex-col gap-6", children: [_jsxs("div", { children: [_jsxs("p", { className: "text-sm text-muted-foreground mb-4", children: ["Enter the password for your other account to verify ownership and transfer the ", provider, " link to your current account."] }), _jsx(Card, { className: "mb-4", children: _jsx(CardContent, { className: "p-4", children: _jsxs("div", { className: "flex flex-col gap-2", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsxs("svg", { width: "16", height: "16", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-label": "Transfer from", className: "text-muted-foreground", children: [_jsx("title", { children: "Transfer from" }), _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8 7h12m0 0l-4-4m4 4l-4 4" })] }), _jsx("span", { className: "text-xs text-muted-foreground", children: "Transferring from:" })] }), _jsx("span", { className: "text-xs font-mono break-all", children: existingBapId }), _jsxs("div", { className: "flex items-center gap-2 mt-2", children: [_jsxs("svg", { width: "16", height: "16", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-label": "Transfer to", className: "text-muted-foreground", children: [_jsx("title", { children: "Transfer to" }), _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M16 17l-4 4m0 0l-4-4m4 4V3" })] }), _jsx("span", { className: "text-xs text-muted-foreground", children: "Transferring to:" })] }), _jsx("span", { className: "text-xs font-mono break-all", children: currentBapId })] }) }) })] }), _jsx(PasswordInput, { label: "Password for Other Account", value: password, onChange: setPassword, placeholder: "Enter encryption password", disabled: loading, required: true }), _jsx(ErrorDisplay, { error: error }), _jsxs("div", { className: "flex gap-3 justify-end", children: [_jsx(Button, { type: "button", variant: "secondary", onClick: resetForm, disabled: loading, children: "Back" }), _jsx(LoadingButton, { type: "submit", loading: loading, disabled: !password, children: "Transfer Link" })] })] }) })); const renderSwitchingMode = () => (_jsxs("div", { className: "flex flex-col items-center gap-4 py-8", 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: "Switching to your existing account..." })] })); const renderContent = () => { switch (mode) { case "choose": return renderChooseMode(); case "transfer": return renderTransferMode(); case "switching": return renderSwitchingMode(); default: return renderChooseMode(); } }; return (_jsx(AlertDialog, { open: isOpen, onOpenChange: (open) => !open && handleClose(), children: _jsxs(AlertDialogContent, { className: cn("max-w-[28rem] w-full", className), children: [_jsxs(AlertDialogTitle, { children: [provider, " Account Conflict"] }), _jsxs(AlertDialogDescription, { children: [mode === "choose" && "This account is already linked to another Bitcoin identity.", mode === "transfer" && "Enter your password to verify ownership and transfer the link.", mode === "switching" && "Switching to your existing account..."] }), _jsx("div", { className: "mt-4", children: renderContent() })] }) })); }