import { useState, useEffect, useCallback } from 'react'; import { useParams, useNavigate } from 'react-router-dom'; import styles from './Session.module.css'; interface Participant { partyId: string; name: string; status: 'waiting' | 'ready' | 'processing' | 'completed' | 'failed'; joinedAt: string; } interface SessionState { sessionId: string; walletName: string; threshold: { t: number; n: number }; status: 'waiting' | 'ready' | 'processing' | 'completed' | 'failed'; participants: Participant[]; currentRound: number; totalRounds: number; publicKey?: string; error?: string; } export default function Session() { const { sessionId } = useParams<{ sessionId: string }>(); const navigate = useNavigate(); const [session, setSession] = useState(null); const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(null); const fetchSessionStatus = useCallback(async () => { if (!sessionId) return; try { const result = await window.electronAPI.grpc.getSessionStatus(sessionId); if (result.success && result.session) { setSession(result.session); } else { setError(result.error || '获取会话状态失败'); } } catch (err) { setError('获取会话状态失败'); } finally { setIsLoading(false); } }, [sessionId]); useEffect(() => { fetchSessionStatus(); // 订阅会话事件 const unsubscribe = window.electronAPI.grpc.subscribeSessionEvents( sessionId!, (event: any) => { if (event.type === 'participant_joined') { setSession(prev => prev ? { ...prev, participants: [...prev.participants, event.participant] } : null); } else if (event.type === 'status_changed') { setSession(prev => prev ? { ...prev, status: event.status, currentRound: event.currentRound ?? prev.currentRound, } : null); } else if (event.type === 'completed') { setSession(prev => prev ? { ...prev, status: 'completed', publicKey: event.publicKey, } : null); // Auto-navigate to home after a short delay to show completion status setTimeout(() => { navigate('/'); }, 2000); } else if (event.type === 'failed') { setSession(prev => prev ? { ...prev, status: 'failed', error: event.error, } : null); } } ); return () => { unsubscribe(); }; }, [sessionId, fetchSessionStatus]); const getStatusText = (status: string) => { switch (status) { case 'waiting': return '等待参与方'; case 'ready': return '准备就绪'; case 'processing': return '密钥生成中'; case 'completed': return '已完成'; case 'failed': return '失败'; default: return status; } }; const getStatusClass = (status: string) => { switch (status) { case 'waiting': return styles.statusWaiting; case 'ready': return styles.statusReady; case 'processing': return styles.statusProcessing; case 'completed': return styles.statusCompleted; case 'failed': return styles.statusFailed; default: return ''; } }; const getParticipantStatusIcon = (status: string) => { switch (status) { case 'waiting': return '⏳'; case 'ready': return '✓'; case 'processing': return '⚡'; case 'completed': return '✓'; case 'failed': return '✗'; default: return '•'; } }; const handleCopyPublicKey = async () => { if (session?.publicKey) { try { await navigator.clipboard.writeText(session.publicKey); } catch (err) { console.error('Failed to copy:', err); } } }; if (isLoading) { return (

加载会话信息...

); } if (error || !session) { return (
!

加载失败

{error || '无法获取会话信息'}

); } return (

{session.walletName}

会话 ID: {session.sessionId}

{getStatusText(session.status)}
{/* 进度部分 */} {session.status === 'processing' && (
密钥生成进度 {session.currentRound} / {session.totalRounds}
)} {/* 参与方列表 */}

参与方 ({(session.participants || []).length} / {session.threshold?.n || 0})

{(session.participants || []).map((participant, index) => (
#{index + 1} {participant.name}
{getParticipantStatusIcon(participant.status)}
))} {Array.from({ length: Math.max(0, (session.threshold?.n || 0) - (session.participants || []).length) }).map((_, index) => (
#{(session.participants || []).length + index + 1} 等待加入...
))}
{/* 阈值信息 */} {session.threshold && (

阈值设置

{session.threshold.t}-of-{session.threshold.n} 需要 {session.threshold.t} 个参与方共同签名
)} {/* 完成状态 */} {session.status === 'completed' && session.publicKey && (

钱包公钥

{session.publicKey}

✓ 密钥份额已安全保存到本地

)} {/* 失败状态 */} {session.status === 'failed' && session.error && (
! {session.error}
)}
{session.status === 'completed' ? ( ) : session.status === 'failed' ? ( ) : ( )}
); }