From ff5c79cfcf0ac6b351af20345ec639110f206f4b Mon Sep 17 00:00:00 2001 From: Dries Augustyns Date: Tue, 9 Dec 2025 10:27:56 +0100 Subject: [PATCH] fix: Update recipient count on create/update of campaign --- apps/api/src/services/CampaignService.ts | 40 +++++++++++++++++++++--- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/apps/api/src/services/CampaignService.ts b/apps/api/src/services/CampaignService.ts index 3a1bcca..0f46daa 100644 --- a/apps/api/src/services/CampaignService.ts +++ b/apps/api/src/services/CampaignService.ts @@ -71,7 +71,7 @@ export class CampaignService { SegmentService.validateCondition(data.audienceCondition); } - // Create campaign + // Create campaign with initial recipient count of 0 const campaign = await prisma.campaign.create({ data: { projectId, @@ -86,6 +86,7 @@ export class CampaignService { audienceCondition: (data.audienceCondition || null) as unknown as Prisma.InputJsonValue, segmentId: data.segmentId, status: CampaignStatus.DRAFT, + totalRecipients: 0, // Will be updated below }, include: { project: { @@ -94,10 +95,17 @@ export class CampaignService { }, }); + // Calculate and update recipient count for the draft + const recipientCount = await this.getRecipientCount(projectId, campaign); + const updatedCampaign = await prisma.campaign.update({ + where: {id: campaign.id}, + data: {totalRecipients: recipientCount}, + }); + // Send notification about campaign creation await NtfyService.notifyCampaignCreated(campaign.name, campaign.project.name, projectId); - return campaign; + return updatedCampaign; } /** @@ -147,10 +155,25 @@ export class CampaignService { delete (updateData as Record).segmentId; } - return prisma.campaign.update({ + // Update the campaign first + const updatedCampaign = await prisma.campaign.update({ where: {id: campaignId}, data: updateData, }); + + // If audience-related fields changed and campaign is still a draft, recalculate totalRecipients + const audienceChanged = + data.audienceType !== undefined || data.segmentId !== undefined || data.audienceCondition !== undefined; + + if (audienceChanged && updatedCampaign.status === CampaignStatus.DRAFT) { + const recipientCount = await this.getRecipientCount(projectId, updatedCampaign); + return prisma.campaign.update({ + where: {id: campaignId}, + data: {totalRecipients: recipientCount}, + }); + } + + return updatedCampaign; } /** @@ -252,7 +275,7 @@ export class CampaignService { const campaign = await this.get(projectId, campaignId); // Create a new campaign with the same data but reset status and stats - return prisma.campaign.create({ + const duplicatedCampaign = await prisma.campaign.create({ data: { projectId, name: `${campaign.name} (Copy)`, @@ -266,7 +289,7 @@ export class CampaignService { audienceCondition: campaign.audienceCondition as Prisma.InputJsonValue, segmentId: campaign.segmentId, status: CampaignStatus.DRAFT, - totalRecipients: 0, + totalRecipients: 0, // Will be updated below sentCount: 0, deliveredCount: 0, openedCount: 0, @@ -274,6 +297,13 @@ export class CampaignService { bouncedCount: 0, }, }); + + // Calculate and update recipient count + const recipientCount = await this.getRecipientCount(projectId, duplicatedCampaign); + return prisma.campaign.update({ + where: {id: duplicatedCampaign.id}, + data: {totalRecipients: recipientCount}, + }); } /**