324 lines
12 KiB
TypeScript
324 lines
12 KiB
TypeScript
import { useEffect, useState } from "react";
|
|
import DashboardLayout from "@/components/DashboardLayout";
|
|
import { trpc } from "@/lib/trpc";
|
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
|
import { Label } from "@/components/ui/label";
|
|
import { Input } from "@/components/ui/input";
|
|
import { Button } from "@/components/ui/button";
|
|
import { toast } from "sonner";
|
|
import { Switch } from "@/components/ui/switch";
|
|
import { Alert, AlertDescription } from "@/components/ui/alert";
|
|
import { AlertCircle, CheckCircle2, Mail, Send } from "lucide-react";
|
|
|
|
export default function AdminEmailConfig() {
|
|
const { data: config, isLoading, refetch } = trpc.emailConfig.get.useQuery();
|
|
const upsertMutation = trpc.emailConfig.upsert.useMutation();
|
|
const testEmailMutation = trpc.emailConfig.testEmail.useMutation();
|
|
|
|
const [formData, setFormData] = useState({
|
|
provider: "resend",
|
|
apiKey: "",
|
|
fromEmail: "",
|
|
fromName: "Formation Manager Itinova",
|
|
mode: "simulation" as "simulation" | "production",
|
|
domainVerified: false,
|
|
});
|
|
|
|
const [testEmail, setTestEmail] = useState("");
|
|
|
|
// Charger la configuration existante
|
|
useEffect(() => {
|
|
if (config) {
|
|
setFormData({
|
|
provider: config.provider,
|
|
apiKey: config.apiKey || "",
|
|
fromEmail: config.fromEmail,
|
|
fromName: config.fromName,
|
|
mode: config.mode,
|
|
domainVerified: config.domainVerified,
|
|
});
|
|
}
|
|
}, [config]);
|
|
|
|
const handleSubmit = (e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
|
|
upsertMutation.mutate(formData, {
|
|
onSuccess: () => {
|
|
toast.success("Configuration enregistrée avec succès");
|
|
refetch();
|
|
},
|
|
onError: (error) => {
|
|
toast.error(`Erreur: ${error.message}`);
|
|
},
|
|
});
|
|
};
|
|
|
|
const handleTestEmail = () => {
|
|
if (!testEmail) {
|
|
toast.error("Veuillez saisir une adresse email");
|
|
return;
|
|
}
|
|
|
|
testEmailMutation.mutate(
|
|
{ toEmail: testEmail },
|
|
{
|
|
onSuccess: (data) => {
|
|
if (data.success) {
|
|
toast.success(data.message || "Email de test envoyé avec succès");
|
|
} else {
|
|
toast.error(data.message || "Échec de l'envoi de l'email de test");
|
|
}
|
|
},
|
|
onError: (error) => {
|
|
toast.error(`Erreur: ${error.message}`);
|
|
},
|
|
}
|
|
);
|
|
};
|
|
|
|
if (isLoading) {
|
|
return (
|
|
<DashboardLayout>
|
|
<div className="container py-8">
|
|
<p>Chargement...</p>
|
|
</div>
|
|
</DashboardLayout>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<DashboardLayout>
|
|
<div className="container py-8 max-w-4xl">
|
|
<div className="mb-8">
|
|
<h1 className="text-3xl font-bold">Configuration des emails</h1>
|
|
<p className="text-muted-foreground mt-2">
|
|
Configurez l'envoi d'emails via Resend et basculez entre mode simulation et production
|
|
</p>
|
|
</div>
|
|
|
|
<div className="grid gap-6">
|
|
{/* Statut actuel */}
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle className="flex items-center gap-2">
|
|
<Mail className="h-5 w-5" />
|
|
Statut actuel
|
|
</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="space-y-4">
|
|
<div className="flex items-center justify-between p-4 border rounded-lg">
|
|
<div>
|
|
<p className="font-medium">Mode d'envoi</p>
|
|
<p className="text-sm text-muted-foreground">
|
|
{formData.mode === "simulation"
|
|
? "Les emails sont simulés et envoyés comme notifications"
|
|
: "Les emails sont envoyés via Resend"}
|
|
</p>
|
|
</div>
|
|
<div className={`px-3 py-1 rounded-full text-sm font-medium ${
|
|
formData.mode === "production"
|
|
? "bg-green-100 text-green-800"
|
|
: "bg-yellow-100 text-yellow-800"
|
|
}`}>
|
|
{formData.mode === "production" ? "Production" : "Simulation"}
|
|
</div>
|
|
</div>
|
|
|
|
{formData.apiKey && (
|
|
<Alert>
|
|
<CheckCircle2 className="h-4 w-4" />
|
|
<AlertDescription>
|
|
Clé API Resend configurée
|
|
</AlertDescription>
|
|
</Alert>
|
|
)}
|
|
|
|
{!formData.apiKey && (
|
|
<Alert>
|
|
<AlertCircle className="h-4 w-4" />
|
|
<AlertDescription>
|
|
Aucune clé API configurée. Les emails seront simulés.
|
|
</AlertDescription>
|
|
</Alert>
|
|
)}
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* Formulaire de configuration */}
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Configuration Resend</CardTitle>
|
|
<CardDescription>
|
|
Configurez votre compte Resend pour envoyer de vrais emails
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<form onSubmit={handleSubmit} className="space-y-6">
|
|
<div className="space-y-2">
|
|
<Label htmlFor="apiKey">Clé API Resend *</Label>
|
|
<Input
|
|
id="apiKey"
|
|
type="password"
|
|
placeholder="re_..."
|
|
value={formData.apiKey}
|
|
onChange={(e) => setFormData({ ...formData, apiKey: e.target.value })}
|
|
/>
|
|
<p className="text-sm text-muted-foreground">
|
|
Obtenez votre clé API sur{" "}
|
|
<a
|
|
href="https://resend.com/api-keys"
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
className="text-primary hover:underline"
|
|
>
|
|
resend.com/api-keys
|
|
</a>
|
|
</p>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="fromEmail">Email expéditeur *</Label>
|
|
<Input
|
|
id="fromEmail"
|
|
type="email"
|
|
placeholder="noreply@votredomaine.com"
|
|
value={formData.fromEmail}
|
|
onChange={(e) => setFormData({ ...formData, fromEmail: e.target.value })}
|
|
required
|
|
/>
|
|
<p className="text-sm text-muted-foreground">
|
|
L'adresse email doit être vérifiée dans votre compte Resend
|
|
</p>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="fromName">Nom de l'expéditeur *</Label>
|
|
<Input
|
|
id="fromName"
|
|
type="text"
|
|
placeholder="Formation Manager Itinova"
|
|
value={formData.fromName}
|
|
onChange={(e) => setFormData({ ...formData, fromName: e.target.value })}
|
|
required
|
|
/>
|
|
</div>
|
|
|
|
<div className="flex items-center justify-between p-4 border rounded-lg">
|
|
<div className="space-y-0.5">
|
|
<Label htmlFor="mode">Mode production</Label>
|
|
<p className="text-sm text-muted-foreground">
|
|
Activer l'envoi réel d'emails (désactiver pour simuler)
|
|
</p>
|
|
</div>
|
|
<Switch
|
|
id="mode"
|
|
checked={formData.mode === "production"}
|
|
onCheckedChange={(checked) =>
|
|
setFormData({ ...formData, mode: checked ? "production" : "simulation" })
|
|
}
|
|
/>
|
|
</div>
|
|
|
|
<div className="flex gap-3">
|
|
<Button type="submit" disabled={upsertMutation.isPending}>
|
|
{upsertMutation.isPending ? "Enregistrement..." : "Enregistrer la configuration"}
|
|
</Button>
|
|
</div>
|
|
</form>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* Test d'envoi */}
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle className="flex items-center gap-2">
|
|
<Send className="h-5 w-5" />
|
|
Test d'envoi
|
|
</CardTitle>
|
|
<CardDescription>
|
|
Envoyez un email de test pour vérifier votre configuration
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="space-y-4">
|
|
<div className="space-y-2">
|
|
<Label htmlFor="testEmail">Adresse email de test</Label>
|
|
<Input
|
|
id="testEmail"
|
|
type="email"
|
|
placeholder="votre@email.com"
|
|
value={testEmail}
|
|
onChange={(e) => setTestEmail(e.target.value)}
|
|
/>
|
|
</div>
|
|
|
|
<Button
|
|
onClick={handleTestEmail}
|
|
disabled={testEmailMutation.isPending || !testEmail}
|
|
variant="outline"
|
|
>
|
|
{testEmailMutation.isPending ? "Envoi en cours..." : "Envoyer un email de test"}
|
|
</Button>
|
|
|
|
{formData.mode === "simulation" && (
|
|
<Alert>
|
|
<AlertCircle className="h-4 w-4" />
|
|
<AlertDescription>
|
|
Mode simulation actif. L'email de test sera simulé et envoyé comme notification au propriétaire.
|
|
</AlertDescription>
|
|
</Alert>
|
|
)}
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* Documentation */}
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Guide de configuration</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="space-y-4 text-sm">
|
|
<div>
|
|
<h4 className="font-medium mb-2">1. Créer un compte Resend</h4>
|
|
<p className="text-muted-foreground">
|
|
Inscrivez-vous gratuitement sur{" "}
|
|
<a href="https://resend.com" target="_blank" rel="noopener noreferrer" className="text-primary hover:underline">
|
|
resend.com
|
|
</a>{" "}
|
|
(100 emails/jour gratuits)
|
|
</p>
|
|
</div>
|
|
|
|
<div>
|
|
<h4 className="font-medium mb-2">2. Vérifier votre domaine</h4>
|
|
<p className="text-muted-foreground">
|
|
Ajoutez et vérifiez votre domaine dans les paramètres Resend pour pouvoir envoyer des emails
|
|
</p>
|
|
</div>
|
|
|
|
<div>
|
|
<h4 className="font-medium mb-2">3. Obtenir la clé API</h4>
|
|
<p className="text-muted-foreground">
|
|
Générez une clé API dans la section "API Keys" de votre compte Resend
|
|
</p>
|
|
</div>
|
|
|
|
<div>
|
|
<h4 className="font-medium mb-2">4. Configurer et tester</h4>
|
|
<p className="text-muted-foreground">
|
|
Saisissez vos informations ci-dessus, enregistrez, puis testez l'envoi avant de passer en mode production
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
</div>
|
|
</DashboardLayout>
|
|
);
|
|
}
|