diff --git a/.changeset/clever-moons-push.md b/.changeset/clever-moons-push.md new file mode 100644 index 00000000..67860739 --- /dev/null +++ b/.changeset/clever-moons-push.md @@ -0,0 +1,5 @@ +--- +"@comet/brevo-admin": minor +--- + +Replace the `TextField` with a `FinalFormSelect` component in the `TestEmailCampaignForm`, allowing users to choose contacts directly from the `TestContactList` diff --git a/demo/api/schema.gql b/demo/api/schema.gql index 13a3eacc..0d11c031 100644 --- a/demo/api/schema.gql +++ b/demo/api/schema.gql @@ -891,6 +891,7 @@ enum SubscribeResponse { SUCCESSFUL ERROR_UNKNOWN ERROR_CONTAINED_IN_ECG_RTR_LIST + ERROR_MAXIMAL_NUMBER_OF_TEST_CONTACTS_REACHED } input BrevoContactInput { diff --git a/packages/admin/src/brevoTestContacts/BrevoTestContactsGrid.tsx b/packages/admin/src/brevoTestContacts/BrevoTestContactsGrid.tsx index aa3b12d5..b1f56e0c 100644 --- a/packages/admin/src/brevoTestContacts/BrevoTestContactsGrid.tsx +++ b/packages/admin/src/brevoTestContacts/BrevoTestContactsGrid.tsx @@ -11,6 +11,7 @@ import { ToolbarFillSpace, ToolbarItem, ToolbarTitleItem, + Tooltip, useBufferedRowCount, useDataGridRemote, usePersistentColumnState, @@ -48,7 +49,20 @@ const deleteBrevoTestContactMutation = gql` } `; -function BrevoTestContactsGridToolbar({ intl, scope }: { intl: IntlShape; scope: GQLEmailCampaignContentScopeInput }) { +function BrevoTestContactsGridToolbar({ + intl, + scope, + totalCount, +}: { + intl: IntlShape; + scope: GQLEmailCampaignContentScopeInput; + totalCount: number; +}) { + const disableButton = totalCount >= 100; + const tooltipMessage = intl.formatMessage({ + id: "cometBrevoModule.brevoTestContact.contactLimitReached", + defaultMessage: "Contact limit of 100 reached. You cannot add more contacts.", + }); return ( <> @@ -65,9 +79,21 @@ function BrevoTestContactsGridToolbar({ intl, scope }: { intl: IntlShape; scope: - + + + + + @@ -172,6 +198,7 @@ export function BrevoTestContactsGrid({ const rowCount = useBufferedRowCount(data?.brevoTestContacts.totalCount); if (error) throw error; const rows = data?.brevoTestContacts.nodes ?? []; + const totalCount = data?.brevoTestContacts.totalCount || 0; return ( @@ -197,6 +224,7 @@ export function BrevoTestContactsGrid({ toolbar: { intl, scope, + totalCount, }, }} /> diff --git a/packages/admin/src/emailCampaigns/form/TestEmailCampaignForm.tsx b/packages/admin/src/emailCampaigns/form/TestEmailCampaignForm.tsx index 51c20417..fefab925 100644 --- a/packages/admin/src/emailCampaigns/form/TestEmailCampaignForm.tsx +++ b/packages/admin/src/emailCampaigns/form/TestEmailCampaignForm.tsx @@ -1,16 +1,18 @@ -import { useApolloClient } from "@apollo/client"; -import { Field, FinalForm, FinalFormInput, SaveButton } from "@comet/admin"; +import { gql, useApolloClient, useQuery } from "@apollo/client"; +import { Field, FinalForm, FinalFormSelect, 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 { useContentScope } from "@comet/cms-admin"; +import { Card } from "@mui/material"; import React from "react"; import { FormattedMessage } from "react-intl"; +import { GQLBrevoTestContactsSelectListFragment } from "./TestEmailCampaignForm.generated"; import { SendEmailCampaignToTestEmailsMutation } from "./TestEmailCampaignForm.gql"; import { GQLSendEmailCampaignToTestEmailsMutation, GQLSendEmailCampaignToTestEmailsMutationVariables } from "./TestEmailCampaignForm.gql.generated"; interface FormProps { - testEmails: string; + testEmails: string[]; } interface TestEmailCampaignFormProps { @@ -18,21 +20,46 @@ interface TestEmailCampaignFormProps { isSendable?: boolean; } +const brevoTestContactsSelectFragment = gql` + fragment BrevoTestContactsSelectList on BrevoContact { + id + email + } +`; + +const brevoTestContactsSelectQuery = gql` + query BrevoTestContactsGridSelect($offset: Int, $limit: Int, $email: String, $scope: EmailCampaignContentScopeInput!) { + brevoTestContacts(offset: $offset, limit: $limit, email: $email, scope: $scope) { + nodes { + ...BrevoTestContactsSelectList + } + totalCount + } + } + ${brevoTestContactsSelectFragment} +`; + export const TestEmailCampaignForm = ({ id, isSendable = false }: TestEmailCampaignFormProps) => { const client = useApolloClient(); + const scope = useContentScope(); - async function submitTestEmails({ testEmails }: FormProps) { - const emailsArray = testEmails.trim().split("\n"); + // Contact creation is limited to 100 at a time. Therefore, 100 contacts are queried without using pagination. + const { data, loading, error } = useQuery(brevoTestContactsSelectQuery, { + variables: { offset: 0, limit: 100, scope }, + }); + async function submitTestEmails({ testEmails }: FormProps) { if (id) { const { data } = await client.mutate({ mutation: SendEmailCampaignToTestEmailsMutation, - variables: { id, data: { emails: emailsArray } }, + variables: { id, data: { emails: testEmails } }, }); return data?.sendEmailCampaignToTestEmails; } } + const emailOptions: string[] = data?.brevoTestContacts?.nodes?.map((contact: GQLBrevoTestContactsSelectListFragment) => contact.email) || []; + return ( @@ -41,11 +68,12 @@ export const TestEmailCampaignForm = ({ id, isSendable = false }: TestEmailCampa } > - mode="edit" onSubmit={submitTestEmails}> + mode="edit" onSubmit={submitTestEmails} initialValues={{ testEmails: [] }}> {({ handleSubmit, submitting, values }) => { return ( <> } - component={FinalFormInput} - multiline - placeholder={["First test email address", "Second test email address"].join("\n")} fullWidth - minRows={4} + options={emailOptions} + isLoading={loading} + error={!!error} + value={values.testEmails || []} + getOptionLabel={(option: string) => option} /> - - - - - - } diff --git a/packages/api/src/brevo-api/brevo-api-contact.service.ts b/packages/api/src/brevo-api/brevo-api-contact.service.ts index ed25a1b5..2b8446e1 100644 --- a/packages/api/src/brevo-api/brevo-api-contact.service.ts +++ b/packages/api/src/brevo-api/brevo-api-contact.service.ts @@ -169,6 +169,15 @@ export class BrevoApiContactsService { } } + public async getContactCountByListId(id: number, scope: EmailCampaignScopeInterface): Promise { + try { + const data = await this.getContactsApi(scope).getContactsFromList(id); + return data.body.count; + } catch (error) { + handleBrevoError(error); + } + } + public async findContacts(limit: number, offset: number, scope: EmailCampaignScopeInterface): Promise { try { const data = await this.getContactsApi(scope).getContacts(limit, offset); diff --git a/packages/api/src/brevo-contact/brevo-contact.resolver.ts b/packages/api/src/brevo-contact/brevo-contact.resolver.ts index 02c5a07c..a90f5be1 100644 --- a/packages/api/src/brevo-contact/brevo-contact.resolver.ts +++ b/packages/api/src/brevo-contact/brevo-contact.resolver.ts @@ -237,6 +237,12 @@ export function createBrevoContactResolver({ const targetGroup = await this.targetGroupRepository.findOne(where); const contact = await this.brevoContactsApiService.getContactInfoByEmail(input.email, scope); + if (targetGroup) { + const numberOfContacts = await this.brevoContactsApiService.getContactCountByListId(targetGroup.brevoId, Scope); + if (numberOfContacts >= 100) { + return SubscribeResponse.ERROR_MAXIMAL_NUMBER_OF_TEST_CONTACTS_REACHED; + } + } if (contact && targetGroup) { const listIds: number[] = contact.listIds ? [...contact.listIds] : []; listIds.push(targetGroup.brevoId); diff --git a/packages/api/src/brevo-contact/dto/subscribe-response.enum.ts b/packages/api/src/brevo-contact/dto/subscribe-response.enum.ts index 7f1fd367..6db63b8c 100644 --- a/packages/api/src/brevo-contact/dto/subscribe-response.enum.ts +++ b/packages/api/src/brevo-contact/dto/subscribe-response.enum.ts @@ -4,6 +4,7 @@ export enum SubscribeResponse { SUCCESSFUL = "SUCCESSFUL", ERROR_UNKNOWN = "ERROR_UNKNOWN", ERROR_CONTAINED_IN_ECG_RTR_LIST = "ERROR_CONTAINED_IN_ECG_RTR_LIST", + ERROR_MAXIMAL_NUMBER_OF_TEST_CONTACTS_REACHED = "ERROR_MAXIMAL_NUMBER_OF_TEST_CONTACTS_REACHED", } registerEnumType(SubscribeResponse, {