bigblocks
Version:
Complete Bitcoin UI component library - authentication, social, wallet, market, inscriptions, and blockchain interactions for React
106 lines (105 loc) • 10.1 kB
JavaScript
"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() })] }) }));
}