Fix email template preview UX and debug template loading

- Convert EmailTemplatePreview from bottom card to modal Dialog component
- Replace problematic bottom preview with clean modal popup
- Add proper modal state management (open/close handlers)
- Debug template loading with comprehensive error handling and logging
- Add user feedback for template seeding and loading errors
- Improve fetchData() and seedTemplates() with try-catch blocks
- Add console logging for debugging template initialization

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
dwindown
2025-12-22 20:57:33 +07:00
parent f743a79674
commit 1982033ac4
2 changed files with 242 additions and 142 deletions

View File

@@ -346,36 +346,93 @@ export function NotifikasiTab() {
const [loading, setLoading] = useState(true);
const [expandedTemplates, setExpandedTemplates] = useState<Set<string>>(new Set());
const [testingTemplate, setTestingTemplate] = useState<string | null>(null);
const [selectedTemplate, setSelectedTemplate] = useState<NotificationTemplate | null>(null);
const [previewMode, setPreviewMode] = useState<'master' | 'content'>('master');
const [previewTemplate, setPreviewTemplate] = useState<NotificationTemplate | null>(null);
const [isPreviewOpen, setIsPreviewOpen] = useState(false);
useEffect(() => {
fetchData();
}, []);
const fetchData = async () => {
// Fetch templates
const { data: templatesData } = await supabase.from('notification_templates').select('*').order('key');
if (templatesData && templatesData.length > 0) {
setTemplates(templatesData);
} else {
// Seed default templates if none exist
await seedTemplates();
try {
console.log('Fetching templates...');
// Fetch templates
const { data: templatesData, error: fetchError } = await supabase.from('notification_templates').select('*').order('key');
if (fetchError) {
console.error('Error fetching templates:', fetchError);
toast({
title: 'Error',
description: 'Gagal mengambil template: ' + fetchError.message,
variant: 'destructive'
});
setLoading(false);
return;
}
console.log('Templates data:', templatesData);
if (templatesData && templatesData.length > 0) {
console.log('Setting templates from database:', templatesData.length);
setTemplates(templatesData);
} else {
console.log('No templates found, seeding default templates...');
// Seed default templates if none exist
await seedTemplates();
}
} catch (error) {
console.error('Unexpected error in fetchData:', error);
toast({
title: 'Error',
description: 'Terjadi kesalahan tak terduga saat mengambil data',
variant: 'destructive'
});
} finally {
setLoading(false);
}
setLoading(false);
};
const seedTemplates = async () => {
const toInsert = DEFAULT_TEMPLATES.map(t => ({
key: t.key,
name: t.name,
is_active: false,
email_subject: t.defaultSubject,
email_body_html: t.defaultBody,
webhook_url: '',
}));
const { data, error } = await supabase.from('notification_templates').insert(toInsert).select();
if (!error && data) setTemplates(data);
try {
console.log('Seeding default templates...');
const toInsert = DEFAULT_TEMPLATES.map(t => ({
key: t.key,
name: t.name,
is_active: false,
email_subject: t.defaultSubject,
email_body_html: t.defaultBody,
webhook_url: '',
}));
console.log('Inserting templates:', toInsert.length);
const { data, error } = await supabase.from('notification_templates').insert(toInsert).select();
if (error) {
console.error('Error seeding templates:', error);
toast({
title: 'Error',
description: 'Gagal membuat template default: ' + error.message,
variant: 'destructive'
});
return;
}
console.log('Templates seeded successfully:', data);
if (data) {
setTemplates(data);
toast({
title: 'Berhasil',
description: `Berhasil membuat ${data.length} template default`
});
}
} catch (error) {
console.error('Unexpected error in seedTemplates:', error);
toast({
title: 'Error',
description: 'Terjadi kesalahan saat membuat template default',
variant: 'destructive'
});
}
};
@@ -587,7 +644,8 @@ export function NotifikasiTab() {
<Button
onClick={() => {
updateTemplate(template);
setSelectedTemplate(template);
setPreviewTemplate(template);
setIsPreviewOpen(true);
}}
className="shadow-sm flex-1"
>
@@ -620,33 +678,14 @@ export function NotifikasiTab() {
</CardContent>
</Card>
{/* Consolidated Email Preview */}
{selectedTemplate && (
<Card className="border-2 border-border">
<CardHeader>
<CardTitle className="flex items-center justify-between">
<span>Preview: {selectedTemplate.name}</span>
<Button
variant="outline"
size="sm"
onClick={() => setSelectedTemplate(null)}
>
Tutup Preview
</Button>
</CardTitle>
<CardDescription>
Preview template email dengan master styling
</CardDescription>
</CardHeader>
<CardContent>
<EmailTemplatePreview
template={selectedTemplate}
onTest={sendTestEmail}
isTestSending={testingTemplate === selectedTemplate.id}
/>
</CardContent>
</Card>
)}
{/* Modal Email Preview */}
<EmailTemplatePreview
template={previewTemplate!}
open={isPreviewOpen}
onClose={() => setIsPreviewOpen(false)}
onTest={sendTestEmail}
isTestSending={testingTemplate === previewTemplate?.id}
/>
</div>
);
}