Files
mule-image/frontend/src/components/auth/SetupPage.tsx
dtoro 7efac4354e ui: migrate to shadcn/ui primitives across dialogs, filters, and forms
Adopts shadcn/ui components (Dialog, Button, Input, Select, Popover,
Command, Checkbox, Switch, Toggle, Calendar, etc.) across the app,
replacing hand-rolled modals, dropdowns, and form controls. Adds a
reusable cmdk-backed MultiSelect for the Type, Tags, and Flag filters
so all multi-value filter popovers share one component and layout.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 09:07:20 +02:00

111 lines
3.2 KiB
TypeScript

import { useState, type FormEvent } from 'react'
import { useAuth } from '../../contexts/AuthContext'
import api from '../../services/api'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import { Alert, AlertDescription } from '@/components/ui/alert'
export function SetupPage() {
const { onSetupComplete } = useAuth()
const [username, setUsername] = useState('')
const [password, setPassword] = useState('')
const [confirmPassword, setConfirmPassword] = useState('')
const [error, setError] = useState<string | null>(null)
const [loading, setLoading] = useState(false)
const handleSubmit = async (e: FormEvent) => {
e.preventDefault()
setError(null)
if (password !== confirmPassword) {
setError('Passwords do not match.')
return
}
if (password.length < 6) {
setError('Password must be at least 6 characters.')
return
}
if (username.trim().length < 2) {
setError('Username must be at least 2 characters.')
return
}
setLoading(true)
try {
const res = await api.post('/auth/setup', {
username: username.trim(),
password,
})
const { access_token, refresh_token } = res.data
await onSetupComplete(access_token, refresh_token)
} catch (err: any) {
setError(
err.response?.data?.detail ?? 'Setup failed. Please try again.',
)
} finally {
setLoading(false)
}
}
return (
<div className="flex min-h-screen items-center justify-center bg-bg px-4">
<form
onSubmit={handleSubmit}
className="w-full max-w-sm space-y-5 rounded-lg border border-border bg-surface p-8 shadow-xl"
>
<div className="space-y-1 text-center">
<h1 className="text-xl font-semibold text-text">Welcome to Mulita</h1>
<p className="text-sm text-text-muted">
Create your admin account to get started.
</p>
</div>
{error && (
<Alert variant="destructive">
<AlertDescription>{error}</AlertDescription>
</Alert>
)}
<div className="space-y-1.5">
<Label htmlFor="setup-user">Username</Label>
<Input
id="setup-user"
type="text"
value={username}
onChange={(e) => setUsername(e.target.value)}
required
autoFocus
/>
</div>
<div className="space-y-1.5">
<Label htmlFor="setup-pass">Password</Label>
<Input
id="setup-pass"
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
required
/>
</div>
<div className="space-y-1.5">
<Label htmlFor="setup-confirm">Confirm Password</Label>
<Input
id="setup-confirm"
type="password"
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)}
required
/>
</div>
<Button type="submit" disabled={loading} className="w-full">
{loading ? 'Creating account\u2026' : 'Create Admin Account'}
</Button>
</form>
</div>
)
}