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:
parent
d6393c6718
commit
eb274d5e0c
4 changed files with 65 additions and 62 deletions
|
|
@ -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
|
||||
|
|
|
|||
59
apps/desktop/src/renderer/src/components/qr-hooks.ts
Normal file
59
apps/desktop/src/renderer/src/components/qr-hooks.ts
Normal 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
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue