Files
breakpilot-compliance/admin-compliance/app/sdk/email-templates/_hooks/useEmailTemplates.ts
Sharang Parnerkar ffae41237e 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>
2026-04-15 08:24:48 +02:00

228 lines
6.8 KiB
TypeScript

'use client'
import { useCallback, useEffect, useState } from 'react'
import {
API_BASE,
EmailTemplate,
SendLog,
Settings,
TabId,
TemplateType,
TemplateVersion,
getHeaders,
} from '../_types'
export function useEmailTemplates(activeTab: TabId) {
const [templates, setTemplates] = useState<EmailTemplate[]>([])
const [templateTypes, setTemplateTypes] = useState<TemplateType[]>([])
const [settings, setSettings] = useState<Settings | null>(null)
const [logs, setLogs] = useState<SendLog[]>([])
const [logsTotal, setLogsTotal] = useState(0)
const [loading, setLoading] = useState(true)
const [error, setError] = useState<string | null>(null)
const [selectedCategory, setSelectedCategory] = useState<string | null>(null)
// Editor state
const [selectedTemplate, setSelectedTemplate] = useState<EmailTemplate | null>(null)
const [editorSubject, setEditorSubject] = useState('')
const [editorHtml, setEditorHtml] = useState('')
const [editorVersion, setEditorVersion] = useState<TemplateVersion | null>(null)
const [saving, setSaving] = useState(false)
const [previewHtml, setPreviewHtml] = useState<string | null>(null)
// Settings form
const [settingsForm, setSettingsForm] = useState<Settings | null>(null)
const [savingSettings, setSavingSettings] = useState(false)
const loadTemplates = useCallback(async () => {
try {
const url = selectedCategory ? `${API_BASE}?category=${selectedCategory}` : API_BASE
const res = await fetch(url, { headers: getHeaders() })
if (!res.ok) throw new Error(`HTTP ${res.status}`)
const data = await res.json()
setTemplates(Array.isArray(data) ? data : [])
} catch (e: any) {
setError(e.message)
}
}, [selectedCategory])
const loadTypes = useCallback(async () => {
try {
const res = await fetch(`${API_BASE}/types`, { headers: getHeaders() })
if (res.ok) {
const data = await res.json()
setTemplateTypes(Array.isArray(data) ? data : [])
}
} catch { /* ignore */ }
}, [])
const loadSettings = useCallback(async () => {
try {
const res = await fetch(`${API_BASE}/settings`, { headers: getHeaders() })
if (res.ok) {
const data = await res.json()
setSettings(data)
setSettingsForm(data)
}
} catch { /* ignore */ }
}, [])
const loadLogs = useCallback(async () => {
try {
const res = await fetch(`${API_BASE}/logs?limit=50`, { headers: getHeaders() })
if (res.ok) {
const data = await res.json()
setLogs(data.logs || [])
setLogsTotal(data.total || 0)
}
} catch { /* ignore */ }
}, [])
useEffect(() => {
setLoading(true)
Promise.all([loadTemplates(), loadTypes(), loadSettings()])
.finally(() => setLoading(false))
}, [loadTemplates, loadTypes, loadSettings])
useEffect(() => {
if (activeTab === 'logs') loadLogs()
}, [activeTab, loadLogs])
useEffect(() => {
loadTemplates()
}, [selectedCategory, loadTemplates])
const openEditor = useCallback(async (template: EmailTemplate) => {
setSelectedTemplate(template)
setPreviewHtml(null)
if (template.latest_version) {
setEditorSubject(template.latest_version.subject)
setEditorHtml(template.latest_version.body_html)
setEditorVersion(template.latest_version)
} else {
// Load default content
try {
const res = await fetch(`${API_BASE}/default/${template.template_type}`, { headers: getHeaders() })
if (res.ok) {
const data = await res.json()
setEditorSubject(data.default_subject || '')
setEditorHtml(data.default_body_html || '')
}
} catch { /* ignore */ }
setEditorVersion(null)
}
}, [])
const saveVersion = useCallback(async () => {
if (!selectedTemplate) return
setSaving(true)
try {
const res = await fetch(`${API_BASE}/${selectedTemplate.id}/versions`, {
method: 'POST',
headers: getHeaders(),
body: JSON.stringify({
version: editorVersion ? `${parseFloat(editorVersion.version) + 0.1}` : '1.0',
language: 'de',
subject: editorSubject,
body_html: editorHtml,
}),
})
if (!res.ok) throw new Error(`HTTP ${res.status}`)
const version = await res.json()
setEditorVersion(version)
await loadTemplates()
} catch (e: any) {
setError(e.message)
} finally {
setSaving(false)
}
}, [selectedTemplate, editorSubject, editorHtml, editorVersion, loadTemplates])
const publishVersion = useCallback(async () => {
if (!editorVersion) return
setSaving(true)
try {
const res = await fetch(`${API_BASE}/versions/${editorVersion.id}/publish`, {
method: 'POST',
headers: getHeaders(),
})
if (!res.ok) throw new Error(`HTTP ${res.status}`)
const updated = await res.json()
setEditorVersion(updated)
await loadTemplates()
} catch (e: any) {
setError(e.message)
} finally {
setSaving(false)
}
}, [editorVersion, loadTemplates])
const loadPreview = useCallback(async () => {
if (!editorVersion) return
try {
const res = await fetch(`${API_BASE}/versions/${editorVersion.id}/preview`, {
method: 'POST',
headers: getHeaders(),
body: JSON.stringify({ variables: {} }),
})
if (res.ok) {
const data = await res.json()
setPreviewHtml(data.body_html)
}
} catch { /* ignore */ }
}, [editorVersion])
const saveSettings2 = useCallback(async () => {
if (!settingsForm) return
setSavingSettings(true)
try {
const res = await fetch(`${API_BASE}/settings`, {
method: 'PUT',
headers: getHeaders(),
body: JSON.stringify(settingsForm),
})
if (res.ok) {
const data = await res.json()
setSettings(data)
setSettingsForm(data)
}
} catch (e: any) {
setError(e.message)
} finally {
setSavingSettings(false)
}
}, [settingsForm])
const initializeDefaults = useCallback(async () => {
try {
const res = await fetch(`${API_BASE}/initialize`, {
method: 'POST',
headers: getHeaders(),
})
if (res.ok) {
await loadTemplates()
}
} catch (e: any) {
setError(e.message)
}
}, [loadTemplates])
return {
// Data
templates, templateTypes, settings, logs, logsTotal, loading, error,
selectedCategory,
// Editor
selectedTemplate, editorSubject, editorHtml, editorVersion, saving, previewHtml,
// Settings
settingsForm, savingSettings,
// Setters
setError, setSelectedCategory,
setEditorSubject, setEditorHtml,
setSettingsForm,
// Actions
openEditor, saveVersion, publishVersion, loadPreview,
saveSettings2, initializeDefaults,
}
}