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:
- } component={StackLink} pageName="add" payload="add" variant="contained" color="primary">
-
-
+
+
+ }
+ component={StackLink}
+ pageName="add"
+ payload="add"
+ variant="contained"
+ color="primary"
+ disabled={disableButton}
+ >
+
+
+
+
>
@@ -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, {