Skip to content

Commit

Permalink
COM-343: Add additional functionality to email campaign admin (send n…
Browse files Browse the repository at this point in the history
…ow & test emails) (#33)

* add test email section to email campaign edit

* add send now button to email campaign form

---------

Co-authored-by: Denise Buder <[email protected]>
  • Loading branch information
RainbowBunchie and RainbowBunchie authored Feb 5, 2024
1 parent 7784108 commit ebcc444
Show file tree
Hide file tree
Showing 8 changed files with 238 additions and 8 deletions.
9 changes: 8 additions & 1 deletion packages/admin/src/emailCampaigns/form/EmailCampaignForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ import {
GQLUpdateEmailCampaignMutationVariables,
} from "./EmailCampaignForm.gql.generated";
import { SendManagerFields } from "./SendManagerFields";
import { TestEmailCampaignForm } from "./TestEmailCampaignForm";

interface FormProps {
id?: string;
Expand Down Expand Up @@ -287,7 +288,13 @@ export function EmailCampaignForm({ id, EmailCampaignContentBlock, scope, previe
scheduledAt: state.scheduledAt,
}}
>
<SendManagerFields scope={scope} disableScheduling={isScheduleDateDisabled} />
<SendManagerFields
scope={scope}
disableScheduling={isScheduleDateDisabled}
isSendable={!hasChanges && state.targetGroup != undefined}
id={id}
/>
<TestEmailCampaignForm id={id} isSendable={!hasChanges && state.targetGroup != undefined} />
</BlocksFinalForm>
),
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { CancelButton, SaveButton } from "@comet/admin";
import { Dialog, DialogActions, DialogContent, DialogTitle } from "@mui/material";
import React from "react";
import { FormattedMessage } from "react-intl";

interface SendEmailCampaignNowDialogProps {
dialogOpen: boolean;
handleNoClick: () => void;
handleYesClick: () => void;
}

const SendEmailCampaignNowDialog = ({ dialogOpen, handleNoClick, handleYesClick }: SendEmailCampaignNowDialogProps) => {
return (
<Dialog open={dialogOpen} onClose={handleNoClick}>
<DialogTitle>
<FormattedMessage id="cometBrevoModule.emailCampaigns.sendNow.dialog.title" defaultMessage="Send email campaign now?" />
</DialogTitle>
<DialogContent>
<FormattedMessage
id="cometBrevoModule.emailCampaigns.sendNow.dialog.contentText"
defaultMessage="Are you sure you want to send the email campaign now?"
/>
</DialogContent>
<DialogActions>
<CancelButton onClick={handleNoClick} />
<SaveButton onClick={handleYesClick}>
<FormattedMessage id="cometBrevoModule.emailCampaigns.sendNow.dialog.sendText" defaultMessage="Send now" />
</SaveButton>
</DialogActions>
</Dialog>
);
};

export { SendEmailCampaignNowDialog };
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,9 @@ export const targetGroupsSelectQuery = gql`
}
}
`;

export const sendEmailCampaignNowMutation = gql`
mutation SendEmailCampaignNow($id: ID!) {
sendEmailCampaignNow(id: $id)
}
`;
58 changes: 53 additions & 5 deletions packages/admin/src/emailCampaigns/form/SendManagerFields.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,27 @@
import { useQuery } from "@apollo/client";
import { Field, FinalFormSelect } from "@comet/admin";
import { useMutation, useQuery } from "@apollo/client";
import { Field, FinalFormSelect, SaveButton } from "@comet/admin";
import { FinalFormDateTimePicker } from "@comet/admin-date-time";
import { Newsletter } from "@comet/admin-icons";
import { AdminComponentPaper, AdminComponentSectionGroup } from "@comet/blocks-admin";
import { ContentScopeInterface } from "@comet/cms-admin";
import { Card, MenuItem } from "@mui/material";
import * as React from "react";
import { FormattedMessage } from "react-intl";

import { targetGroupsSelectQuery } from "./SendManagerFields.gql";
import { GQLTargetGroupsSelectQuery, GQLTargetGroupsSelectQueryVariables } from "./SendManagerFields.gql.generated";
import { SendEmailCampaignNowDialog } from "./SendEmailCampaignNowDialog";
import { sendEmailCampaignNowMutation, targetGroupsSelectQuery } from "./SendManagerFields.gql";
import {
GQLSendEmailCampaignNowMutation,
GQLSendEmailCampaignNowMutationVariables,
GQLTargetGroupsSelectQuery,
GQLTargetGroupsSelectQueryVariables,
} from "./SendManagerFields.gql.generated";

interface SendManagerFieldsProps {
disableScheduling?: boolean;
scope: ContentScopeInterface;
id?: string;
isSendable: boolean;
}

const validateScheduledAt = (value: Date, now: Date) => {
Expand All @@ -28,12 +37,19 @@ const validateScheduledAt = (value: Date, now: Date) => {
}
};

export const SendManagerFields = ({ disableScheduling, scope }: SendManagerFieldsProps) => {
export const SendManagerFields = ({ disableScheduling, scope, id, isSendable }: SendManagerFieldsProps) => {
const [isSendEmailCampaignNowDialogOpen, setIsSendEmailCampaignNowDialogOpen] = React.useState(false);

const { data: targetGroups } = useQuery<GQLTargetGroupsSelectQuery, GQLTargetGroupsSelectQueryVariables>(targetGroupsSelectQuery, {
variables: { scope },
fetchPolicy: "network-only",
});

const [sendEmailCampaignNow, { loading: sendEmailCampaignNowLoading, error: sendEmailCampaignNowError }] = useMutation<
GQLSendEmailCampaignNowMutation,
GQLSendEmailCampaignNowMutationVariables
>(sendEmailCampaignNowMutation);

const now = new Date();
return (
<Card>
Expand Down Expand Up @@ -66,6 +82,38 @@ export const SendManagerFields = ({ disableScheduling, scope }: SendManagerField
</FinalFormSelect>
)}
</Field>

<SaveButton
variant="contained"
disabled={!isSendable && id == undefined && disableScheduling}
saveIcon={<Newsletter />}
saving={sendEmailCampaignNowLoading}
hasErrors={!!sendEmailCampaignNowError}
savingItem={<FormattedMessage id="cometBrevoModule.emailCampaigns.sendNow.sendingText" defaultMessage="Sending..." />}
errorItem={
<FormattedMessage
id="cometBrevoModule.emailCampaigns.sendNow.errorText"
defaultMessage="There was an error sending the email campaign."
/>
}
onClick={() => {
setIsSendEmailCampaignNowDialogOpen(true);
}}
>
<FormattedMessage id="cometBrevoModule.emailCampaigns.sendNow.sendText" defaultMessage="Send email campaign now" />
</SaveButton>
<SendEmailCampaignNowDialog
dialogOpen={isSendEmailCampaignNowDialogOpen}
handleNoClick={() => {
setIsSendEmailCampaignNowDialogOpen(false);
}}
handleYesClick={async () => {
if (id) {
await sendEmailCampaignNow({ variables: { id } });
setIsSendEmailCampaignNowDialogOpen(false);
}
}}
/>
</AdminComponentSectionGroup>
</AdminComponentPaper>
</Card>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { gql } from "@apollo/client";

export const SendEmailCampaignToTestEmailsMutation = gql`
mutation SendEmailCampaignToTestEmails($id: ID!, $data: SendTestEmailCampaignArgs!) {
sendEmailCampaignToTestEmails(id: $id, data: $data)
}
`;
114 changes: 114 additions & 0 deletions packages/admin/src/emailCampaigns/form/TestEmailCampaignForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import { useApolloClient } from "@apollo/client";
import { Field, FinalForm, FinalFormInput, SaveButton } from "@comet/admin";
import { Newsletter } from "@comet/admin-icons";
import { AdminComponentPaper, AdminComponentSectionGroup } from "@comet/blocks-admin";
import { Card, FormHelperText, Typography } from "@mui/material";
import React from "react";
import { FormattedMessage } from "react-intl";

import { SendEmailCampaignToTestEmailsMutation } from "./TestEmailCampaignForm.gql";
import { GQLSendEmailCampaignToTestEmailsMutation, GQLSendEmailCampaignToTestEmailsMutationVariables } from "./TestEmailCampaignForm.gql.generated";

interface FormProps {
testEmails: string;
}

interface TestEmailCampaignFormProps {
id?: string;
isSendable?: boolean;
}

export const TestEmailCampaignForm = ({ id, isSendable = false }: TestEmailCampaignFormProps) => {
const client = useApolloClient();

async function submitTestEmails({ testEmails }: FormProps) {
const emailsArray = testEmails.trim().split("\n");

if (id) {
const { data } = await client.mutate<GQLSendEmailCampaignToTestEmailsMutation, GQLSendEmailCampaignToTestEmailsMutationVariables>({
mutation: SendEmailCampaignToTestEmailsMutation,
variables: { id, data: { emails: emailsArray } },
});
return data?.sendEmailCampaignToTestEmails;
}
}

return (
<Card sx={{ mt: 4 }}>
<AdminComponentPaper>
<AdminComponentSectionGroup
title={
<FormattedMessage id="cometBrevoModule.emailCampaigns.testEmailCampaign.title" defaultMessage="Send test email campaign" />
}
>
<FinalForm<FormProps>
mode="edit"
onSubmit={submitTestEmails}
onAfterSubmit={() => {
// override default behavior
}}
>
{({ handleSubmit, submitting, values }) => {
return (
<>
<Field
name="testEmails"
label={
<FormattedMessage
id="cometBrevoModule.emailCampaigns.testEmailCampaign.testEmails"
defaultMessage="Email addresses"
/>
}
component={FinalFormInput}
multiline
placeholder={["First test email address", "Second test email address"].join("\n")}
fullWidth
minRows={4}
/>
<FormHelperText sx={{ marginTop: -2, marginBottom: 4 }}>
<Typography sx={{ display: "flex", alignItems: "center" }}>
<FormattedMessage
id="cometBrevoModule.emailCampaigns.testEmailCampaign.oneEmailAddressEachLine"
defaultMessage="One email address each line"
/>
</Typography>
<Typography />
</FormHelperText>
<SaveButton
disabled={!values.testEmails || !isSendable || !id}
saveIcon={<Newsletter />}
onClick={handleSubmit}
saving={submitting}
errorItem={
<FormattedMessage
id="cometBrevoModule.emailCampaigns.testEmailCampaign.errorText"
defaultMessage="There was an error sending the email campaign to the test addresses."
/>
}
successItem={
<FormattedMessage
id="cometBrevoModule.emailCampaigns.testEmailCampaign.successText"
defaultMessage="Test email campaign was sent successfully."
/>
}
savingItem={
<FormattedMessage
id="cometBrevoModule.emailCampaigns.testEmailCampaign.sendingText"
defaultMessage="Sending..."
/>
}
>
<FormattedMessage
id="cometBrevoModule.emailCampaigns.testEmailCampaign.sendText"
defaultMessage="Send test email campaign"
/>
</SaveButton>
</>
);
}}
</FinalForm>
</AdminComponentSectionGroup>
</AdminComponentPaper>
</Card>
);
};
16 changes: 15 additions & 1 deletion packages/api/src/email-campaign/email-campaign.resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,21 @@ export function createEmailCampaignsResolver({

@Mutation(() => Boolean)
async sendEmailCampaignNow(@Args("id", { type: () => ID }) id: string): Promise<boolean> {
return this.campaignsService.sendEmailCampaignNow(id);
const campaignSent = await this.campaignsService.sendEmailCampaignNow(id);

if (campaignSent) {
const campaign = await this.repository.findOneOrFail(id);

wrap(campaign).assign({
scheduledAt: new Date(),
});

await this.entityManager.flush();

return true;
}

return false;
}

@Mutation(() => Boolean)
Expand Down
2 changes: 1 addition & 1 deletion packages/api/src/email-campaign/email-campaigns.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,6 @@ export class EmailCampaignsService {
} while (currentOffset < totalContacts);
}

return campaign.brevoId ? this.brevoApiCampaignService.sendBrevoCampaign(campaign.brevoId) : false;
return false;
}
}

0 comments on commit ebcc444

Please sign in to comment.