UNPKG

bigblocks

Version:

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

111 lines (110 loc) 9.58 kB
"use client"; import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { MagnifyingGlassIcon, Pencil1Icon, PersonIcon, PlusIcon, RocketIcon, } from "@radix-ui/react-icons"; import { useState } from "react"; import { useBitcoinAuth } from "../../hooks/useBitcoinAuth.js"; import { useBapProfileSync } from "../bap-identity/hooks/useBapProfileSync.js"; import { Button } from "../ui/button.js"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "../ui/tabs.js"; import { ProfileEditor } from "./ProfileEditor.js"; import { ProfilePublisher } from "./ProfilePublisher.js"; import { ProfileSwitcher } from "./ProfileSwitcher.js"; import { ProfileViewer } from "./ProfileViewer.js"; /** * ProfileManager - Complete profile management interface * * Features: * - View current profile details * - Edit profile information * - Publish profiles to blockchain * - Switch between multiple profiles * - Create new profiles * - Tabbed interface for different actions */ export function ProfileManager({ user: userProp, onProfileUpdate, onProfilePublish, onProfileCreate, onProfileSwitch, showPublisher = true, maxProfiles = 10, className = "", enableProfileSync = true, maxDiscoveryAttempts = 50, }) { const { user: authUser, createProfile, switchProfile } = useBitcoinAuth(); const user = userProp || authUser; const [activeTab, setActiveTab] = useState("view"); const [isCreating, setIsCreating] = useState(false); // Profile synchronization const profileSync = useBapProfileSync({ autoSync: false, // Manual sync only in ProfileManager maxDiscoveryAttempts, }); if (!user) { return (_jsx("div", { className: className, children: _jsx("p", { className: "text-base text-muted-foreground", children: "Please sign in to manage your profiles." }) })); } const activeProfile = user.profiles.find((p) => p.id === user.activeProfileId) || user.profiles[0]; if (!activeProfile) { return (_jsx("div", { className: className, children: _jsxs("div", { className: "flex flex-col gap-4 items-center py-8", children: [_jsx(PersonIcon, { width: "48", height: "48", className: "text-muted-foreground" }), _jsx("h3", { className: "text-base font-medium", children: "No Profiles Yet" }), _jsx("p", { className: "text-sm text-muted-foreground", children: "Create your first profile to get started" }), _jsxs(Button, { size: "lg", onClick: async () => { setIsCreating(true); try { const newProfile = onProfileCreate ? await onProfileCreate() : await createProfile(); if (onProfileSwitch) { onProfileSwitch(newProfile.id); } else if (switchProfile) { switchProfile(newProfile.id); } } catch (error) { console.error("Failed to create profile:", error); } finally { setIsCreating(false); } }, disabled: isCreating, children: [_jsx(PlusIcon, { className: "h-4 w-4 mr-2" }), isCreating ? "Creating..." : "Create First Profile"] })] }) })); } const handleProfileUpdate = async (updates) => { if (onProfileUpdate) { await onProfileUpdate({ ...activeProfile, ...updates }); } setActiveTab("view"); }; const handleProfilePublish = async (profileId) => { if (onProfilePublish) { return await onProfilePublish(profileId); } throw new Error("No publish handler available"); }; const handleProfileSwitch = (profileId) => { if (onProfileSwitch) { onProfileSwitch(profileId); } else if (switchProfile) { switchProfile(profileId); } }; const handleProfileCreate = async () => { setIsCreating(true); try { const newProfile = onProfileCreate ? await onProfileCreate() : await createProfile(); handleProfileSwitch(newProfile.id); } catch (error) { console.error("Failed to create profile:", error); } finally { setIsCreating(false); } }; return (_jsx("div", { className: className, children: _jsxs("div", { className: "flex flex-col gap-4", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("h2", { className: "text-2xl font-bold", children: "Profile Management" }), user.profiles.length > 1 && (_jsx(ProfileSwitcher, { profiles: user.profiles, activeProfileId: user.activeProfileId, onSwitch: handleProfileSwitch, onCreate: user.profiles.length < maxProfiles ? handleProfileCreate : undefined, maxProfiles: maxProfiles }))] }), _jsxs(Tabs, { value: activeTab, onValueChange: (value) => setActiveTab(value), children: [_jsxs(TabsList, { children: [_jsxs(TabsTrigger, { value: "view", className: "flex items-center gap-2", children: [_jsx(PersonIcon, { className: "h-4 w-4" }), "View Profile"] }), _jsxs(TabsTrigger, { value: "edit", className: "flex items-center gap-2", children: [_jsx(Pencil1Icon, { className: "h-4 w-4" }), "Edit Profile"] }), showPublisher && !activeProfile.isPublished && (_jsxs(TabsTrigger, { value: "publish", className: "flex items-center gap-2", children: [_jsx(RocketIcon, { className: "h-4 w-4" }), "Publish"] })), enableProfileSync && (_jsxs(TabsTrigger, { value: "sync", className: "flex items-center gap-2", children: [_jsx(MagnifyingGlassIcon, { className: "h-4 w-4" }), "Discover Profiles"] }))] }), _jsxs("div", { className: "pt-4", children: [_jsx(TabsContent, { value: "view", children: _jsx(ProfileViewer, { profile: activeProfile, onEdit: () => setActiveTab("edit"), onPublish: !activeProfile.isPublished ? () => setActiveTab("publish") : undefined }) }), _jsx(TabsContent, { value: "edit", children: _jsx(ProfileEditor, { profile: activeProfile, onSave: handleProfileUpdate, onCancel: () => setActiveTab("view") }) }), showPublisher && (_jsx(TabsContent, { value: "publish", children: _jsx(ProfilePublisher, { profile: activeProfile, onPublish: handleProfilePublish, onSuccess: (txid) => { console.log("Profile published:", txid); setActiveTab("view"); }, onError: (error) => { console.error("Publishing failed:", error); } }) })), enableProfileSync && (_jsx(TabsContent, { value: "sync", children: _jsxs("div", { children: [_jsx("h3", { className: "text-lg font-bold mb-3", children: "Discover Additional Profiles" }), _jsx("p", { className: "text-sm text-muted-foreground mb-4", children: "Scan the blockchain for additional BAP identities associated with your master backup." }), profileSync.isScanning && (_jsxs("div", { className: "mb-4", children: [_jsxs("p", { className: "text-sm mb-2", children: ["Scanning for profiles... ", profileSync.progress, "%"] }), _jsx("div", { className: "flex justify-between items-center", children: _jsxs("p", { className: "text-xs text-muted-foreground", children: ["Current ID: ", profileSync.currentId, " | Found:", " ", profileSync.foundCount] }) })] })), profileSync.isSuccess && profileSync.result && (_jsxs("div", { className: "mb-4 p-3 bg-green-50 border border-green-200 rounded-lg", children: [_jsx("p", { className: "text-sm font-medium text-green-800", children: "Discovery Complete!" }), _jsxs("p", { className: "text-sm text-green-700", children: ["Found ", profileSync.result.totalFound, " profiles total.", profileSync.result.updatedBackup ? " Your backup has been updated with new identities." : " No new identities discovered."] })] })), profileSync.error && (_jsx("div", { className: "mb-4 p-3 bg-red-50 border border-red-200 rounded-lg", children: _jsxs("p", { className: "text-sm text-red-700", children: ["Error: ", profileSync.error.message] }) })), _jsxs("div", { className: "flex gap-3", children: [_jsxs(Button, { variant: "default", onClick: profileSync.syncProfiles, disabled: profileSync.isScanning, children: [_jsx(MagnifyingGlassIcon, { className: "h-4 w-4 mr-2" }), profileSync.isScanning ? "Scanning..." : "Start Discovery"] }), (profileSync.error || profileSync.isSuccess) && (_jsx(Button, { variant: "outline", onClick: profileSync.resetSync, children: "Reset" }))] })] }) }))] })] }), user.profiles.length < maxProfiles && user.profiles.length === 1 && (_jsx("div", { className: "flex justify-center pt-4", children: _jsxs(Button, { variant: "outline", size: "sm", onClick: handleProfileCreate, disabled: isCreating, children: [_jsx(PlusIcon, { className: "h-4 w-4 mr-2" }), isCreating ? "Creating..." : "Create Additional Profile"] }) }))] }) })); }