import { useEffect, useRef, useState } from 'react' import { APP_NAME } from '@/constants/app.constant' import { getMigrateUrl } from '@/services/setup.service' import { applicationConfigurationUrl, getAppConfig } from '@/services/abpConfig.service' interface LogLine { level: 'info' | 'warn' | 'error' | 'success' | 'restart' | 'done' message: string } type MigrationStatus = 'idle' | 'running' | 'success' | 'error' | 'restarting' const levelClass: Record = { info: 'text-gray-300', warn: 'text-yellow-400', error: 'text-red-400', success: 'text-green-400', restart: 'text-blue-400', done: 'text-blue-400', } const DatabaseSetup = () => { const [logs, setLogs] = useState([]) const [status, setStatus] = useState('idle') const [pollCountdown, setPollCountdown] = useState(0) const logEndRef = useRef(null) const eventSourceRef = useRef(null) const pollTimerRef = useRef | null>(null) // Auto-scroll to bottom when new logs arrive useEffect(() => { logEndRef.current?.scrollIntoView({ behavior: 'smooth' }) }, [logs]) // Cleanup on component unmount useEffect(() => { return () => { eventSourceRef.current?.close() if (pollTimerRef.current) clearTimeout(pollTimerRef.current) } }, []) const addLog = (level: LogLine['level'], message: string) => { setLogs((prev) => [...prev, { level, message }]) } // ── Poll ABP config endpoint until server is ready ────────────── const pollUntilReady = () => { setStatus('restarting') let attempt = 0 let successCount = 0 const REQUIRED_SUCCESS = 2 // sunucunun kararlı olduğunu doğrulamak için arka arkaya 2 başarılı yanıt const tick = async () => { attempt++ setPollCountdown(attempt) try { const res = await fetch( `${import.meta.env.VITE_API_URL ?? ''}${applicationConfigurationUrl(false)}`, { method: 'GET', headers: { Accept: 'application/json' }, cache: 'no-store', }, ) if (res.status === 200) { try { const json = await res.json() // ABP config yanıtının geçerli olduğunu doğrula (currentUser alanı her zaman bulunur) if (json && typeof json.currentUser === 'object') { successCount++ if (successCount >= REQUIRED_SUCCESS) { // Sunucu tamamen hazır — yönlendir window.location.href = '/' return } // Bir sonraki doğrulama denemesi pollTimerRef.current = setTimeout(tick, 1000) return } } catch { // JSON parse hatası — sunucu henüz tam hazır değil } } // Başarısız — sıfırla ve tekrar dene successCount = 0 } catch { // Sunucu henüz yanıt vermiyor — bekleniyor, tekrar dene successCount = 0 } pollTimerRef.current = setTimeout(tick, 2000) } // İlk denemeden önce kısa bir bekleme (sunucunun kapanma süresi) pollTimerRef.current = setTimeout(tick, 3000) } const startMigration = () => { if (status === 'running') return setLogs([]) setStatus('running') addLog('info', 'Starting migration...') const url = getMigrateUrl() const es = new EventSource(url) eventSourceRef.current = es es.onmessage = (event) => { try { const data = JSON.parse(event.data) as { level?: string; message?: string } const level = (data.level ?? 'info') as LogLine['level'] const message = data.message ?? event.data if (level === 'done') { es.close() eventSourceRef.current = null // If we received a "restart" event, switch to poll mode; otherwise keep success/error state setStatus((prev) => { if (prev === 'running') return 'error' // failed — no restart event received return prev }) return } addLog(level, message) if (level === 'success') { setStatus('success') } else if (level === 'error') { setStatus('error') } else if (level === 'restart') { // Backend is stopping the minimal app — start polling pollUntilReady() } } catch { addLog('info', event.data) } } es.onerror = () => { es.close() eventSourceRef.current = null setStatus((prev) => (prev === 'running' ? 'error' : prev)) addLog('error', 'Server connection lost or migration could not be completed.') } } return (
{/* Header */}

{APP_NAME}

Initial Setup — Creating Database

{/* Status Card */}
{/* Card Header */}
{status === 'idle' && 'Ready to Setup'} {status === 'running' && 'Migration Running...'} {status === 'success' && 'Migration Completed ✓'} {status === 'restarting' && `Server Restarting... (attempt ${pollCountdown})`} {status === 'error' && 'Migration Failed ✗'}
{logs.length} log lines
{/* Log Terminal */}
{logs.length === 0 ? (

Logs will appear here when migration starts...

) : ( logs.map((line, i) => (
{String(i + 1).padStart(4, '0')} {line.message}
)) )}
{/* Action Area */}
{status === 'idle' && 'Database not found. Press the button to start migration.'} {status === 'running' && 'Please wait, migration is in progress...'} {status === 'success' && 'Migration completed. Server is restarting...'} {status === 'restarting' && 'Waiting for application server to be ready, you will be redirected automatically...'} {status === 'error' && 'Review the errors in the logs, fix the issue, and try again.'}
{(status === 'idle' || status === 'error') && ( )} {status === 'restarting' && (
Waiting...
)}

This page is only visible when the database does not exist.

) } // ─── Status Indicator ──────────────────────────────────────────────────────── const StatusIndicator = ({ status }: { status: MigrationStatus }) => { const cls: Record = { idle: 'bg-gray-500', running: 'bg-yellow-400 animate-pulse', success: 'bg-green-500', restarting: 'bg-blue-400 animate-ping', error: 'bg-red-500', } return } export default DatabaseSetup