Skip to content

Commit 9f1a0c6

Browse files
authored
Fix send intro recruiter (#3268)
1 parent 6092f00 commit 9f1a0c6

2 files changed

Lines changed: 91 additions & 1 deletion

File tree

__tests__/workers/newNotificationV2Mail.ts

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ import {
6767
Reference,
6868
type NotificationAwardContext,
6969
type NotificationOpportunityMatchContext,
70+
type NotificationWarmIntroContext,
7071
} from '../../src/notifications';
7172
import { postsFixture } from '../fixture/post';
7273
import { sourcesFixture } from '../fixture/source';
@@ -96,6 +97,8 @@ import { BriefPost } from '../../src/entity/posts/BriefPost';
9697
import { CampaignUpdateEvent } from '../../src/common/campaign/common';
9798
import { Opportunity } from '../../src/entity/opportunities/Opportunity';
9899
import { OpportunityMatch } from '../../src/entity/OpportunityMatch';
100+
import { OpportunityUserRecruiter } from '../../src/entity/opportunities/user';
101+
import { OpportunityUserType } from '../../src/entity/opportunities/types';
99102
import {
100103
opportunitiesFixture,
101104
opportunityMatchesFixture,
@@ -2749,3 +2752,74 @@ describe('poll result notifications', () => {
27492752
expect(args.transactional_message_id).toEqual('84');
27502753
});
27512754
});
2755+
2756+
describe('warm_intro notification', () => {
2757+
it('should send email to both candidate and recruiter', async () => {
2758+
await saveFixtures(con, Organization, organizationsFixture);
2759+
await saveFixtures(con, Opportunity, opportunitiesFixture);
2760+
await saveFixtures(con, OpportunityMatch, opportunityMatchesFixture);
2761+
2762+
// Create a recruiter user
2763+
const recruiter = await con.getRepository(User).save({
2764+
id: 'recruiter123',
2765+
name: 'John Recruiter',
2766+
email: 'recruiter@test.com',
2767+
username: 'recruiter',
2768+
});
2769+
2770+
// Link recruiter to opportunity
2771+
await con.getRepository(OpportunityUserRecruiter).save({
2772+
opportunityId: opportunitiesFixture[0].id,
2773+
userId: recruiter.id,
2774+
type: OpportunityUserType.Recruiter,
2775+
});
2776+
2777+
// Update opportunity match with warmIntro
2778+
await con.getRepository(OpportunityMatch).update(
2779+
{
2780+
opportunityId: opportunitiesFixture[0].id,
2781+
userId: '1',
2782+
},
2783+
{
2784+
applicationRank: {
2785+
warmIntro: '<p>Great match based on your experience!</p>',
2786+
},
2787+
},
2788+
);
2789+
2790+
const ctx: NotificationWarmIntroContext = {
2791+
userIds: ['1'],
2792+
opportunityId: opportunitiesFixture[0].id,
2793+
description: 'Great match based on your experience!',
2794+
recruiter,
2795+
organization: organizationsFixture[0],
2796+
};
2797+
2798+
const notificationId = await saveNotificationV2Fixture(
2799+
con,
2800+
NotificationType.WarmIntro,
2801+
ctx,
2802+
);
2803+
2804+
await expectSuccessfulBackground(worker, {
2805+
notification: {
2806+
id: notificationId,
2807+
userId: '1',
2808+
},
2809+
});
2810+
2811+
expect(sendEmail).toHaveBeenCalledTimes(1);
2812+
const args = jest.mocked(sendEmail).mock
2813+
.calls[0][0] as SendEmailRequestWithTemplate;
2814+
2815+
expect(args.message_data).toEqual({
2816+
title: `It's a match!`,
2817+
copy: '<p>Great match based on your experience!</p>',
2818+
cc: 'recruiter@test.com',
2819+
});
2820+
2821+
// Verify both emails are in the 'to' field
2822+
expect(args.to).toEqual('ido@daily.dev,recruiter@test.com');
2823+
expect(args.transactional_message_id).toEqual('85');
2824+
});
2825+
});

src/workers/newNotificationV2Mail.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ import { generateCampaignPostEmail } from '../common/campaign/post';
6464
import { generateCampaignSquadEmail } from '../common/campaign/source';
6565
import { PollPost } from '../entity/posts/PollPost';
6666
import { OpportunityMatch } from '../entity/OpportunityMatch';
67+
import { OpportunityUserRecruiter } from '../entity/opportunities/user';
6768

6869
interface Data {
6970
notification: ChangeObject<NotificationV2>;
@@ -1132,9 +1133,17 @@ const notificationToTemplateData: Record<NotificationType, TemplateDataFunc> = {
11321133
return null;
11331134
}
11341135

1136+
const recruiterUser = await con
1137+
.getRepository(OpportunityUserRecruiter)
1138+
.findOneBy({
1139+
opportunityId: notif.referenceId,
1140+
});
1141+
const recruiter = await recruiterUser?.user;
1142+
11351143
return {
11361144
title: `It's a match!`,
11371145
copy: warmIntro,
1146+
cc: recruiter?.email,
11381147
};
11391148
},
11401149
};
@@ -1206,7 +1215,14 @@ const worker: Worker = {
12061215
identifiers: {
12071216
id: user.id,
12081217
},
1209-
to: user.email,
1218+
to: [
1219+
user.email,
1220+
!isNullOrUndefined(templateData?.cc)
1221+
? templateData.cc
1222+
: undefined,
1223+
]
1224+
.filter(Boolean)
1225+
.join(','),
12101226
send_at:
12111227
!isNullOrUndefined(templateData.sendAtMs) &&
12121228
templateData.sendAtMs > Date.now()

0 commit comments

Comments
 (0)