'use client'
import { useCallback, useEffect, useState, type FormEvent } from 'react'
import Image from 'next/image'
import { useTranslations } from 'next-intl'
import { Button } from '@/components/ui/button'
import { LanguageSwitcherSelect } from '@/components/ui/language-switcher'
type SetupStep = 'form' | 'creating'
interface ProgressStep {
label: string
status: 'pending' | 'active' | 'done' | 'error'
}
function getInitialProgress(t: (key: string) => string): ProgressStep[] {
return [
{ label: t('validatingCredentials'), status: 'pending' },
{ label: t('creatingAdminAccount'), status: 'pending' },
{ label: t('configuringSession'), status: 'pending' },
{ label: t('launchingDashboard'), status: 'pending' },
]
}
function ProgressIndicator({ steps }: { steps: ProgressStep[] }) {
return (
{steps.map((step, i) => (
{step.status === 'done' && (
)}
{step.status === 'active' && (
)}
{step.status === 'pending' && (
)}
{step.status === 'error' && (
)}
{step.label}
))}
)
}
export default function SetupPage() {
const t = useTranslations('auth')
const tc = useTranslations('common')
const [username, setUsername] = useState('admin')
const [password, setPassword] = useState('')
const [confirmPassword, setConfirmPassword] = useState('')
const [displayName, setDisplayName] = useState('')
const [error, setError] = useState('')
const [step, setStep] = useState('form')
const [progress, setProgress] = useState(() => getInitialProgress(t))
const [checking, setChecking] = useState(true)
const [setupAvailable, setSetupAvailable] = useState(false)
useEffect(() => {
fetch('/api/setup')
.then((res) => res.json())
.then((data) => {
if (!data.needsSetup) {
window.location.href = '/login'
return
}
setSetupAvailable(true)
setChecking(false)
})
.catch(() => {
setError(t('failedToCheckSetup'))
setChecking(false)
})
}, [t])
const updateProgress = useCallback((index: number, status: ProgressStep['status']) => {
setProgress((prev) => prev.map((s, i) => (i === index ? { ...s, status } : s)))
}, [])
const handleSubmit = useCallback(async (e: FormEvent) => {
e.preventDefault()
setError('')
if (password !== confirmPassword) {
setError(t('passwordsDoNotMatch'))
return
}
if (password.length < 12) {
setError(t('passwordTooShort'))
return
}
setStep('creating')
setProgress(getInitialProgress(t))
// Step 1: Validating
updateProgress(0, 'active')
await new Promise((r) => setTimeout(r, 400))
updateProgress(0, 'done')
// Step 2: Creating account
updateProgress(1, 'active')
try {
const res = await fetch('/api/setup', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
username,
password,
displayName: displayName || undefined,
}),
})
if (!res.ok) {
const data = await res.json().catch(() => null)
updateProgress(1, 'error')
setError(data?.error || t('setupFailed'))
// Allow retry after a brief pause
await new Promise((r) => setTimeout(r, 1500))
setStep('form')
setProgress(getInitialProgress(t))
return
}
updateProgress(1, 'done')
// Step 3: Configuring session
updateProgress(2, 'active')
await new Promise((r) => setTimeout(r, 500))
updateProgress(2, 'done')
// Step 4: Launching
updateProgress(3, 'active')
await new Promise((r) => setTimeout(r, 300))
updateProgress(3, 'done')
await new Promise((r) => setTimeout(r, 500))
window.location.href = '/'
} catch {
updateProgress(1, 'error')
setError(t('networkError'))
await new Promise((r) => setTimeout(r, 1500))
setStep('form')
setProgress(getInitialProgress(t))
}
}, [username, password, confirmPassword, displayName, updateProgress, t])
if (checking) {
return (
{t('checkingSetupStatus')}
)
}
if (!setupAvailable) {
return null
}
return (
{step === 'form' ? t('welcomeToMC') : t('settingUpMC')}
{step === 'form'
? t('createAdminToStart')
: t('creatingAdmin')}
{step === 'creating' && (
)}
{step === 'form' && (
<>
{error && (
{error}
)}
{t('firstTimeSetupOnly')}
>
)}
)
}