feat(co-sign): add invite code display in CoSignSession page

- Add invite_code retrieval in GetSignSessionStatus (backend)
- Add inviteCode to cosign:getSessionStatus response (frontend IPC)
- Add inviteCode to SessionState and display UI in CoSignSession

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
hailin 2025-12-31 01:37:11 -08:00
parent cfbda7bbc7
commit 4d65b8dd83
3 changed files with 40 additions and 0 deletions

View File

@ -616,6 +616,13 @@ func (h *CoManagedHTTPHandler) GetSignSessionStatus(c *gin.Context) {
return return
} }
// Get invite_code from database
var inviteCode string
if h.db != nil {
row := h.db.QueryRowContext(ctx, `SELECT invite_code FROM mpc_sessions WHERE id = $1`, sessionID)
row.Scan(&inviteCode) // Ignore error, invite_code is optional
}
result := gin.H{ result := gin.H{
"session_id": sessionID, "session_id": sessionID,
"status": resp.Status, "status": resp.Status,
@ -626,6 +633,11 @@ func (h *CoManagedHTTPHandler) GetSignSessionStatus(c *gin.Context) {
"total_parties": resp.TotalParties, "total_parties": resp.TotalParties,
} }
// Add invite_code if available
if inviteCode != "" {
result["invite_code"] = inviteCode
}
// Add signature if sign completed // Add signature if sign completed
if resp.SessionType == "sign" && len(resp.Signature) > 0 { if resp.SessionType == "sign" && len(resp.Signature) > 0 {
result["signature"] = hex.EncodeToString(resp.Signature) result["signature"] = hex.EncodeToString(resp.Signature)

View File

@ -1839,6 +1839,7 @@ function setupIpcHandlers() {
sessionId: result?.session_id, sessionId: result?.session_id,
status: result?.status, status: result?.status,
joinedCount: result?.joined_count, joinedCount: result?.joined_count,
inviteCode: (result as { invite_code?: string })?.invite_code || '',
threshold: { threshold: {
t: result?.threshold_t || activeCoSignSession?.threshold?.t || 0, t: result?.threshold_t || activeCoSignSession?.threshold?.t || 0,
n: result?.threshold_n || activeCoSignSession?.threshold?.n || 0, n: result?.threshold_n || activeCoSignSession?.threshold?.n || 0,

View File

@ -26,6 +26,7 @@ interface SessionState {
sessionId: string; sessionId: string;
walletName: string; walletName: string;
messageHash: string; messageHash: string;
inviteCode?: string;
threshold: { t: number; n: number }; threshold: { t: number; n: number };
status: 'waiting' | 'ready' | 'processing' | 'completed' | 'failed'; status: 'waiting' | 'ready' | 'processing' | 'completed' | 'failed';
participants: Participant[]; participants: Participant[];
@ -59,6 +60,7 @@ export default function CoSignSession() {
sessionId: result.session.sessionId || sessionId, sessionId: result.session.sessionId || sessionId,
walletName: result.session.walletName || '', walletName: result.session.walletName || '',
messageHash: result.session.messageHash || '', messageHash: result.session.messageHash || '',
inviteCode: result.session.inviteCode || '',
threshold: result.session.threshold || { t: 0, n: 0 }, threshold: result.session.threshold || { t: 0, n: 0 },
status: mapStatus(result.session.status), status: mapStatus(result.session.status),
participants: (result.session.participants || []).map(p => ({ participants: (result.session.participants || []).map(p => ({
@ -341,6 +343,31 @@ export default function CoSignSession() {
</div> </div>
<div className={styles.content}> <div className={styles.content}>
{/* 邀请码 - 等待状态时显示 */}
{session.inviteCode && session.status === 'waiting' && (
<div className={styles.section}>
<h3 className={styles.sectionTitle}></h3>
<div className={styles.publicKeyWrapper}>
<code className={styles.publicKey}>{session.inviteCode}</code>
<button
className={styles.copyButton}
onClick={async () => {
try {
await navigator.clipboard.writeText(session.inviteCode!);
} catch (err) {
console.error('Failed to copy:', err);
}
}}
>
</button>
</div>
<p style={{ fontSize: '12px', color: 'var(--text-secondary)', marginTop: 'var(--spacing-xs)' }}>
使
</p>
</div>
)}
{/* 消息哈希 */} {/* 消息哈希 */}
{session.messageHash && ( {session.messageHash && (
<div className={styles.section}> <div className={styles.section}>