import React, { useState, useEffect, useRef, useCallback } from 'react';
import { getWallets, Wallet, WalletAccount } from '@talismn/connect-wallets';
import { createWidget, DotPassportClient, type UserScores } from '@dotpassport/sdk';
interface TalismanDotPassportProps {
apiKey: string;
}
export function TalismanDotPassport({ apiKey }: TalismanDotPassportProps) {
const [wallet, setWallet] = useState<Wallet | null>(null);
const [accounts, setAccounts] = useState<WalletAccount[]>([]);
const [selectedAccount, setSelectedAccount] = useState<WalletAccount | null>(null);
const [scores, setScores] = useState<UserScores | null>(null);
const [isConnecting, setIsConnecting] = useState(false);
const [error, setError] = useState<string | null>(null);
const widgetRef = useRef<ReturnType<typeof createWidget>>();
const widgetContainerRef = useRef<HTMLDivElement>(null);
// Check if Talisman is installed
const isTalismanInstalled = useCallback(() => {
const wallets = getWallets();
return wallets.some(w => w.extensionName === 'talisman' && w.installed);
}, []);
// Connect to Talisman
const connectWallet = useCallback(async () => {
setIsConnecting(true);
setError(null);
try {
const wallets = getWallets();
const talisman = wallets.find(w => w.extensionName === 'talisman');
if (!talisman?.installed) {
throw new Error('Talisman is not installed');
}
await talisman.enable('DotPassport App');
const userAccounts = await talisman.getAccounts();
if (userAccounts.length === 0) {
throw new Error('No accounts found');
}
setWallet(talisman);
setAccounts(userAccounts);
setSelectedAccount(userAccounts[0]);
// Subscribe to account changes
talisman.subscribeAccounts((newAccounts) => {
setAccounts(newAccounts);
if (newAccounts.length > 0 && !newAccounts.find(a => a.address === selectedAccount?.address)) {
setSelectedAccount(newAccounts[0]);
}
});
} catch (err) {
setError(err instanceof Error ? err.message : 'Failed to connect');
} finally {
setIsConnecting(false);
}
}, [selectedAccount?.address]);
// Fetch reputation data
useEffect(() => {
if (!selectedAccount) return;
const client = new DotPassportClient({ apiKey });
client.getScores(selectedAccount.address)
.then(setScores)
.catch(err => setError(err.message));
}, [selectedAccount, apiKey]);
// Mount/update widget
useEffect(() => {
if (!selectedAccount || !widgetContainerRef.current) return;
if (widgetRef.current) {
widgetRef.current.update({ address: selectedAccount.address });
} else {
widgetRef.current = createWidget({
apiKey,
address: selectedAccount.address,
type: 'reputation',
theme: 'light',
showCategories: true
});
widgetRef.current.mount(widgetContainerRef.current);
}
return () => {
widgetRef.current?.destroy();
widgetRef.current = undefined;
};
}, [selectedAccount, apiKey]);
// Disconnect
const disconnect = useCallback(() => {
widgetRef.current?.destroy();
widgetRef.current = undefined;
setWallet(null);
setAccounts([]);
setSelectedAccount(null);
setScores(null);
}, []);
// Not installed
if (!isTalismanInstalled()) {
return (
<div className="talisman-connect">
<p>Talisman wallet is not installed.</p>
<a
href="https://talisman.xyz/download"
target="_blank"
rel="noopener noreferrer"
>
Install Talisman
</a>
</div>
);
}
// Not connected
if (!wallet) {
return (
<div className="talisman-connect">
<button onClick={connectWallet} disabled={isConnecting}>
{isConnecting ? 'Connecting...' : 'Connect Talisman'}
</button>
{error && <p className="error">{error}</p>}
</div>
);
}
// Connected
return (
<div className="talisman-dotpassport">
<div className="account-selector">
<label>Account:</label>
<select
value={selectedAccount?.address}
onChange={(e) => {
const account = accounts.find(a => a.address === e.target.value);
setSelectedAccount(account || null);
}}
>
{accounts.map(account => (
<option key={account.address} value={account.address}>
{account.name} ({account.address.slice(0, 8)}...{account.address.slice(-6)})
</option>
))}
</select>
<button onClick={disconnect}>Disconnect</button>
</div>
{scores && (
<div className="scores-summary">
<h3>Reputation Score: {scores.totalScore}</h3>
</div>
)}
<div ref={widgetContainerRef} className="widget-container" />
{error && <p className="error">{error}</p>}
</div>
);
}
// Usage in your app:
// <TalismanDotPassport apiKey="your_api_key" />