import { useState, useEffect, useCallback } from 'react' import { Cloud, ArrowRight, ExternalLink, Info, CheckCircle2, XCircle, RefreshCw } from 'lucide-react' import clsx from 'clsx' import { useI18n } from '../i18n' export default function VercelSync({ onMessage, authFetch }) { const { t } = useI18n() const [vercelToken, setVercelToken] = useState('') const [projectId, setProjectId] = useState('') const [teamId, setTeamId] = useState('') const [loading, setLoading] = useState(false) const [result, setResult] = useState(null) const [preconfig, setPreconfig] = useState(null) const [syncStatus, setSyncStatus] = useState(null) const apiFetch = authFetch || fetch const fetchSyncStatus = useCallback(async () => { try { const res = await apiFetch('/admin/vercel/status') if (res.ok) { const data = await res.json() setSyncStatus(data) } } catch (e) { console.error('Failed to fetch sync status:', e) } }, [apiFetch]) useEffect(() => { const loadPreconfig = async () => { try { const res = await apiFetch('/admin/vercel/config') if (res.ok) { const data = await res.json() setPreconfig(data) if (data.project_id) setProjectId(data.project_id) if (data.team_id) setTeamId(data.team_id) } } catch (e) { console.error('Failed to load preconfig:', e) } } loadPreconfig() fetchSyncStatus() // Poll every 15s to detect config changes const interval = setInterval(fetchSyncStatus, 15000) return () => clearInterval(interval) }, [fetchSyncStatus]) const handleSync = async () => { const tokenToUse = preconfig?.has_token && !vercelToken ? '__USE_PRECONFIG__' : vercelToken if (!tokenToUse && !preconfig?.has_token) { onMessage('error', t('vercel.tokenRequired')) return } if (!projectId) { onMessage('error', t('vercel.projectRequired')) return } setLoading(true) setResult(null) try { const res = await apiFetch('/admin/vercel/sync', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ vercel_token: tokenToUse, project_id: projectId, team_id: teamId || undefined, }), }) const data = await res.json() if (res.ok) { setResult({ ...data, success: true }) onMessage('success', data.message) fetchSyncStatus() } else { setResult({ ...data, success: false }) onMessage('error', data.detail || t('vercel.syncFailed')) } } catch (e) { onMessage('error', t('vercel.networkError')) } finally { setLoading(false) } } return (
{t('vercel.description')}
{syncStatus?.last_sync_time && (
{t('vercel.projectIdHint')}
{t('vercel.redeployHint')}
{result.message}
{result.deployment_url && ( )}{t('vercel.steps.one')}
{t('vercel.steps.two')}
{t('vercel.steps.three')} DS2API_CONFIG_JSON
{t('vercel.steps.four')}