fix(desktop): resolve lint warnings for react-refresh and unused import

- Extract useQRToken and useCountdown hooks to qr-hooks.ts so qr-code.tsx
  only exports components (fixes react-refresh/only-export-components)
- Remove unused useRef import from connect-step.tsx

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jiayuan Zhang 2026-02-14 01:38:04 +08:00
parent d6393c6718
commit eb274d5e0c
4 changed files with 65 additions and 62 deletions

View file

@ -1,7 +1,8 @@
import { useState, useEffect, useCallback, useMemo, useRef } from 'react'
import { useState, useCallback, useMemo } from 'react'
import { QRCodeSVG } from 'qrcode.react'
import { Button } from '@multica/ui/components/ui/button'
import { Copy, Check } from 'lucide-react'
import { useQRToken, useCountdown } from './qr-hooks'
// ============ Types ============
@ -22,65 +23,7 @@ export interface ConnectionQRCodeProps {
size?: number
}
// ============ Hooks ============
/** Generate a secure random token */
function generateToken(): string {
return crypto.randomUUID()
}
/**
* Hook to manage QR token lifecycle
* - Generates token on mount
* - Auto-refreshes when expired
* - Registers token with Hub
*/
export function useQRToken(agentId: string, expirySeconds: number) {
const [token, setToken] = useState(generateToken)
const [expiresAt, setExpiresAt] = useState(() => Date.now() + expirySeconds * 1000)
const refresh = useCallback(() => {
const newToken = generateToken()
const newExpiry = Date.now() + expirySeconds * 1000
setToken(newToken)
setExpiresAt(newExpiry)
window.electronAPI?.hub.registerToken(newToken, agentId, newExpiry)
}, [agentId, expirySeconds])
// Register initial token
useEffect(() => {
window.electronAPI?.hub.registerToken(token, agentId, expiresAt)
}, []) // eslint-disable-line react-hooks/exhaustive-deps
return { token, expiresAt, refresh }
}
/**
* Hook for countdown timer
* Returns remaining seconds, auto-updates every second
*/
export function useCountdown(expiresAt: number, onExpire: () => void) {
const [remaining, setRemaining] = useState(() =>
Math.max(0, Math.ceil((expiresAt - Date.now()) / 1000))
)
const onExpireRef = useRef(onExpire)
onExpireRef.current = onExpire
useEffect(() => {
// Reset when expiresAt changes
setRemaining(Math.max(0, Math.ceil((expiresAt - Date.now()) / 1000)))
const id = setInterval(() => {
const next = Math.max(0, Math.ceil((expiresAt - Date.now()) / 1000))
setRemaining(next)
if (next === 0) onExpireRef.current()
}, 1000)
return () => clearInterval(id)
}, [expiresAt])
return remaining
}
// Hooks are in ./qr-hooks.ts (separate file for react-refresh compatibility)
/**
* Hook for clipboard copy with feedback

View file

@ -0,0 +1,59 @@
import { useState, useEffect, useCallback, useRef } from 'react'
/** Generate a secure random token */
function generateToken(): string {
return crypto.randomUUID()
}
/**
* Hook to manage QR token lifecycle
* - Generates token on mount
* - Auto-refreshes when expired
* - Registers token with Hub
*/
export function useQRToken(agentId: string, expirySeconds: number) {
const [token, setToken] = useState(generateToken)
const [expiresAt, setExpiresAt] = useState(() => Date.now() + expirySeconds * 1000)
const refresh = useCallback(() => {
const newToken = generateToken()
const newExpiry = Date.now() + expirySeconds * 1000
setToken(newToken)
setExpiresAt(newExpiry)
window.electronAPI?.hub.registerToken(newToken, agentId, newExpiry)
}, [agentId, expirySeconds])
// Register initial token
useEffect(() => {
window.electronAPI?.hub.registerToken(token, agentId, expiresAt)
}, []) // eslint-disable-line react-hooks/exhaustive-deps
return { token, expiresAt, refresh }
}
/**
* Hook for countdown timer
* Returns remaining seconds, auto-updates every second
*/
export function useCountdown(expiresAt: number, onExpire: () => void) {
const [remaining, setRemaining] = useState(() =>
Math.max(0, Math.ceil((expiresAt - Date.now()) / 1000))
)
const onExpireRef = useRef(onExpire)
onExpireRef.current = onExpire
useEffect(() => {
// Reset when expiresAt changes
setRemaining(Math.max(0, Math.ceil((expiresAt - Date.now()) / 1000)))
const id = setInterval(() => {
const next = Math.max(0, Math.ceil((expiresAt - Date.now()) / 1000))
setRemaining(next)
if (next === 0) onExpireRef.current()
}, 1000)
return () => clearInterval(id)
}, [expiresAt])
return remaining
}

View file

@ -1,7 +1,8 @@
import { useState, useEffect } from 'react'
import { QRCodeSVG } from 'qrcode.react'
import { Loader2 } from 'lucide-react'
import { useQRToken, useCountdown, QRCodeFrame, ExpiryTimer } from './qr-code'
import { useQRToken, useCountdown } from './qr-hooks'
import { QRCodeFrame, ExpiryTimer } from './qr-code'
export interface TelegramConnectQRProps {
gateway: string

View file

@ -1,4 +1,4 @@
import { useEffect, useState, useCallback, useRef } from 'react'
import { useEffect, useState, useCallback } from 'react'
import { Button } from '@multica/ui/components/ui/button'
import { Separator } from '@multica/ui/components/ui/separator'
import { ChevronLeft, Info, Check, Smartphone } from 'lucide-react'