Files
meet-hub/src/components/admin/settings/IntegrasiTab.tsx
gpt-engineer-app[bot] e569c2cf7e Changes
2025-12-19 16:02:31 +00:00

282 lines
10 KiB
TypeScript

import { useEffect, useState } from 'react';
import { supabase } from '@/integrations/supabase/client';
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { toast } from '@/hooks/use-toast';
import { Puzzle, Webhook, MessageSquare, Calendar, Mail, Link as LinkIcon } from 'lucide-react';
interface IntegrationSettings {
id?: string;
integration_n8n_base_url: string;
integration_whatsapp_number: string;
integration_whatsapp_url: string;
integration_google_calendar_id: string;
integration_email_provider: string;
integration_email_api_base_url: string;
integration_privacy_url: string;
integration_terms_url: string;
}
const emptySettings: IntegrationSettings = {
integration_n8n_base_url: '',
integration_whatsapp_number: '',
integration_whatsapp_url: '',
integration_google_calendar_id: '',
integration_email_provider: 'smtp',
integration_email_api_base_url: '',
integration_privacy_url: '/privacy',
integration_terms_url: '/terms',
};
export function IntegrasiTab() {
const [settings, setSettings] = useState<IntegrationSettings>(emptySettings);
const [loading, setLoading] = useState(true);
const [saving, setSaving] = useState(false);
useEffect(() => {
fetchSettings();
}, []);
const fetchSettings = async () => {
const { data, error } = await supabase
.from('platform_settings')
.select('*')
.single();
if (data) {
setSettings({
id: data.id,
integration_n8n_base_url: data.integration_n8n_base_url || '',
integration_whatsapp_number: data.integration_whatsapp_number || '',
integration_whatsapp_url: data.integration_whatsapp_url || '',
integration_google_calendar_id: data.integration_google_calendar_id || '',
integration_email_provider: data.integration_email_provider || 'smtp',
integration_email_api_base_url: data.integration_email_api_base_url || '',
integration_privacy_url: data.integration_privacy_url || '/privacy',
integration_terms_url: data.integration_terms_url || '/terms',
});
}
setLoading(false);
};
const saveSettings = async () => {
setSaving(true);
const payload = { ...settings };
delete payload.id;
if (settings.id) {
const { error } = await supabase
.from('platform_settings')
.update(payload)
.eq('id', settings.id);
if (error) toast({ title: 'Error', description: error.message, variant: 'destructive' });
else toast({ title: 'Berhasil', description: 'Pengaturan integrasi disimpan' });
} else {
const { data, error } = await supabase
.from('platform_settings')
.insert(payload)
.select()
.single();
if (error) toast({ title: 'Error', description: error.message, variant: 'destructive' });
else {
setSettings({ ...settings, id: data.id });
toast({ title: 'Berhasil', description: 'Pengaturan integrasi disimpan' });
}
}
setSaving(false);
};
if (loading) return <div className="animate-pulse h-64 bg-muted rounded-md" />;
return (
<div className="space-y-6">
{/* n8n / Webhook */}
<Card className="border-2 border-border">
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Webhook className="w-5 h-5" />
n8n / Webhook
</CardTitle>
<CardDescription>
Konfigurasi URL untuk integrasi otomatisasi
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="space-y-2">
<Label>Base URL n8n / Integrasi</Label>
<Input
value={settings.integration_n8n_base_url}
onChange={(e) => setSettings({ ...settings, integration_n8n_base_url: e.target.value })}
placeholder="https://automation.domain.com"
className="border-2"
/>
<p className="text-sm text-muted-foreground">
Digunakan sebagai target default untuk webhook lanjutan. webhook_url per template tetap harus URL lengkap.
</p>
</div>
</CardContent>
</Card>
{/* WhatsApp */}
<Card className="border-2 border-border">
<CardHeader>
<CardTitle className="flex items-center gap-2">
<MessageSquare className="w-5 h-5" />
WhatsApp
</CardTitle>
<CardDescription>
Nomor kontak untuk dukungan dan notifikasi
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="space-y-2">
<Label>Nomor WhatsApp Dukungan</Label>
<Input
value={settings.integration_whatsapp_number}
onChange={(e) => setSettings({ ...settings, integration_whatsapp_number: e.target.value })}
placeholder="+62812xxxx"
className="border-2"
/>
<p className="text-sm text-muted-foreground">
Ditampilkan di konfirmasi konsultasi
</p>
</div>
<div className="space-y-2">
<Label>URL WhatsApp Click-to-Chat (Opsional)</Label>
<Input
value={settings.integration_whatsapp_url}
onChange={(e) => setSettings({ ...settings, integration_whatsapp_url: e.target.value })}
placeholder="https://wa.me/62812..."
className="border-2"
/>
</div>
</div>
</CardContent>
</Card>
{/* Google Calendar */}
<Card className="border-2 border-border">
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Calendar className="w-5 h-5" />
Google Calendar
</CardTitle>
<CardDescription>
Untuk pembuatan event konsultasi otomatis
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="space-y-2">
<Label>ID Kalender Google untuk Konsultasi</Label>
<Input
value={settings.integration_google_calendar_id}
onChange={(e) => setSettings({ ...settings, integration_google_calendar_id: e.target.value })}
placeholder="your-calendar@gmail.com"
className="border-2"
/>
<p className="text-sm text-muted-foreground">
Backend/n8n akan menggunakan ID ini untuk membuat event
</p>
</div>
</CardContent>
</Card>
{/* Email Provider */}
<Card className="border-2 border-border">
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Mail className="w-5 h-5" />
Provider Email (Opsional)
</CardTitle>
<CardDescription>
Konfigurasi alternatif selain SMTP
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="space-y-2">
<Label>Provider Email Eksternal</Label>
<Select
value={settings.integration_email_provider}
onValueChange={(value) => setSettings({ ...settings, integration_email_provider: value })}
>
<SelectTrigger className="border-2">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="smtp">SMTP (Default)</SelectItem>
<SelectItem value="resend">Resend</SelectItem>
<SelectItem value="elasticemail">ElasticEmail</SelectItem>
<SelectItem value="mailgun">Mailgun</SelectItem>
<SelectItem value="sendgrid">SendGrid</SelectItem>
</SelectContent>
</Select>
</div>
<div className="space-y-2">
<Label>API Base URL Provider Email</Label>
<Input
value={settings.integration_email_api_base_url}
onChange={(e) => setSettings({ ...settings, integration_email_api_base_url: e.target.value })}
placeholder="https://api.resend.com"
className="border-2"
disabled={settings.integration_email_provider === 'smtp'}
/>
</div>
</div>
</CardContent>
</Card>
{/* Public Links */}
<Card className="border-2 border-border">
<CardHeader>
<CardTitle className="flex items-center gap-2">
<LinkIcon className="w-5 h-5" />
Link Publik
</CardTitle>
<CardDescription>
URL untuk halaman legal
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="space-y-2">
<Label>URL Kebijakan Privasi</Label>
<Input
value={settings.integration_privacy_url}
onChange={(e) => setSettings({ ...settings, integration_privacy_url: e.target.value })}
placeholder="/privacy"
className="border-2"
/>
</div>
<div className="space-y-2">
<Label>URL Syarat & Ketentuan</Label>
<Input
value={settings.integration_terms_url}
onChange={(e) => setSettings({ ...settings, integration_terms_url: e.target.value })}
placeholder="/terms"
className="border-2"
/>
</div>
</div>
<p className="text-sm text-muted-foreground">
Default: halaman internal. Bisa diganti dengan URL eksternal.
</p>
</CardContent>
</Card>
<Button onClick={saveSettings} disabled={saving} className="shadow-sm">
{saving ? 'Menyimpan...' : 'Simpan Pengaturan'}
</Button>
</div>
);
}