Changes
Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com>
This commit is contained in:
co-authored by
renee-png
parent
1b454bf090
commit
fbf23c1c2f
@@ -8,7 +8,8 @@ import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { Loader2, Mail, Send, KeyRound } from "lucide-react";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Loader2, Mail, Send, KeyRound, History } from "lucide-react";
|
||||
import { toast } from "sonner";
|
||||
|
||||
export const Route = createFileRoute("/settings/smtp")({
|
||||
@@ -23,10 +24,22 @@ const EMPTY = {
|
||||
from_email: "",
|
||||
from_name: "",
|
||||
reply_to: "",
|
||||
default_bcc: "",
|
||||
enabled: true,
|
||||
notes: "",
|
||||
};
|
||||
|
||||
interface EmailLog {
|
||||
id: string;
|
||||
sent_at: string;
|
||||
to_addresses: string[];
|
||||
bcc_addresses: string[];
|
||||
subject: string;
|
||||
status: string;
|
||||
error_message: string | null;
|
||||
context: string | null;
|
||||
}
|
||||
|
||||
function SmtpSettingsPage() {
|
||||
const { user, isAdmin } = useAuth();
|
||||
const [loading, setLoading] = useState(true);
|
||||
@@ -35,15 +48,24 @@ function SmtpSettingsPage() {
|
||||
const [recordId, setRecordId] = useState<string | null>(null);
|
||||
const [form, setForm] = useState({ ...EMPTY });
|
||||
const [testTo, setTestTo] = useState("");
|
||||
const [logs, setLogs] = useState<EmailLog[]>([]);
|
||||
|
||||
const load = async () => {
|
||||
setLoading(true);
|
||||
const { data } = await supabase
|
||||
.from("smtp_settings")
|
||||
.select("*")
|
||||
.order("updated_at", { ascending: false })
|
||||
.limit(1)
|
||||
.maybeSingle();
|
||||
const [settingsRes, logsRes] = await Promise.all([
|
||||
supabase
|
||||
.from("smtp_settings")
|
||||
.select("*")
|
||||
.order("updated_at", { ascending: false })
|
||||
.limit(1)
|
||||
.maybeSingle(),
|
||||
supabase
|
||||
.from("email_logs")
|
||||
.select("id, sent_at, to_addresses, bcc_addresses, subject, status, error_message, context")
|
||||
.order("sent_at", { ascending: false })
|
||||
.limit(25),
|
||||
]);
|
||||
const data = settingsRes.data;
|
||||
if (data) {
|
||||
setRecordId(data.id);
|
||||
setForm({
|
||||
@@ -54,10 +76,12 @@ function SmtpSettingsPage() {
|
||||
from_email: data.from_email ?? "",
|
||||
from_name: data.from_name ?? "",
|
||||
reply_to: data.reply_to ?? "",
|
||||
default_bcc: (data as any).default_bcc ?? "",
|
||||
enabled: data.enabled ?? true,
|
||||
notes: data.notes ?? "",
|
||||
});
|
||||
}
|
||||
setLogs((logsRes.data as EmailLog[]) ?? []);
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
@@ -83,6 +107,7 @@ function SmtpSettingsPage() {
|
||||
from_email: form.from_email.trim(),
|
||||
from_name: form.from_name || null,
|
||||
reply_to: form.reply_to || null,
|
||||
default_bcc: form.default_bcc.trim() || null,
|
||||
enabled: form.enabled,
|
||||
notes: form.notes || null,
|
||||
updated_by: user?.id,
|
||||
@@ -111,6 +136,8 @@ function SmtpSettingsPage() {
|
||||
subject: "SMTP test from your firm CRM",
|
||||
html: `<p>This is a test email sent from <strong>${form.from_email}</strong> via <code>${form.host}:${form.port}</code>.</p><p>If you received this, your SMTP settings are working.</p>`,
|
||||
text: `Test email from ${form.from_email} via ${form.host}:${form.port}.`,
|
||||
test: true,
|
||||
context: "smtp_test",
|
||||
},
|
||||
});
|
||||
setTesting(false);
|
||||
@@ -118,9 +145,11 @@ function SmtpSettingsPage() {
|
||||
toast.error("Send failed", {
|
||||
description: (error as any)?.message || (data as any)?.error,
|
||||
});
|
||||
load();
|
||||
return;
|
||||
}
|
||||
toast.success(`Test email sent to ${testTo}`);
|
||||
load();
|
||||
};
|
||||
|
||||
if (!isAdmin) {
|
||||
@@ -218,6 +247,16 @@ function SmtpSettingsPage() {
|
||||
onChange={(e) => update("reply_to", e.target.value)}
|
||||
/>
|
||||
</Field>
|
||||
<Field label="Default BCC (optional)" className="sm:col-span-2">
|
||||
<Input
|
||||
value={form.default_bcc}
|
||||
onChange={(e) => update("default_bcc", e.target.value)}
|
||||
placeholder="archive@yourfirm.com, partner@yourfirm.com"
|
||||
/>
|
||||
<p className="text-xs text-muted-foreground mt-1">
|
||||
Every outbound email will be silently BCC'd to these addresses (comma-separated).
|
||||
</p>
|
||||
</Field>
|
||||
<Field label="Notes" className="sm:col-span-2">
|
||||
<Textarea
|
||||
rows={2}
|
||||
@@ -271,6 +310,59 @@ function SmtpSettingsPage() {
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="border-border/60">
|
||||
<CardHeader>
|
||||
<CardTitle className="font-serif text-base flex items-center gap-2">
|
||||
<History className="h-4 w-4 text-muted-foreground" /> Recent email log
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
{logs.length === 0 ? (
|
||||
<p className="text-sm text-muted-foreground">No emails sent yet.</p>
|
||||
) : (
|
||||
<div className="space-y-2">
|
||||
{logs.map((log) => (
|
||||
<div
|
||||
key={log.id}
|
||||
className="flex items-start justify-between gap-3 p-2 rounded-md border text-sm"
|
||||
>
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="flex items-center gap-2 flex-wrap">
|
||||
<span className="font-medium truncate">{log.subject}</span>
|
||||
<Badge
|
||||
variant={log.status === "sent" ? "secondary" : "destructive"}
|
||||
className="text-[10px] uppercase"
|
||||
>
|
||||
{log.status}
|
||||
</Badge>
|
||||
{log.context && (
|
||||
<span className="text-[10px] text-muted-foreground">
|
||||
{log.context}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="text-xs text-muted-foreground mt-0.5 truncate">
|
||||
To: {log.to_addresses.join(", ") || "—"}
|
||||
{log.bcc_addresses.length > 0 && (
|
||||
<> · BCC: {log.bcc_addresses.join(", ")}</>
|
||||
)}
|
||||
</div>
|
||||
{log.error_message && (
|
||||
<div className="text-xs text-destructive mt-0.5 truncate">
|
||||
{log.error_message}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="text-xs text-muted-foreground whitespace-nowrap">
|
||||
{new Date(log.sent_at).toLocaleString()}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user