feat: Add dedicated received type
This commit is contained in:
@@ -154,7 +154,7 @@ export class Webhooks {
|
|||||||
body: '', // Inbound emails don't have body content in our system
|
body: '', // Inbound emails don't have body content in our system
|
||||||
from: recipientEmail, // The recipient address that received the email
|
from: recipientEmail, // The recipient address that received the email
|
||||||
sourceType: EmailSourceType.INBOUND,
|
sourceType: EmailSourceType.INBOUND,
|
||||||
status: EmailStatus.DELIVERED, // Inbound emails are already delivered
|
status: EmailStatus.RECEIVED, // Inbound emails use RECEIVED status
|
||||||
deliveredAt: new Date(body.mail?.timestamp || new Date()),
|
deliveredAt: new Date(body.mail?.timestamp || new Date()),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -376,6 +376,9 @@ export class ActivityService {
|
|||||||
if (!types || types.includes(ActivityType.EMAIL_DELIVERED)) {
|
if (!types || types.includes(ActivityType.EMAIL_DELIVERED)) {
|
||||||
orConditions.push({deliveredAt: {not: null, ...dateFilter}});
|
orConditions.push({deliveredAt: {not: null, ...dateFilter}});
|
||||||
}
|
}
|
||||||
|
if (!types || types.includes(ActivityType.EMAIL_RECEIVED)) {
|
||||||
|
orConditions.push({deliveredAt: {not: null, ...dateFilter}, sourceType: 'INBOUND'});
|
||||||
|
}
|
||||||
if (!types || types.includes(ActivityType.EMAIL_OPENED)) {
|
if (!types || types.includes(ActivityType.EMAIL_OPENED)) {
|
||||||
orConditions.push({openedAt: {not: null, ...dateFilter}});
|
orConditions.push({openedAt: {not: null, ...dateFilter}});
|
||||||
}
|
}
|
||||||
@@ -485,6 +488,22 @@ export class ActivityService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
email.deliveredAt &&
|
||||||
|
email.sourceType === 'INBOUND' &&
|
||||||
|
(!types || types.includes(ActivityType.EMAIL_RECEIVED)) &&
|
||||||
|
isInDateRange(email.deliveredAt)
|
||||||
|
) {
|
||||||
|
activities.push({
|
||||||
|
id: `${email.id}_received`,
|
||||||
|
type: ActivityType.EMAIL_RECEIVED,
|
||||||
|
timestamp: email.deliveredAt,
|
||||||
|
contactEmail: email.contact.email,
|
||||||
|
contactId: email.contactId,
|
||||||
|
metadata: baseMetadata,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (email.openedAt && (!types || types.includes(ActivityType.EMAIL_OPENED)) && isInDateRange(email.openedAt)) {
|
if (email.openedAt && (!types || types.includes(ActivityType.EMAIL_OPENED)) && isInDateRange(email.openedAt)) {
|
||||||
activities.push({
|
activities.push({
|
||||||
id: `${email.id}_opened`,
|
id: `${email.id}_opened`,
|
||||||
|
|||||||
@@ -585,10 +585,11 @@ export class EmailService {
|
|||||||
: {}),
|
: {}),
|
||||||
};
|
};
|
||||||
|
|
||||||
const [total, sent, delivered, opened, clicked, bounced, failed] = await Promise.all([
|
const [total, sent, delivered, received, opened, clicked, bounced, failed] = await Promise.all([
|
||||||
prisma.email.count({where}),
|
prisma.email.count({where}),
|
||||||
prisma.email.count({where: {...where, status: EmailStatus.SENT}}),
|
prisma.email.count({where: {...where, status: EmailStatus.SENT}}),
|
||||||
prisma.email.count({where: {...where, status: EmailStatus.DELIVERED}}),
|
prisma.email.count({where: {...where, status: EmailStatus.DELIVERED}}),
|
||||||
|
prisma.email.count({where: {...where, status: EmailStatus.RECEIVED}}),
|
||||||
prisma.email.count({where: {...where, status: EmailStatus.OPENED}}),
|
prisma.email.count({where: {...where, status: EmailStatus.OPENED}}),
|
||||||
prisma.email.count({where: {...where, status: EmailStatus.CLICKED}}),
|
prisma.email.count({where: {...where, status: EmailStatus.CLICKED}}),
|
||||||
prisma.email.count({where: {...where, status: EmailStatus.BOUNCED}}),
|
prisma.email.count({where: {...where, status: EmailStatus.BOUNCED}}),
|
||||||
@@ -599,6 +600,7 @@ export class EmailService {
|
|||||||
total,
|
total,
|
||||||
sent,
|
sent,
|
||||||
delivered,
|
delivered,
|
||||||
|
received,
|
||||||
opened,
|
opened,
|
||||||
clicked,
|
clicked,
|
||||||
bounced,
|
bounced,
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
CheckCircle,
|
CheckCircle,
|
||||||
ChevronRight,
|
ChevronRight,
|
||||||
Eye,
|
Eye,
|
||||||
|
Inbox,
|
||||||
MousePointerClick,
|
MousePointerClick,
|
||||||
Send,
|
Send,
|
||||||
ShieldAlert,
|
ShieldAlert,
|
||||||
@@ -99,6 +100,7 @@ function isEmailActivity(type: string): boolean {
|
|||||||
return [
|
return [
|
||||||
'email.sent',
|
'email.sent',
|
||||||
'email.delivered',
|
'email.delivered',
|
||||||
|
'email.received',
|
||||||
'email.opened',
|
'email.opened',
|
||||||
'email.clicked',
|
'email.clicked',
|
||||||
'email.bounced',
|
'email.bounced',
|
||||||
@@ -181,6 +183,19 @@ function getActivityConfig(activity: Activity): ActivityConfig {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
case 'email.received':
|
||||||
|
return {
|
||||||
|
icon: Inbox,
|
||||||
|
color: 'text-blue-600',
|
||||||
|
bgColor: 'bg-blue-100',
|
||||||
|
title: (typeof metadata.subject === 'string' ? metadata.subject : undefined) || 'Email received',
|
||||||
|
description: typeof metadata.from === 'string' ? `From: ${metadata.from}` : 'Inbound email',
|
||||||
|
badge: {
|
||||||
|
label: 'Received',
|
||||||
|
variant: 'default',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
case 'email.opened':
|
case 'email.opened':
|
||||||
return {
|
return {
|
||||||
icon: Eye,
|
icon: Eye,
|
||||||
|
|||||||
@@ -119,10 +119,12 @@ export default function ActivityPage() {
|
|||||||
<SelectContent>
|
<SelectContent>
|
||||||
<SelectItem value="ALL">All Activity Types</SelectItem>
|
<SelectItem value="ALL">All Activity Types</SelectItem>
|
||||||
<SelectItem value="event.triggered">Events</SelectItem>
|
<SelectItem value="event.triggered">Events</SelectItem>
|
||||||
<SelectItem value="email.sent,email.delivered,email.opened,email.clicked,email.bounced,email.complaint">
|
<SelectItem value="email.sent,email.delivered,email.received,email.opened,email.clicked,email.bounced,email.complaint">
|
||||||
Emails
|
Emails
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
<SelectItem value="email.sent">Emails Sent</SelectItem>
|
<SelectItem value="email.sent">Emails Sent</SelectItem>
|
||||||
|
<SelectItem value="email.delivered">Emails Delivered</SelectItem>
|
||||||
|
<SelectItem value="email.received">Emails Received</SelectItem>
|
||||||
<SelectItem value="email.opened">Emails Opened</SelectItem>
|
<SelectItem value="email.opened">Emails Opened</SelectItem>
|
||||||
<SelectItem value="email.clicked">Emails Clicked</SelectItem>
|
<SelectItem value="email.clicked">Emails Clicked</SelectItem>
|
||||||
<SelectItem value="email.bounced">Emails Bounced</SelectItem>
|
<SelectItem value="email.bounced">Emails Bounced</SelectItem>
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
-- AlterEnum
|
||||||
|
ALTER TYPE "EmailStatus" ADD VALUE 'RECEIVED';
|
||||||
@@ -759,6 +759,7 @@ enum EmailStatus {
|
|||||||
SENDING // Currently being sent
|
SENDING // Currently being sent
|
||||||
SENT // Successfully sent to provider
|
SENT // Successfully sent to provider
|
||||||
DELIVERED // Confirmed delivered
|
DELIVERED // Confirmed delivered
|
||||||
|
RECEIVED // Received by platform (inbound)
|
||||||
OPENED // Recipient opened email
|
OPENED // Recipient opened email
|
||||||
CLICKED // Recipient clicked link
|
CLICKED // Recipient clicked link
|
||||||
BOUNCED // Bounced (hard or soft)
|
BOUNCED // Bounced (hard or soft)
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ export enum ActivityType {
|
|||||||
EVENT_TRIGGERED = 'event.triggered',
|
EVENT_TRIGGERED = 'event.triggered',
|
||||||
EMAIL_SENT = 'email.sent',
|
EMAIL_SENT = 'email.sent',
|
||||||
EMAIL_DELIVERED = 'email.delivered',
|
EMAIL_DELIVERED = 'email.delivered',
|
||||||
|
EMAIL_RECEIVED = 'email.received',
|
||||||
EMAIL_OPENED = 'email.opened',
|
EMAIL_OPENED = 'email.opened',
|
||||||
EMAIL_CLICKED = 'email.clicked',
|
EMAIL_CLICKED = 'email.clicked',
|
||||||
EMAIL_BOUNCED = 'email.bounced',
|
EMAIL_BOUNCED = 'email.bounced',
|
||||||
|
|||||||
Reference in New Issue
Block a user