fix: Update sentCount on campaign sent for correct overview stats

This commit is contained in:
Dries Augustyns
2026-01-03 11:18:44 +01:00
parent 5d44b1606d
commit ee00eb3481
4 changed files with 67 additions and 2 deletions
+1
View File
@@ -204,6 +204,7 @@ export async function createEmailWorker() {
where: {id: email.campaignId},
data: {
status: CampaignStatus.SENT,
sentCount,
},
});
+1
View File
@@ -564,6 +564,7 @@ export class CampaignService {
await prisma.campaign.update({
where: {id: campaignId},
data: {
sentCount: sentEmails,
deliveredCount: deliveredEmails,
openedCount: openedEmails,
clickedCount: clickedEmails,
+36
View File
@@ -503,6 +503,42 @@ export class EmailService {
data: updateData,
});
// Update campaign stats if applicable
if (email.campaignId) {
const campaignUpdate: Prisma.CampaignUpdateInput = {};
switch (eventType) {
case 'delivered':
campaignUpdate.deliveredCount = {increment: 1};
break;
case 'opened':
// Only increment unique opens to match getStats logic
if (!email.openedAt) {
campaignUpdate.openedCount = {increment: 1};
}
break;
case 'clicked':
// Only increment unique clicks to match getStats logic
if (!email.clickedAt) {
campaignUpdate.clickedCount = {increment: 1};
}
break;
case 'bounced':
campaignUpdate.bouncedCount = {increment: 1};
break;
}
if (Object.keys(campaignUpdate).length > 0) {
await prisma.campaign.update({
where: {id: email.campaignId},
data: campaignUpdate,
});
}
}
// Track event
await prisma.event.create({
data: {
+29 -2
View File
@@ -25,7 +25,20 @@ import {TemplateSelectionDialog} from '../../components/TemplateSelectionDialog'
import {CampaignSelectionDialog} from '../../components/CampaignSelectionDialog';
import {network} from '../../lib/network';
import {formatRelativeTime} from '../../lib/dateUtils';
import {Calendar, ChevronDown, Copy, FileText, Info, Mail, Plus, RefreshCw, Trash2, Users} from 'lucide-react';
import {
AlertCircle,
Calendar,
ChevronDown,
Copy,
FileText,
Info,
Mail,
MousePointerClick,
Plus,
RefreshCw,
Trash2,
Users,
} from 'lucide-react';
import {NextSeo} from 'next-seo';
import Link from 'next/link';
import {useRouter} from 'next/router';
@@ -426,7 +439,7 @@ export default function CampaignsPage() {
{campaign.clickedCount > 0 && (
<div className="bg-orange-50 border border-orange-100 rounded-lg p-3">
<div className="flex items-center gap-2 mb-1">
<Mail className="h-3.5 w-3.5 text-orange-600" />
<MousePointerClick className="h-3.5 w-3.5 text-orange-600" />
<span className="text-xs font-medium text-orange-900">Clicks</span>
</div>
<p className="text-lg font-bold text-orange-900">{clickRate.toFixed(1)}%</p>
@@ -436,6 +449,20 @@ export default function CampaignsPage() {
</div>
)}
{/* Bounced Rate */}
{campaign.bouncedCount > 0 && campaign.sentCount > 0 && (
<div className="bg-red-50 border border-red-100 rounded-lg p-3">
<div className="flex items-center gap-2 mb-1">
<AlertCircle className="h-3.5 w-3.5 text-red-600" />
<span className="text-xs font-medium text-red-900">Bounced</span>
</div>
<p className="text-lg font-bold text-red-900">
{((campaign.bouncedCount / campaign.sentCount) * 100).toFixed(1)}%
</p>
<p className="text-xs text-red-700 mt-1">{campaign.bouncedCount.toLocaleString()} bounced</p>
</div>
)}
{/* Scheduled For */}
{campaign.scheduledFor && (
<div className="bg-green-50 border border-green-100 rounded-lg p-3 md:col-span-2">