Skip to content

Commit

Permalink
✨(frontend) add support email field on domain creation form
Browse files Browse the repository at this point in the history
Add new field to give email of support to manage actions
required on domain.
  • Loading branch information
sdemagny committed Feb 7, 2025
1 parent 10a13bf commit 2411504
Show file tree
Hide file tree
Showing 13 changed files with 108 additions and 46 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ and this project adheres to

### Added

- ✨(frontend) add support email field on domain creation form
- ✨(domains) add support email field on MailDomain
- ✨(api) add count mailboxes to MailDomain serializer
- ✨(dimail) manage 'action required' status for MailDomain
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ describe('MailDomainAccessesPage', () => {
status: 'enabled',
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
support_email: '[email protected]',
abilities: {
get: true,
patch: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ describe('AccessAction', () => {
status: 'enabled',
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
support_email: '[email protected]',
abilities: {
get: true,
patch: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ describe('AccessesContent', () => {
status: 'enabled',
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
support_email: '[email protected]',
abilities: {
get: true,
patch: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const mockMailDomain: MailDomain = {
status: 'enabled',
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
support_email: '[email protected]',
abilities: {
manage_accesses: true,
get: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ describe('ModalDelete', () => {
status: 'enabled',
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
support_email: '[email protected]',
abilities: {
get: true,
patch: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -37,12 +38,19 @@ describe('ModalAddMailDomain', () => {
it('renders all the elements', () => {
render(<ModalAddMailDomain />, { 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();
Expand Down Expand Up @@ -104,16 +112,18 @@ describe('ModalAddMailDomain', () => {

render(<ModalAddMailDomain />, { wrapper: AppWrapper });

const { inputName, buttonSubmit } = getElements();
const { inputName, inputSupportEmail, buttonSubmit } = getElements();

await user.type(inputName, 'domain.fr');
await user.type(inputSupportEmail, '[email protected]');

await user.click(buttonSubmit);

expect(fetchMock.lastUrl()).toContain('/mail-domains/');
expect(fetchMock.lastOptions()).toEqual({
body: JSON.stringify({
name: 'domain.fr',
support_email: '[email protected]',
}),
credentials: 'include',
headers: { 'Content-Type': 'application/json' },
Expand All @@ -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(<ModalAddMailDomain />, { 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,
Expand All @@ -158,10 +145,10 @@ describe('ModalAddMailDomain', () => {

render(<ModalAddMailDomain />, { wrapper: AppWrapper });

const { inputName, buttonSubmit } = getElements();
const { inputName, inputSupportEmail, buttonSubmit } = getElements();

await user.type(inputName, 'domain.fr');

await user.type(inputSupportEmail, '[email protected]');
await user.click(buttonSubmit);

await waitFor(() => {
Expand All @@ -175,6 +162,8 @@ describe('ModalAddMailDomain', () => {
expect(inputName).toHaveFocus();

await user.type(inputName, 'domain2.fr');
//await user.type(inputSupportEmail, '[email protected]');

expect(buttonSubmit).toBeEnabled();
});

Expand All @@ -190,9 +179,10 @@ describe('ModalAddMailDomain', () => {

render(<ModalAddMailDomain />, { wrapper: AppWrapper });

const { inputName, buttonSubmit } = getElements();
const { inputName, inputSupportEmail, buttonSubmit } = getElements();

await user.type(inputName, 'domainfr');
await user.type(inputSupportEmail, '[email protected]');

await user.click(buttonSubmit);

Expand Down Expand Up @@ -220,9 +210,10 @@ describe('ModalAddMailDomain', () => {

render(<ModalAddMailDomain />, { wrapper: AppWrapper });

const { inputName, buttonSubmit } = getElements();
const { inputName, inputSupportEmail, buttonSubmit } = getElements();

await user.type(inputName, 'domain.fr');
await user.type(inputSupportEmail, '[email protected]');

await user.click(buttonSubmit);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<MailDomain> => {
export const addMailDomain = async ({
name,
supportEmail,
}: AddMailDomainParams): Promise<MailDomain> => {
const response = await fetchAPI(`mail-domains/`, {
method: 'POST',
body: JSON.stringify({
name,
}),
body: JSON.stringify({ name, support_email: supportEmail }),
});

if (!response.ok) {
Expand All @@ -38,7 +38,7 @@ export const useAddMailDomain = ({
onError: (error: APIError) => void;
}) => {
const queryClient = useQueryClient();
return useMutation<MailDomain, APIError, string>({
return useMutation<MailDomain, APIError, AddMailDomainParams>({
mutationFn: addMailDomain,
onSuccess: (data) => {
void queryClient.invalidateQueries({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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',
Expand All @@ -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: [
Expand Down Expand Up @@ -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 });
})();
};

Expand Down Expand Up @@ -167,6 +175,14 @@ export const ModalAddMailDomain = () => {
/>
)}
/>
<Box $margin={{ vertical: '10px' }}>
<FieldMailBox
name="supportEmail"
label={t('Support email address')}
methods={methods}
text={t('E.g. : [email protected]')}
/>
</Box>
</form>

{isPending && (
Expand All @@ -178,3 +194,33 @@ export const ModalAddMailDomain = () => {
</Modal>
);
};

interface FieldMailBoxProps {
name: 'name' | 'supportEmail';
label: string;
methods: UseFormReturn<{
name: string;
supportEmail: string;
}>;
text: string;
}

const FieldMailBox = ({ name, label, methods, text }: FieldMailBoxProps) => {
return (
<Controller
control={methods.control}
name={name}
render={({ fieldState }) => (
<Input
aria-invalid={!!fieldState.error}
aria-required
required
label={label}
state={fieldState.error ? 'error' : 'default'}
text={fieldState?.error?.message ? fieldState.error.message : text}
{...methods.register(name)}
/>
)}
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const mockMailDomain: MailDomain = {
name: 'example.com',
slug: 'example-com',
status: 'enabled',
support_email: '[email protected]',
abilities: {
get: true,
patch: true,
Expand All @@ -31,6 +32,7 @@ const mockMailDomainAsViewer: MailDomain = {
name: 'example.com',
slug: 'example-com',
status: 'enabled',
support_email: '[email protected]',
abilities: {
get: true,
patch: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const mockMailDomain: MailDomain = {
status: 'enabled',
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
support_email: '[email protected]',
abilities: {
get: true,
patch: true,
Expand Down
Loading

0 comments on commit 2411504

Please sign in to comment.