refactor(admin): split email-templates page.tsx into colocated components
Extract tabs nav, templates grid, editor split view, settings form, logs table, and data-loading/actions hook into _components/ and _hooks/. page.tsx reduced from 816 to 88 LOC. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
'use client'
|
||||
|
||||
import { Settings } from '../_types'
|
||||
|
||||
interface SettingsTabProps {
|
||||
settings: Settings
|
||||
saving: boolean
|
||||
onChange: (s: Settings) => void
|
||||
onSave: () => void
|
||||
}
|
||||
|
||||
export function SettingsTab({ settings, saving, onChange, onSave }: SettingsTabProps) {
|
||||
const update = (field: keyof Settings, value: string) => {
|
||||
onChange({ ...settings, [field]: value })
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="max-w-2xl space-y-6">
|
||||
<h2 className="text-lg font-semibold">E-Mail-Einstellungen</h2>
|
||||
|
||||
<div className="space-y-4">
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">Absender-Name</label>
|
||||
<input
|
||||
type="text"
|
||||
value={settings.sender_name || ''}
|
||||
onChange={e => update('sender_name', e.target.value)}
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">Absender-E-Mail</label>
|
||||
<input
|
||||
type="email"
|
||||
value={settings.sender_email || ''}
|
||||
onChange={e => update('sender_email', e.target.value)}
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">Antwort-Adresse</label>
|
||||
<input
|
||||
type="email"
|
||||
value={settings.reply_to || ''}
|
||||
onChange={e => update('reply_to', e.target.value)}
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm"
|
||||
placeholder="optional"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">Firmenname</label>
|
||||
<input
|
||||
type="text"
|
||||
value={settings.company_name || ''}
|
||||
onChange={e => update('company_name', e.target.value)}
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">Logo URL</label>
|
||||
<input
|
||||
type="url"
|
||||
value={settings.logo_url || ''}
|
||||
onChange={e => update('logo_url', e.target.value)}
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm"
|
||||
placeholder="https://..."
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">Primaerfarbe</label>
|
||||
<div className="flex gap-2">
|
||||
<input
|
||||
type="color"
|
||||
value={settings.primary_color || '#4F46E5'}
|
||||
onChange={e => update('primary_color', e.target.value)}
|
||||
className="h-10 w-10 rounded cursor-pointer"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
value={settings.primary_color || ''}
|
||||
onChange={e => update('primary_color', e.target.value)}
|
||||
className="flex-1 px-3 py-2 border border-gray-300 rounded-lg text-sm font-mono"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">Sekundaerfarbe</label>
|
||||
<div className="flex gap-2">
|
||||
<input
|
||||
type="color"
|
||||
value={settings.secondary_color || '#7C3AED'}
|
||||
onChange={e => update('secondary_color', e.target.value)}
|
||||
className="h-10 w-10 rounded cursor-pointer"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
value={settings.secondary_color || ''}
|
||||
onChange={e => update('secondary_color', e.target.value)}
|
||||
className="flex-1 px-3 py-2 border border-gray-300 rounded-lg text-sm font-mono"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">Firmenadresse</label>
|
||||
<textarea
|
||||
value={settings.company_address || ''}
|
||||
onChange={e => update('company_address', e.target.value)}
|
||||
rows={2}
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">Footer-Text</label>
|
||||
<textarea
|
||||
value={settings.footer_text || ''}
|
||||
onChange={e => update('footer_text', e.target.value)}
|
||||
rows={3}
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={onSave}
|
||||
disabled={saving}
|
||||
className="px-4 py-2 bg-purple-600 text-white rounded-lg hover:bg-purple-700 disabled:opacity-50"
|
||||
>
|
||||
{saving ? 'Speichern...' : 'Einstellungen speichern'}
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user