Skip to content

Commit 38cda43

Browse files
committed
Refactor DBL Upload email to do its own data & config loading
1 parent bc3d36d commit 38cda43

File tree

2 files changed

+41
-74
lines changed

2 files changed

+41
-74
lines changed

src/components/dbl-upload-notification/emails/dbl-upload.email.tsx

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,38 @@
11
import { type NonEmptyArray } from '@seedcompany/common';
22
import type { Verse } from '@seedcompany/scripture';
33
import type { Range } from '~/common';
4-
import { EmailTemplate, LanguageRef, Mjml, useFrontendUrl } from '~/core/email';
5-
import { type Engagement } from '../../../components/engagement/dto';
6-
import { type Language } from '../../../components/language/dto';
7-
import { type Project } from '../../../components/project/dto';
8-
import { type User } from '../../../components/user/dto';
4+
import { ConfigService } from '~/core/config/config.service';
5+
import {
6+
EmailTemplate,
7+
Headers,
8+
LanguageRef,
9+
Mjml,
10+
useFrontendUrl,
11+
useModuleRef,
12+
useResources,
13+
} from '~/core/email';
14+
import { type LanguageEngagement } from '../../engagement/dto';
915

1016
interface Props {
11-
recipient: User;
12-
project: Pick<Project, 'id' | 'name'>;
13-
engagement: Pick<Engagement, 'id'>;
14-
language: Pick<Language, 'id' | 'name' | 'ethnologue'>;
17+
engagement: LanguageEngagement;
1518
completedBooks: NonEmptyArray<Range<Verse>>;
16-
dblFormUrl: string;
1719
}
1820

19-
export function DBLUpload(props: Props) {
20-
const { language, project, completedBooks, engagement, dblFormUrl } = props;
21+
export async function DBLUpload(props: Props) {
22+
const { engagement, completedBooks } = props;
23+
24+
const resources = useResources();
25+
const [language, project] = await Promise.all([
26+
resources.load('Language', props.engagement.language.value!.id),
27+
resources.load('Project', props.engagement.project.id),
28+
]);
29+
30+
const config = useModuleRef().get(ConfigService).email.notifyDblUpload!;
31+
2132
const languageName = language.name.value;
2233
return (
2334
<EmailTemplate title={`${languageName || 'Language'} needs a DBL upload`}>
35+
{config.replyTo && <Headers replyTo={config.replyTo} />}
2436
<Mjml.Section>
2537
<Mjml.Column>
2638
<Mjml.Text>
@@ -136,7 +148,9 @@ export function DBLUpload(props: Props) {
136148
<Mjml.Column>
137149
<Mjml.Text>
138150
🔗{' '}
139-
<a href={dblFormUrl}>Seed Company DBL Publication Request Form</a>
151+
<a href={config.formUrl}>
152+
Seed Company DBL Publication Request Form
153+
</a>
140154
</Mjml.Text>
141155
</Mjml.Column>
142156
</Mjml.Section>

src/components/dbl-upload-notification/handlers/dbl-upload-notification.handler.tsx

Lines changed: 14 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { ModuleRef } from '@nestjs/core';
22
import {
33
asNonEmptyArray,
4+
asyncPool,
45
groupBy,
56
type NonEmptyArray,
67
setOf,
@@ -11,7 +12,6 @@ import {
1112
splitRangeByBook,
1213
type Verse,
1314
} from '@seedcompany/scripture';
14-
import { type ComponentProps as PropsOf } from 'react';
1515
import { type ID, type Range } from '~/common';
1616
import {
1717
ConfigService,
@@ -96,44 +96,23 @@ export class DBLUploadNotificationHandler
9696
.get(ProjectMemberRepository, { strict: false })
9797
.listAsNotifiers(engagement.project.id, ['ProjectManager']);
9898

99-
const notifyeesProps = await Promise.all(
100-
notifyees
101-
.filter((n) => n.email)
102-
.map(({ id: userId }) =>
103-
this.gatherTemplateProps(
104-
userId,
105-
engagement.id,
106-
engagement.language.value!.id,
107-
engagement.project.id,
108-
completedBooks,
109-
),
110-
),
111-
);
112-
11399
this.logger.info('Notifying', {
114-
engagement: notifyeesProps[0]?.engagement.id ?? undefined,
115-
reportId: report.id,
116-
reportDate: report.start,
100+
language: engagement.language.value!.id,
117101
books: completedBooks.map((r) => r.start.book.name),
118-
emails: notifyeesProps.map((r) => r.recipient.email.value),
102+
emails: notifyees.flatMap((r) => r.email ?? []),
119103
});
120104

121-
for (const props of notifyeesProps) {
122-
// members without an email address are already omitted
123-
const to = props.recipient.email.value!;
124-
await this.mailer
125-
.withOptions({ send: !!this.config.email.notifyDblUpload })
126-
.compose(
127-
{
128-
to,
129-
...(this.config.email.notifyDblUpload && {
130-
'reply-to': this.config.email.notifyDblUpload.replyTo,
131-
}),
132-
},
133-
<DBLUpload {...props} />,
134-
)
135-
.send();
136-
}
105+
await asyncPool(Infinity, notifyees, async ({ id: user, email }) => {
106+
if (!email) {
107+
return;
108+
}
109+
const msg = await this.identity.asUser(user, async () =>
110+
this.mailer
111+
.withOptions({ send: !!this.config.email.notifyDblUpload })
112+
.compose(email, [DBLUpload, { engagement, completedBooks }]),
113+
);
114+
await msg.send();
115+
});
137116
}
138117

139118
private async determineCompletedProducts(report: ProgressReport) {
@@ -215,30 +194,4 @@ export class DBLUploadNotificationHandler
215194
});
216195
return asNonEmptyArray(completedBooks);
217196
}
218-
219-
private async gatherTemplateProps(
220-
recipientId: ID<'User'>,
221-
engagementId: ID,
222-
languageId: ID,
223-
projectId: ID,
224-
completedBooks: NonEmptyArray<Range<Verse>>,
225-
) {
226-
return await this.identity.asUser(recipientId, async () => {
227-
const [recipient, language, engagement, project] = await Promise.all([
228-
this.resources.load('User', recipientId),
229-
this.resources.load('Language', languageId),
230-
this.resources.load('Engagement', engagementId),
231-
this.resources.load('Project', projectId),
232-
]);
233-
234-
return {
235-
recipient,
236-
language,
237-
project,
238-
engagement,
239-
completedBooks,
240-
dblFormUrl: this.config.email.notifyDblUpload?.formUrl ?? '',
241-
} satisfies PropsOf<typeof DBLUpload>;
242-
});
243-
}
244197
}

0 commit comments

Comments
 (0)