feat: Add type to campaign

This commit is contained in:
Dries Augustyns
2026-04-01 18:49:51 +02:00
parent 3343e891bd
commit d24259e8d2
9 changed files with 139 additions and 20 deletions
+10 -2
View File
@@ -1,5 +1,5 @@
import type {Campaign, Contact, Prisma} from '@plunk/db';
import {CampaignAudienceType, CampaignStatus, EmailSourceType} from '@plunk/db';
import {CampaignAudienceType, CampaignStatus, EmailSourceType, TemplateType} from '@plunk/db';
import type {CreateCampaignData, FilterCondition, PaginatedResponse, UpdateCampaignData} from '@plunk/types';
import {fromPrismaJson, toPrismaJson} from '@plunk/types';
import signale from 'signale';
@@ -59,6 +59,7 @@ export class CampaignService {
from: data.from,
fromName: data.fromName,
replyTo: data.replyTo,
type: data.type ?? TemplateType.MARKETING,
audienceType: data.audienceType,
audienceCondition: toPrismaJson(data.audienceCondition || null),
segmentId: data.segmentId,
@@ -100,6 +101,10 @@ export class CampaignService {
const updateData: Prisma.CampaignUpdateInput = buildEmailFieldsUpdate(data) as Prisma.CampaignUpdateInput;
// Handle campaign-specific fields
if (data.type !== undefined) {
updateData.type = data.type;
}
if (data.audienceType !== undefined) {
updateData.audienceType = data.audienceType;
}
@@ -262,6 +267,7 @@ export class CampaignService {
from: campaign.from,
fromName: campaign.fromName,
replyTo: campaign.replyTo,
type: campaign.type,
audienceType: campaign.audienceType,
audienceCondition: campaign.audienceCondition as Prisma.InputJsonValue,
segmentId: campaign.segmentId,
@@ -482,6 +488,7 @@ export class CampaignService {
from: campaign.from,
fromName: campaign.fromName || undefined,
replyTo: campaign.replyTo || undefined,
isTransactional: campaign.type === TemplateType.TRANSACTIONAL,
});
} catch (error) {
signale.error(`[CAMPAIGN] Failed to queue email for contact ${contact.id}:`, error);
@@ -708,7 +715,8 @@ export class CampaignService {
): Promise<Prisma.ContactWhereInput> {
const baseWhere: Prisma.ContactWhereInput = {
projectId,
subscribed: true, // Only send to subscribed contacts
// Transactional campaigns send to all contacts regardless of subscription status
...(campaign.type !== TemplateType.TRANSACTIONAL && {subscribed: true}),
};
switch (campaign.audienceType) {
+5 -2
View File
@@ -38,6 +38,7 @@ interface SendEmailParams {
workflowExecutionId?: string;
workflowStepExecutionId?: string;
recipientEmail?: string; // Optional custom recipient email (overrides contact.email)
isTransactional?: boolean; // Override source type to TRANSACTIONAL (e.g. for transactional campaigns)
}
/**
@@ -116,10 +117,12 @@ export class EmailService {
* Send a campaign email
*/
public static async sendCampaignEmail(params: SendEmailParams): Promise<Email> {
// Check if template is transactional to determine source type
// Check if campaign or template is transactional to determine source type
let sourceType: EmailSourceType = EmailSourceType.CAMPAIGN;
if (params.templateId) {
if (params.isTransactional) {
sourceType = EmailSourceType.TRANSACTIONAL;
} else if (params.templateId) {
const template = await prisma.template.findUnique({
where: {id: params.templateId},
select: {type: true},