'use client'; import { useState } from 'react'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Eye, EyeOff, HardDrive, CheckCircle2, AlertCircle } from 'lucide-react'; import { saveHetznerConfig, configureHetznerCors } from '@/actions/settings'; interface HetznerConfig { hetzner_endpoint: string; hetzner_access_key: string; hetzner_secret_key: string; hetzner_bucket_name: string; } interface Props { initialConfig: HetznerConfig; } export function HetznerConfigForm({ initialConfig }: Props) { const [form, setForm] = useState(initialConfig); const [showSecret, setShowSecret] = useState(false); const [loading, setLoading] = useState(false); const [status, setStatus] = useState<'idle' | 'success' | 'error'>('idle'); const [errorMsg, setErrorMsg] = useState(null); const [corsLoading, setCorsLoading] = useState(false); const [corsStatus, setCorsStatus] = useState<'idle' | 'success' | 'error'>('idle'); const [corsError, setCorsError] = useState(null); function handleChange(key: keyof HetznerConfig) { return (e: React.ChangeEvent) => { setForm((prev) => ({ ...prev, [key]: e.target.value })); setStatus('idle'); }; } async function handleSubmit(e: React.FormEvent) { e.preventDefault(); setLoading(true); setStatus('idle'); setErrorMsg(null); try { await saveHetznerConfig(form); setStatus('success'); } catch (err: unknown) { setStatus('error'); setErrorMsg(err instanceof Error ? err.message : 'Failed to save configuration.'); } finally { setLoading(false); } } async function handleConfigureCors() { setCorsLoading(true); setCorsStatus('idle'); setCorsError(null); try { await configureHetznerCors(); setCorsStatus('success'); } catch (err: unknown) { setCorsStatus('error'); setCorsError(err instanceof Error ? err.message : 'Failed to configure CORS.'); } finally { setCorsLoading(false); } } return ( Hetzner Object Storage Configure the Hetzner S3-compatible bucket used for high-res deliverable storage. These values override the environment variables and take effect immediately — no rebuild required.
{status === 'success' && (
Configuration saved — changes are live immediately.
)} {status === 'error' && (
{errorMsg}
)}

Batch Upload — CORS

Required once so browsers can upload large MOV files directly to Hetzner, bypassing the Cloudflare / Nginx size limit.

{corsStatus === 'success' && (
CORS policy applied — batch MOV uploads should now work.
)} {corsStatus === 'error' && (
{corsError}
)}
); }