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:
@@ -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>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user