Replace SMTP configuration with Mailketing API

- Remove SMTP host/port/username/TLS configuration
- Add Mailkening API token configuration
- Update email provider dropdown (Mailketing only)
- Update test email function to use Mailketing API
- Update help text and validation

🤖 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 18:57:55 +07:00
parent 1fe0aa0b96
commit 7f918374f4

View File

@@ -9,18 +9,16 @@ import { Textarea } from '@/components/ui/textarea';
import { Alert, AlertDescription } from '@/components/ui/alert'; import { Alert, AlertDescription } from '@/components/ui/alert';
import { RichTextEditor } from '@/components/RichTextEditor'; import { RichTextEditor } from '@/components/RichTextEditor';
import { toast } from '@/hooks/use-toast'; import { toast } from '@/hooks/use-toast';
import { Mail, AlertTriangle, Send, ChevronDown, ChevronUp, Webhook } from 'lucide-react'; import { Mail, AlertTriangle, Send, ChevronDown, ChevronUp, Webhook, Key } from 'lucide-react';
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible'; import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
interface SmtpSettings { interface EmailProviderSettings {
id?: string; id?: string;
smtp_host: string; provider: 'mailketing';
smtp_port: number; api_token: string;
smtp_username: string; from_name: string;
smtp_password: string; from_email: string;
smtp_from_name: string;
smtp_from_email: string;
smtp_use_tls: boolean;
} }
interface NotificationTemplate { interface NotificationTemplate {
@@ -86,18 +84,15 @@ const DEFAULT_TEMPLATES: { key: string; name: string; defaultSubject: string; de
}, },
]; ];
const emptySmtp: SmtpSettings = { const emptyEmailSettings: EmailProviderSettings = {
smtp_host: '', provider: 'mailketing',
smtp_port: 587, api_token: '',
smtp_username: '', from_name: '',
smtp_password: '', from_email: '',
smtp_from_name: '',
smtp_from_email: '',
smtp_use_tls: true,
}; };
export function NotifikasiTab() { export function NotifikasiTab() {
const [smtp, setSmtp] = useState<SmtpSettings>(emptySmtp); const [emailSettings, setEmailSettings] = useState<EmailProviderSettings>(emptyEmailSettings);
const [templates, setTemplates] = useState<NotificationTemplate[]>([]); const [templates, setTemplates] = useState<NotificationTemplate[]>([]);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [saving, setSaving] = useState(false); const [saving, setSaving] = useState(false);
@@ -110,9 +105,9 @@ export function NotifikasiTab() {
}, []); }, []);
const fetchData = async () => { const fetchData = async () => {
// Fetch SMTP settings // Fetch email provider settings
const { data: smtpData } = await supabase.from('notification_settings').select('*').single(); const { data: emailData } = await supabase.from('notification_settings').select('*').single();
if (smtpData) setSmtp(smtpData); if (emailData) setEmailSettings(emailData);
// Fetch templates // Fetch templates
const { data: templatesData } = await supabase.from('notification_templates').select('*').order('key'); const { data: templatesData } = await supabase.from('notification_templates').select('*').order('key');
@@ -138,39 +133,44 @@ export function NotifikasiTab() {
if (!error && data) setTemplates(data); if (!error && data) setTemplates(data);
}; };
const saveSmtp = async () => { const saveEmailSettings = async () => {
setSaving(true); setSaving(true);
const payload = { ...smtp }; const payload = { ...emailSettings };
delete payload.id; delete payload.id;
if (smtp.id) { if (emailSettings.id) {
const { error } = await supabase.from('notification_settings').update(payload).eq('id', smtp.id); const { error } = await supabase.from('notification_settings').update(payload).eq('id', emailSettings.id);
if (error) toast({ title: 'Error', description: error.message, variant: 'destructive' }); if (error) toast({ title: 'Error', description: error.message, variant: 'destructive' });
else toast({ title: 'Berhasil', description: 'Pengaturan SMTP disimpan' }); else toast({ title: 'Berhasil', description: 'Pengaturan email disimpan' });
} else { } else {
const { data, error } = await supabase.from('notification_settings').insert(payload).select().single(); const { data, error } = await supabase.from('notification_settings').insert(payload).select().single();
if (error) toast({ title: 'Error', description: error.message, variant: 'destructive' }); if (error) toast({ title: 'Error', description: error.message, variant: 'destructive' });
else { setSmtp(data); toast({ title: 'Berhasil', description: 'Pengaturan SMTP disimpan' }); } else { setEmailSettings(data); toast({ title: 'Berhasil', description: 'Pengaturan email disimpan' }); }
} }
setSaving(false); setSaving(false);
}; };
const sendTestEmail = async () => { const sendTestEmail = async () => {
if (!testEmail) return toast({ title: 'Error', description: 'Masukkan email tujuan', variant: 'destructive' }); if (!testEmail) return toast({ title: 'Error', description: 'Masukkan email tujuan', variant: 'destructive' });
if (!isSmtpConfigured) return toast({ title: 'Error', description: 'Lengkapi konfigurasi SMTP terlebih dahulu', variant: 'destructive' }); if (!isEmailConfigured) return toast({ title: 'Error', description: 'Lengkapi konfigurasi email provider terlebih dahulu', variant: 'destructive' });
setSendingTest(true); setSendingTest(true);
try { try {
const { data, error } = await supabase.functions.invoke('send-email-v2', { const { data, error } = await supabase.functions.invoke('send-email-v2', {
body: { body: {
to: testEmail, to: testEmail,
smtp_host: smtp.smtp_host, api_token: emailSettings.api_token,
smtp_port: smtp.smtp_port, from_name: emailSettings.from_name,
smtp_username: smtp.smtp_username, from_email: emailSettings.from_email,
smtp_password: smtp.smtp_password, subject: 'Test Email dari Access Hub',
smtp_from_name: smtp.smtp_from_name, html_body: `
smtp_from_email: smtp.smtp_from_email, <h2>Test Email</h2>
smtp_use_tls: smtp.smtp_use_tls, <p>Ini adalah email uji coba dari aplikasi Access Hub Anda.</p>
<p>Jika Anda menerima email ini, konfigurasi Mailketing API sudah berfungsi dengan baik!</p>
<p>Kirim ke: ${testEmail}</p>
<br>
<p>Best regards,<br>Access Hub Team</p>
`,
}, },
}); });
@@ -205,98 +205,92 @@ export function NotifikasiTab() {
}); });
}; };
const isSmtpConfigured = smtp.smtp_host && smtp.smtp_username && smtp.smtp_password; const isEmailConfigured = emailSettings.api_token && emailSettings.from_email;
if (loading) return <div className="animate-pulse h-64 bg-muted rounded-md" />; if (loading) return <div className="animate-pulse h-64 bg-muted rounded-md" />;
return ( return (
<div className="space-y-6"> <div className="space-y-6">
{/* SMTP Settings */} {/* Email Provider Settings */}
<Card className="border-2 border-border"> <Card className="border-2 border-border">
<CardHeader> <CardHeader>
<CardTitle className="flex items-center gap-2"> <CardTitle className="flex items-center gap-2">
<Mail className="w-5 h-5" /> <Mail className="w-5 h-5" />
Pengaturan SMTP Pengaturan Email Provider
</CardTitle> </CardTitle>
<CardDescription>Konfigurasi server email untuk pengiriman notifikasi</CardDescription> <CardDescription>Konfigurasi provider email untuk pengiriman notifikasi</CardDescription>
</CardHeader> </CardHeader>
<CardContent className="space-y-4"> <CardContent className="space-y-4">
{!isSmtpConfigured && ( {!isEmailConfigured && (
<Alert variant="destructive" className="border-2"> <Alert variant="destructive" className="border-2">
<AlertTriangle className="w-4 h-4" /> <AlertTriangle className="w-4 h-4" />
<AlertDescription> <AlertDescription>
Konfigurasi SMTP belum lengkap. Email tidak akan terkirim. Konfigurasi email provider belum lengkap. Email tidak akan terkirim.
</AlertDescription> </AlertDescription>
</Alert> </Alert>
)} )}
<div className="grid grid-cols-1 md:grid-cols-2 gap-4"> <div className="space-y-4">
<div className="space-y-2"> <div className="space-y-2">
<Label>SMTP Host</Label> <Label>Provider Email</Label>
<Input <Select
value={smtp.smtp_host} value={emailSettings.provider}
onChange={(e) => setSmtp({ ...smtp, smtp_host: e.target.value })} onValueChange={(value: 'mailketing') => setEmailSettings({ ...emailSettings, provider: value })}
placeholder="smtp.example.com" >
className="border-2" <SelectTrigger className="border-2">
/> <SelectValue placeholder="Pilih provider email" />
</SelectTrigger>
<SelectContent>
<SelectItem value="mailketing">Mailketing</SelectItem>
</SelectContent>
</Select>
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
<Label>SMTP Port</Label> <Label className="flex items-center gap-2">
<Input <Key className="w-4 h-4" />
type="number" API Token
value={smtp.smtp_port} </Label>
onChange={(e) => setSmtp({ ...smtp, smtp_port: parseInt(e.target.value) || 587 })}
className="border-2"
/>
</div>
<div className="space-y-2">
<Label>Username</Label>
<Input
value={smtp.smtp_username}
onChange={(e) => setSmtp({ ...smtp, smtp_username: e.target.value })}
className="border-2"
/>
</div>
<div className="space-y-2">
<Label>Password</Label>
<Input <Input
type="password" type="password"
value={smtp.smtp_password} value={emailSettings.api_token}
onChange={(e) => setSmtp({ ...smtp, smtp_password: e.target.value })} onChange={(e) => setEmailSettings({ ...emailSettings, api_token: e.target.value })}
placeholder="Masukkan API token dari Mailketing"
className="border-2" className="border-2"
/> />
<p className="text-sm text-muted-foreground">
Dapatkan API token dari menu Integration di dashboard Mailketing
</p>
</div> </div>
<div className="space-y-2">
<Label>Nama Pengirim</Label>
<Input
value={smtp.smtp_from_name}
onChange={(e) => setSmtp({ ...smtp, smtp_from_name: e.target.value })}
placeholder="Nama Bisnis"
className="border-2"
/>
</div>
<div className="space-y-2">
<Label>Email Pengirim</Label>
<Input
type="email"
value={smtp.smtp_from_email}
onChange={(e) => setSmtp({ ...smtp, smtp_from_email: e.target.value })}
placeholder="noreply@example.com"
className="border-2"
/>
</div>
</div>
<div className="flex items-center space-x-2"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<Switch <div className="space-y-2">
checked={smtp.smtp_use_tls} <Label>Nama Pengirim</Label>
onCheckedChange={(checked) => setSmtp({ ...smtp, smtp_use_tls: checked })} <Input
/> value={emailSettings.from_name}
<Label>Gunakan TLS/SSL</Label> onChange={(e) => setEmailSettings({ ...emailSettings, from_name: e.target.value })}
placeholder="Nama Bisnis"
className="border-2"
/>
</div>
<div className="space-y-2">
<Label>Email Pengirim</Label>
<Input
type="email"
value={emailSettings.from_email}
onChange={(e) => setEmailSettings({ ...emailSettings, from_email: e.target.value })}
placeholder="info@domain.com"
className="border-2"
/>
<p className="text-sm text-muted-foreground">
Pastikan email sudah terdaftar di Mailketing
</p>
</div>
</div>
</div> </div>
<div className="flex gap-4 pt-4 border-t"> <div className="flex gap-4 pt-4 border-t">
<Button onClick={saveSmtp} disabled={saving}> <Button onClick={saveEmailSettings} disabled={saving}>
{saving ? 'Menyimpan...' : 'Simpan'} {saving ? 'Menyimpan...' : 'Simpan'}
</Button> </Button>
<div className="flex gap-2 flex-1"> <div className="flex gap-2 flex-1">
@@ -342,9 +336,10 @@ export function NotifikasiTab() {
</div> </div>
</div> </div>
<p className="text-xs mt-2 p-2 bg-background rounded border"> <p className="text-xs mt-2 p-2 bg-background rounded border">
<strong>Penting:</strong> Toggle "Aktifkan" hanya mengontrol pengiriman email. <strong>Penting:</strong> Email dikirim melalui Mailketing API. Pastikan API token valid
Jika <code>webhook_url</code> diisi, sistem tetap akan mengirim payload ke URL tersebut dan domain pengirim sudah terdaftar di Mailketing. Toggle "Aktifkan" hanya mengontrol
meskipun email dinonaktifkan. pengiriman email. Jika <code>webhook_url</code> diisi, sistem tetap akan mengirim payload
ke URL tersebut meskipun email dinonaktifkan.
</p> </p>
</div> </div>