diff --git a/CHANGELOG.md b/CHANGELOG.md
index 835e1854e..56794903e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,7 @@ and this project adheres to
### Added
+- ✨(frontend) add support email field on domain creation form
- ✨(domains) add support email field on MailDomain
## [1.11.0] - 2025-02-07
diff --git a/src/frontend/apps/desk/src/features/mail-domains/access-management/__tests__/accesses.test.tsx b/src/frontend/apps/desk/src/features/mail-domains/access-management/__tests__/accesses.test.tsx
index 600f66552..9e485f0ae 100644
--- a/src/frontend/apps/desk/src/features/mail-domains/access-management/__tests__/accesses.test.tsx
+++ b/src/frontend/apps/desk/src/features/mail-domains/access-management/__tests__/accesses.test.tsx
@@ -99,6 +99,7 @@ describe('MailDomainAccessesPage', () => {
status: 'enabled',
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
+ support_email: 'support@example.com',
abilities: {
get: true,
patch: true,
diff --git a/src/frontend/apps/desk/src/features/mail-domains/access-management/components/__tests__/AccessAction.test.tsx b/src/frontend/apps/desk/src/features/mail-domains/access-management/components/__tests__/AccessAction.test.tsx
index 15007364f..50d627794 100644
--- a/src/frontend/apps/desk/src/features/mail-domains/access-management/components/__tests__/AccessAction.test.tsx
+++ b/src/frontend/apps/desk/src/features/mail-domains/access-management/components/__tests__/AccessAction.test.tsx
@@ -25,6 +25,7 @@ describe('AccessAction', () => {
status: 'enabled',
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
+ support_email: 'support@example.com',
abilities: {
get: true,
patch: true,
diff --git a/src/frontend/apps/desk/src/features/mail-domains/access-management/components/__tests__/AccessesContent.test.tsx b/src/frontend/apps/desk/src/features/mail-domains/access-management/components/__tests__/AccessesContent.test.tsx
index 51ddb0c7b..17998d240 100644
--- a/src/frontend/apps/desk/src/features/mail-domains/access-management/components/__tests__/AccessesContent.test.tsx
+++ b/src/frontend/apps/desk/src/features/mail-domains/access-management/components/__tests__/AccessesContent.test.tsx
@@ -31,6 +31,7 @@ describe('AccessesContent', () => {
status: 'enabled',
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
+ support_email: 'support@example.com',
abilities: {
get: true,
patch: true,
diff --git a/src/frontend/apps/desk/src/features/mail-domains/access-management/components/__tests__/AccessesGrid.test.tsx b/src/frontend/apps/desk/src/features/mail-domains/access-management/components/__tests__/AccessesGrid.test.tsx
index 68e3775d8..31ac23fe4 100644
--- a/src/frontend/apps/desk/src/features/mail-domains/access-management/components/__tests__/AccessesGrid.test.tsx
+++ b/src/frontend/apps/desk/src/features/mail-domains/access-management/components/__tests__/AccessesGrid.test.tsx
@@ -26,6 +26,7 @@ const mockMailDomain: MailDomain = {
status: 'enabled',
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
+ support_email: 'support@example.com',
abilities: {
manage_accesses: true,
get: true,
diff --git a/src/frontend/apps/desk/src/features/mail-domains/access-management/components/__tests__/ModalDelete.test.tsx b/src/frontend/apps/desk/src/features/mail-domains/access-management/components/__tests__/ModalDelete.test.tsx
index e24d169db..571516640 100644
--- a/src/frontend/apps/desk/src/features/mail-domains/access-management/components/__tests__/ModalDelete.test.tsx
+++ b/src/frontend/apps/desk/src/features/mail-domains/access-management/components/__tests__/ModalDelete.test.tsx
@@ -36,6 +36,7 @@ describe('ModalDelete', () => {
status: 'enabled',
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
+ support_email: 'support@example.com',
abilities: {
get: true,
patch: true,
diff --git a/src/frontend/apps/desk/src/features/mail-domains/domains/__tests__/ModalAddMailDomain.test.tsx b/src/frontend/apps/desk/src/features/mail-domains/domains/__tests__/ModalAddMailDomain.test.tsx
index f09c6156d..d45868a1b 100644
--- a/src/frontend/apps/desk/src/features/mail-domains/domains/__tests__/ModalAddMailDomain.test.tsx
+++ b/src/frontend/apps/desk/src/features/mail-domains/domains/__tests__/ModalAddMailDomain.test.tsx
@@ -19,6 +19,7 @@ describe('ModalAddMailDomain', () => {
modalElement: screen.getByText('Add a mail domain'),
formTag: screen.getByTitle('Mail domain addition form'),
inputName: screen.getByLabelText(/Domain name/i),
+ inputSupportEmail: screen.getByLabelText(/Support email address/i),
buttonCancel: screen.getByRole('button', { name: /Cancel/i, hidden: true }),
buttonSubmit: screen.getByRole('button', {
name: /Add the domain/i,
@@ -37,12 +38,19 @@ describe('ModalAddMailDomain', () => {
it('renders all the elements', () => {
render(, { wrapper: AppWrapper });
- const { modalElement, formTag, inputName, buttonCancel, buttonSubmit } =
- getElements();
+ const {
+ modalElement,
+ formTag,
+ inputName,
+ inputSupportEmail,
+ buttonCancel,
+ buttonSubmit,
+ } = getElements();
expect(modalElement).toBeVisible();
expect(formTag).toBeVisible();
expect(inputName).toBeVisible();
+ expect(inputSupportEmail).toBeVisible();
expect(screen.getByText('Example: saint-laurent.fr')).toBeVisible();
expect(buttonCancel).toBeVisible();
expect(buttonSubmit).toBeVisible();
@@ -104,9 +112,10 @@ describe('ModalAddMailDomain', () => {
render(, { wrapper: AppWrapper });
- const { inputName, buttonSubmit } = getElements();
+ const { inputName, inputSupportEmail, buttonSubmit } = getElements();
await user.type(inputName, 'domain.fr');
+ await user.type(inputSupportEmail, 'support@domain.fr');
await user.click(buttonSubmit);
@@ -114,6 +123,7 @@ describe('ModalAddMailDomain', () => {
expect(fetchMock.lastOptions()).toEqual({
body: JSON.stringify({
name: 'domain.fr',
+ support_email: 'support@domain.fr',
}),
credentials: 'include',
headers: { 'Content-Type': 'application/json' },
@@ -123,29 +133,6 @@ describe('ModalAddMailDomain', () => {
expect(mockPush).toHaveBeenCalledWith(`/mail-domains/domainfr`);
});
- it('submits the form on key enter press', async () => {
- fetchMock.mock(`end:mail-domains/`, 201);
-
- const user = userEvent.setup();
-
- render(, { wrapper: AppWrapper });
-
- const { inputName } = getElements();
-
- await user.type(inputName, 'domain.fr');
- await user.type(inputName, '{enter}');
-
- expect(fetchMock.lastUrl()).toContain('/mail-domains/');
- expect(fetchMock.lastOptions()).toEqual({
- body: JSON.stringify({
- name: 'domain.fr',
- }),
- credentials: 'include',
- headers: { 'Content-Type': 'application/json' },
- method: 'POST',
- });
- });
-
it('displays right error message error when maildomain name is already used', async () => {
fetchMock.mock(`end:mail-domains/`, {
status: 400,
@@ -158,10 +145,10 @@ describe('ModalAddMailDomain', () => {
render(, { wrapper: AppWrapper });
- const { inputName, buttonSubmit } = getElements();
+ const { inputName, inputSupportEmail, buttonSubmit } = getElements();
await user.type(inputName, 'domain.fr');
-
+ await user.type(inputSupportEmail, 'support@domain.fr');
await user.click(buttonSubmit);
await waitFor(() => {
@@ -175,6 +162,8 @@ describe('ModalAddMailDomain', () => {
expect(inputName).toHaveFocus();
await user.type(inputName, 'domain2.fr');
+ //await user.type(inputSupportEmail, 'support@domain.fr');
+
expect(buttonSubmit).toBeEnabled();
});
@@ -190,9 +179,10 @@ describe('ModalAddMailDomain', () => {
render(, { wrapper: AppWrapper });
- const { inputName, buttonSubmit } = getElements();
+ const { inputName, inputSupportEmail, buttonSubmit } = getElements();
await user.type(inputName, 'domainfr');
+ await user.type(inputSupportEmail, 'support@domain.fr');
await user.click(buttonSubmit);
@@ -220,9 +210,10 @@ describe('ModalAddMailDomain', () => {
render(, { wrapper: AppWrapper });
- const { inputName, buttonSubmit } = getElements();
+ const { inputName, inputSupportEmail, buttonSubmit } = getElements();
await user.type(inputName, 'domain.fr');
+ await user.type(inputSupportEmail, 'support@domain.fr');
await user.click(buttonSubmit);
diff --git a/src/frontend/apps/desk/src/features/mail-domains/domains/api/useAddMailDomain.tsx b/src/frontend/apps/desk/src/features/mail-domains/domains/api/useAddMailDomain.tsx
index c76d3b648..1c73e6bba 100644
--- a/src/frontend/apps/desk/src/features/mail-domains/domains/api/useAddMailDomain.tsx
+++ b/src/frontend/apps/desk/src/features/mail-domains/domains/api/useAddMailDomain.tsx
@@ -8,16 +8,16 @@ import { KEY_LIST_MAIL_DOMAIN } from './useMailDomains';
export interface AddMailDomainParams {
name: string;
+ supportEmail: string;
}
-export const addMailDomain = async (
- name: AddMailDomainParams['name'],
-): Promise => {
+export const addMailDomain = async ({
+ name,
+ supportEmail,
+}: AddMailDomainParams): Promise => {
const response = await fetchAPI(`mail-domains/`, {
method: 'POST',
- body: JSON.stringify({
- name,
- }),
+ body: JSON.stringify({ name, support_email: supportEmail }),
});
if (!response.ok) {
@@ -38,7 +38,7 @@ export const useAddMailDomain = ({
onError: (error: APIError) => void;
}) => {
const queryClient = useQueryClient();
- return useMutation({
+ return useMutation({
mutationFn: addMailDomain,
onSuccess: (data) => {
void queryClient.invalidateQueries({
diff --git a/src/frontend/apps/desk/src/features/mail-domains/domains/components/ModalAddMailDomain.tsx b/src/frontend/apps/desk/src/features/mail-domains/domains/components/ModalAddMailDomain.tsx
index 62f07c4e9..20dc24fb6 100644
--- a/src/frontend/apps/desk/src/features/mail-domains/domains/components/ModalAddMailDomain.tsx
+++ b/src/frontend/apps/desk/src/features/mail-domains/domains/components/ModalAddMailDomain.tsx
@@ -2,10 +2,16 @@ import { zodResolver } from '@hookform/resolvers/zod';
import { Button, Input, Loader, ModalSize } from '@openfun/cunningham-react';
import { useRouter } from 'next/navigation';
import React, { useState } from 'react';
-import { Controller, FormProvider, useForm } from 'react-hook-form';
+import {
+ Controller,
+ FormProvider,
+ UseFormReturn,
+ useForm,
+} from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import { z } from 'zod';
+import { APIError } from '@/api';
import { parseAPIError } from '@/api/parseAPIError';
import { Box, Text, TextErrors } from '@/components';
import { Modal } from '@/components/Modal';
@@ -23,12 +29,14 @@ export const ModalAddMailDomain = () => {
const addMailDomainValidationSchema = z.object({
name: z.string().min(1, t('Example: saint-laurent.fr')),
+ supportEmail: z.string().email(t('Please enter a valid email address')),
});
- const methods = useForm<{ name: string }>({
+ const methods = useForm<{ name: string; supportEmail: string }>({
delayError: 0,
defaultValues: {
name: '',
+ supportEmail: '',
},
mode: 'onChange',
reValidateMode: 'onChange',
@@ -39,7 +47,7 @@ export const ModalAddMailDomain = () => {
onSuccess: (mailDomain) => {
router.push(`/mail-domains/${mailDomain.slug}`);
},
- onError: (error) => {
+ onError: (error: APIError) => {
const unhandledCauses = parseAPIError({
error,
errorParams: [
@@ -87,8 +95,8 @@ export const ModalAddMailDomain = () => {
const onSubmitCallback = (event: React.FormEvent) => {
event.preventDefault();
- void methods.handleSubmit(({ name }) => {
- void addMailDomain(name);
+ void methods.handleSubmit(({ name, supportEmail }) => {
+ void addMailDomain({ name, supportEmail });
})();
};
@@ -167,6 +175,27 @@ export const ModalAddMailDomain = () => {
/>
)}
/>
+
+ (
+
+ )}
+ />
+
{isPending && (
diff --git a/src/frontend/apps/desk/src/features/mail-domains/domains/types.ts b/src/frontend/apps/desk/src/features/mail-domains/domains/types.ts
index 8c877bbc0..4f9489b45 100644
--- a/src/frontend/apps/desk/src/features/mail-domains/domains/types.ts
+++ b/src/frontend/apps/desk/src/features/mail-domains/domains/types.ts
@@ -7,6 +7,7 @@ export interface MailDomain {
updated_at: string;
slug: string;
status: 'pending' | 'enabled' | 'failed' | 'disabled';
+ support_email: string;
abilities: {
get: boolean;
patch: boolean;
diff --git a/src/frontend/apps/desk/src/features/mail-domains/mailboxes/components/__tests__/MailDomainsContent.test.tsx b/src/frontend/apps/desk/src/features/mail-domains/mailboxes/components/__tests__/MailDomainsContent.test.tsx
index e4e1a4137..2cc3e1a86 100644
--- a/src/frontend/apps/desk/src/features/mail-domains/mailboxes/components/__tests__/MailDomainsContent.test.tsx
+++ b/src/frontend/apps/desk/src/features/mail-domains/mailboxes/components/__tests__/MailDomainsContent.test.tsx
@@ -14,6 +14,7 @@ const mockMailDomain: MailDomain = {
name: 'example.com',
slug: 'example-com',
status: 'enabled',
+ support_email: 'support@example.com',
abilities: {
get: true,
patch: true,
@@ -31,6 +32,7 @@ const mockMailDomainAsViewer: MailDomain = {
name: 'example.com',
slug: 'example-com',
status: 'enabled',
+ support_email: 'support@example.com',
abilities: {
get: true,
patch: false,
diff --git a/src/frontend/apps/desk/src/features/mail-domains/mailboxes/components/__tests__/ModalCreateMailbox.test.tsx b/src/frontend/apps/desk/src/features/mail-domains/mailboxes/components/__tests__/ModalCreateMailbox.test.tsx
index 51659aad4..6898468ea 100644
--- a/src/frontend/apps/desk/src/features/mail-domains/mailboxes/components/__tests__/ModalCreateMailbox.test.tsx
+++ b/src/frontend/apps/desk/src/features/mail-domains/mailboxes/components/__tests__/ModalCreateMailbox.test.tsx
@@ -14,6 +14,7 @@ const mockMailDomain: MailDomain = {
status: 'enabled',
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
+ support_email: 'support@example.com',
abilities: {
get: true,
patch: true,
diff --git a/src/frontend/apps/e2e/__tests__/app-desk/mail-domains-add.spec.ts b/src/frontend/apps/e2e/__tests__/app-desk/mail-domains-add.spec.ts
index beb194e07..f57e32acb 100644
--- a/src/frontend/apps/e2e/__tests__/app-desk/mail-domains-add.spec.ts
+++ b/src/frontend/apps/e2e/__tests__/app-desk/mail-domains-add.spec.ts
@@ -9,6 +9,7 @@ const getElements = (page: Page) => {
});
const form = page.locator('form');
const inputName = form.getByLabel('Domain name');
+ const inputSupportEmail = form.getByLabel('Support email address');
const buttonSubmit = page.getByRole('button', {
name: 'Add the domain',
});
@@ -22,6 +23,7 @@ const getElements = (page: Page) => {
linkIndexPageAddDomain,
form,
inputName,
+ inputSupportEmail,
buttonCancel,
buttonSubmit,
};
@@ -50,6 +52,7 @@ test.describe('Add Mail Domains', () => {
}),
).toBeVisible();
+ await expect(inputName).toBeVisible();
await expect(inputName).toBeVisible();
await expect(page.getByText('Example: saint-laurent.fr')).toBeVisible();
@@ -82,12 +85,17 @@ test.describe('Add Mail Domains', () => {
test('checks form invalid status', async ({ page }) => {
await page.goto('/mail-domains/');
- const { linkIndexPageAddDomain, inputName, buttonSubmit } =
- getElements(page);
+ const {
+ linkIndexPageAddDomain,
+ inputName,
+ inputSupportEmail,
+ buttonSubmit,
+ } = getElements(page);
await linkIndexPageAddDomain.click();
await expect(inputName).toBeVisible();
+ await expect(inputSupportEmail).toBeVisible();
await expect(page.getByText('Example: saint-laurent.fr')).toBeVisible();
await expect(
@@ -111,16 +119,23 @@ test.describe('Add Mail Domains', () => {
browserName,
}) => {
const mailDomainName = randomName('versailles.fr', browserName, 1)[0];
+ const mailDomainSupportMail = 'support@'.concat(mailDomainName);
const mailDomainSlug = mailDomainName.replace('.', '');
await page.goto('/mail-domains/');
- const { linkIndexPageAddDomain, inputName, buttonSubmit } =
- getElements(page);
+ const {
+ linkIndexPageAddDomain,
+ inputName,
+ inputSupportEmail,
+ buttonSubmit,
+ } = getElements(page);
await linkIndexPageAddDomain.click();
await inputName.fill(mailDomainName);
+ await inputSupportEmail.fill(mailDomainSupportMail);
+
await buttonSubmit.click();
await expect(page).toHaveURL(`/mail-domains/${mailDomainSlug}/`);