diff --git a/packages/admin/src/emailCampaigns/form/EmailCampaignForm.tsx b/packages/admin/src/emailCampaigns/form/EmailCampaignForm.tsx index 9cc80b03..8e11db66 100644 --- a/packages/admin/src/emailCampaigns/form/EmailCampaignForm.tsx +++ b/packages/admin/src/emailCampaigns/form/EmailCampaignForm.tsx @@ -52,6 +52,7 @@ import { GQLUpdateEmailCampaignMutationVariables, } from "./EmailCampaignForm.gql.generated"; import { SendManagerFields } from "./SendManagerFields"; +import { TestEmailCampaignForm } from "./TestEmailCampaignForm"; interface FormProps { id?: string; @@ -287,7 +288,13 @@ export function EmailCampaignForm({ id, EmailCampaignContentBlock, scope, previe scheduledAt: state.scheduledAt, }} > - + + ), }, diff --git a/packages/admin/src/emailCampaigns/form/SendEmailCampaignNowDialog.tsx b/packages/admin/src/emailCampaigns/form/SendEmailCampaignNowDialog.tsx new file mode 100644 index 00000000..076b7b9a --- /dev/null +++ b/packages/admin/src/emailCampaigns/form/SendEmailCampaignNowDialog.tsx @@ -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 ( + + + + + + + + + + + + + + + ); +}; + +export { SendEmailCampaignNowDialog }; diff --git a/packages/admin/src/emailCampaigns/form/SendManagerFields.gql.ts b/packages/admin/src/emailCampaigns/form/SendManagerFields.gql.ts index 1fe7a6d7..08c6538c 100644 --- a/packages/admin/src/emailCampaigns/form/SendManagerFields.gql.ts +++ b/packages/admin/src/emailCampaigns/form/SendManagerFields.gql.ts @@ -10,3 +10,9 @@ export const targetGroupsSelectQuery = gql` } } `; + +export const sendEmailCampaignNowMutation = gql` + mutation SendEmailCampaignNow($id: ID!) { + sendEmailCampaignNow(id: $id) + } +`; diff --git a/packages/admin/src/emailCampaigns/form/SendManagerFields.tsx b/packages/admin/src/emailCampaigns/form/SendManagerFields.tsx index 38283864..85c016c5 100644 --- a/packages/admin/src/emailCampaigns/form/SendManagerFields.tsx +++ b/packages/admin/src/emailCampaigns/form/SendManagerFields.tsx @@ -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) => { @@ -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(targetGroupsSelectQuery, { variables: { scope }, fetchPolicy: "network-only", }); + const [sendEmailCampaignNow, { loading: sendEmailCampaignNowLoading, error: sendEmailCampaignNowError }] = useMutation< + GQLSendEmailCampaignNowMutation, + GQLSendEmailCampaignNowMutationVariables + >(sendEmailCampaignNowMutation); + const now = new Date(); return ( @@ -66,6 +82,38 @@ export const SendManagerFields = ({ disableScheduling, scope }: SendManagerField )} + + } + saving={sendEmailCampaignNowLoading} + hasErrors={!!sendEmailCampaignNowError} + savingItem={} + errorItem={ + + } + onClick={() => { + setIsSendEmailCampaignNowDialogOpen(true); + }} + > + + + { + setIsSendEmailCampaignNowDialogOpen(false); + }} + handleYesClick={async () => { + if (id) { + await sendEmailCampaignNow({ variables: { id } }); + setIsSendEmailCampaignNowDialogOpen(false); + } + }} + /> diff --git a/packages/admin/src/emailCampaigns/form/TestEmailCampaignForm.gql.ts b/packages/admin/src/emailCampaigns/form/TestEmailCampaignForm.gql.ts new file mode 100644 index 00000000..a4d4669f --- /dev/null +++ b/packages/admin/src/emailCampaigns/form/TestEmailCampaignForm.gql.ts @@ -0,0 +1,7 @@ +import { gql } from "@apollo/client"; + +export const SendEmailCampaignToTestEmailsMutation = gql` + mutation SendEmailCampaignToTestEmails($id: ID!, $data: SendTestEmailCampaignArgs!) { + sendEmailCampaignToTestEmails(id: $id, data: $data) + } +`; diff --git a/packages/admin/src/emailCampaigns/form/TestEmailCampaignForm.tsx b/packages/admin/src/emailCampaigns/form/TestEmailCampaignForm.tsx new file mode 100644 index 00000000..ac66004d --- /dev/null +++ b/packages/admin/src/emailCampaigns/form/TestEmailCampaignForm.tsx @@ -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({ + mutation: SendEmailCampaignToTestEmailsMutation, + variables: { id, data: { emails: emailsArray } }, + }); + return data?.sendEmailCampaignToTestEmails; + } + } + + return ( + + + + } + > + + mode="edit" + onSubmit={submitTestEmails} + onAfterSubmit={() => { + // override default behavior + }} + > + {({ handleSubmit, submitting, values }) => { + return ( + <> + + } + component={FinalFormInput} + multiline + placeholder={["First test email address", "Second test email address"].join("\n")} + fullWidth + minRows={4} + /> + + + + + + + } + onClick={handleSubmit} + saving={submitting} + errorItem={ + + } + successItem={ + + } + savingItem={ + + } + > + + + + ); + }} + + + + + ); +}; diff --git a/packages/api/src/email-campaign/email-campaign.resolver.ts b/packages/api/src/email-campaign/email-campaign.resolver.ts index f7d9c2dd..68ca8bc3 100644 --- a/packages/api/src/email-campaign/email-campaign.resolver.ts +++ b/packages/api/src/email-campaign/email-campaign.resolver.ts @@ -173,7 +173,21 @@ export function createEmailCampaignsResolver({ @Mutation(() => Boolean) async sendEmailCampaignNow(@Args("id", { type: () => ID }) id: string): Promise { - 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) diff --git a/packages/api/src/email-campaign/email-campaigns.service.ts b/packages/api/src/email-campaign/email-campaigns.service.ts index 822351e8..378eeab6 100644 --- a/packages/api/src/email-campaign/email-campaigns.service.ts +++ b/packages/api/src/email-campaign/email-campaigns.service.ts @@ -125,6 +125,6 @@ export class EmailCampaignsService { } while (currentOffset < totalContacts); } - return campaign.brevoId ? this.brevoApiCampaignService.sendBrevoCampaign(campaign.brevoId) : false; + return false; } }