Skip to content

Commit

Permalink
BHBC-1972: Delete a Draft Project (#837)
Browse files Browse the repository at this point in the history
  • Loading branch information
KjartanE authored Nov 2, 2022
1 parent a1d9c6a commit 0c75e56
Show file tree
Hide file tree
Showing 5 changed files with 251 additions and 3 deletions.
1 change: 0 additions & 1 deletion app/src/components/map/MapContainer.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,6 @@ describe('MapContainer', () => {
nonEditableGeometries={nonEditableGeometries}
/>
);

expect(asFragment()).toMatchSnapshot();
});

Expand Down
6 changes: 6 additions & 0 deletions app/src/constants/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ export const CreateProjectDraftI18N = {
'An error has occurred while attempting to save your draft, please try again. If the error persists, please contact your system administrator.'
};

export const DeleteProjectDraftI18N = {
draftErrorTitle: 'Error Deleting Draft',
draftErrorText:
'An error has occurred while attempting to delete your draft, please try again. If the error persists, please contact your system administrator.'
};

export const EditPartnershipsI18N = {
editTitle: 'Edit Partnerships',
editErrorTitle: 'Error Editing Partnerships',
Expand Down
17 changes: 17 additions & 0 deletions app/src/features/projects/create/CreateProjectForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import makeStyles from '@material-ui/core/styles/makeStyles';
import HorizontalSplitFormComponent from 'components/fields/HorizontalSplitFormComponent';
import { ScrollToFormikError } from 'components/formik/ScrollToFormikError';
import { Formik, FormikProps } from 'formik';
import { useQuery } from 'hooks/useQuery';
import { IGetAllCodeSetsResponse } from 'interfaces/useCodesApi.interface';
import { ICreateProjectRequest } from 'interfaces/useProjectApi.interface';
import React from 'react';
Expand Down Expand Up @@ -60,6 +61,7 @@ export interface ICreateProjectForm {
handleSubmit: (formikData: ICreateProjectRequest) => void;
handleCancel: () => void;
handleDraft: (value: React.SetStateAction<boolean>) => void;
handleDeleteDraft: (value: React.SetStateAction<boolean>) => void;
formikRef: React.RefObject<FormikProps<ICreateProjectRequest>>;
}

Expand Down Expand Up @@ -89,6 +91,7 @@ const CreateProjectForm: React.FC<ICreateProjectForm> = (props) => {
const { codes, formikRef } = props;

const classes = useStyles();
const queryParams = useQuery();

const handleSubmit = async (formikData: ICreateProjectRequest) => {
props.handleSubmit(formikData);
Expand All @@ -102,6 +105,10 @@ const CreateProjectForm: React.FC<ICreateProjectForm> = (props) => {
props.handleDraft(true);
};

const handleDeleteDraft = () => {
props.handleDeleteDraft(true);
};

return (
<Box p={5}>
<Formik
Expand Down Expand Up @@ -261,6 +268,16 @@ const CreateProjectForm: React.FC<ICreateProjectForm> = (props) => {
<Button color="primary" size="large" variant="outlined" onClick={handleDraft} className={classes.actionButton}>
Save Draft
</Button>
{queryParams.draftId && (
<Button
color="primary"
size="large"
variant="outlined"
onClick={handleDeleteDraft}
className={classes.actionButton}>
Delete Draft
</Button>
)}
<Button color="primary" size="large" variant="outlined" onClick={handleCancel} className={classes.actionButton}>
Cancel
</Button>
Expand Down
185 changes: 185 additions & 0 deletions app/src/features/projects/create/CreateProjectPage.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const mockUseBiohubApi = {
draft: {
createDraft: jest.fn<Promise<object>, []>(),
updateDraft: jest.fn<Promise<object>, []>(),
deleteDraft: jest.fn(),
getDraft: jest.fn()
},
external: {
Expand Down Expand Up @@ -174,6 +175,190 @@ describe('CreateProjectPage', () => {
jest.restoreAllMocks();
});

describe('Delete Draft Button', () => {
it('does not display delete draft button if not in draft', async () => {
const { queryByText } = render(
<MemoryRouter>
<CreateProjectPage />
</MemoryRouter>
);

await waitFor(() => {
expect(queryByText('Delete Draft', { exact: false })).not.toBeInTheDocument();
});
});

it('does display delete draft button if in draft', async () => {
mockBiohubApi().codes.getAllCodeSets.mockResolvedValue(({
coordinator_agency: [{ id: 1, name: 'A Rocha Canada' }]
} as unknown) as IGetAllCodeSetsResponse);

mockBiohubApi().draft.getDraft.mockResolvedValue({
id: 1,
name: 'My draft',
data: {
coordinator: {
first_name: 'Draft first name',
last_name: 'Draft last name',
email_address: '[email protected]',
coordinator_agency: '',
share_contact_details: 'false'
},
project: ProjectDetailsFormInitialValues.project,
objectives: ProjectObjectivesFormInitialValues.objectives,
location: ProjectLocationFormInitialValues.location,
iucn: ProjectIUCNFormInitialValues.iucn,
funding: ProjectFundingFormInitialValues.funding,
partnerships: ProjectPartnershipsFormInitialValues.partnerships
}
});

const { queryAllByText } = render(
<MemoryRouter initialEntries={['?draftId=1']}>
<CreateProjectPage />
</MemoryRouter>
);

await waitFor(() => {
expect(queryAllByText('Delete Draft', { exact: false }).length).toEqual(2);
});
});

it('dispalys a Delete draft Yes/No Dialog', async () => {
mockBiohubApi().codes.getAllCodeSets.mockResolvedValue(({
coordinator_agency: [{ id: 1, name: 'A Rocha Canada' }]
} as unknown) as IGetAllCodeSetsResponse);

mockBiohubApi().draft.getDraft.mockResolvedValue({
id: 1,
name: 'My draft',
data: {
coordinator: {
first_name: 'Draft first name',
last_name: 'Draft last name',
email_address: '[email protected]',
coordinator_agency: '',
share_contact_details: 'false'
},
project: ProjectDetailsFormInitialValues.project,
objectives: ProjectObjectivesFormInitialValues.objectives,
location: ProjectLocationFormInitialValues.location,
iucn: ProjectIUCNFormInitialValues.iucn,
funding: ProjectFundingFormInitialValues.funding,
partnerships: ProjectPartnershipsFormInitialValues.partnerships
}
});

const { getByText, findAllByText } = render(
<MemoryRouter initialEntries={['?draftId=1']}>
<CreateProjectPage />
</MemoryRouter>
);

const deleteButton = await findAllByText('Delete Draft', { exact: false });

fireEvent.click(deleteButton[0]);

await waitFor(() => {
expect(getByText('Are you sure you want to delete this draft?', { exact: false })).toBeInTheDocument();
});
});

it('closes dialog on No click', async () => {
mockBiohubApi().codes.getAllCodeSets.mockResolvedValue(({
coordinator_agency: [{ id: 1, name: 'A Rocha Canada' }]
} as unknown) as IGetAllCodeSetsResponse);

mockBiohubApi().draft.getDraft.mockResolvedValue({
id: 1,
name: 'My draft',
data: {
coordinator: {
first_name: 'Draft first name',
last_name: 'Draft last name',
email_address: '[email protected]',
coordinator_agency: '',
share_contact_details: 'false'
},
project: ProjectDetailsFormInitialValues.project,
objectives: ProjectObjectivesFormInitialValues.objectives,
location: ProjectLocationFormInitialValues.location,
iucn: ProjectIUCNFormInitialValues.iucn,
funding: ProjectFundingFormInitialValues.funding,
partnerships: ProjectPartnershipsFormInitialValues.partnerships
}
});

const { getByText, findAllByText, getByTestId, queryByText } = render(
<MemoryRouter initialEntries={['?draftId=1']}>
<CreateProjectPage />
</MemoryRouter>
);

const deleteButton = await findAllByText('Delete Draft', { exact: false });

fireEvent.click(deleteButton[0]);

await waitFor(() => {
expect(getByText('Are you sure you want to delete this draft?')).toBeInTheDocument();
});

const NoButton = await getByTestId('no-button');
fireEvent.click(NoButton);

await waitFor(() => {
expect(queryByText('Are you sure you want to delete this draft?')).not.toBeInTheDocument();
});
});

it('deletes draft on Yes click', async () => {
mockBiohubApi().codes.getAllCodeSets.mockResolvedValue(({
coordinator_agency: [{ id: 1, name: 'A Rocha Canada' }]
} as unknown) as IGetAllCodeSetsResponse);

mockBiohubApi().draft.getDraft.mockResolvedValue({
id: 1,
name: 'My draft',
data: {
coordinator: {
first_name: 'Draft first name',
last_name: 'Draft last name',
email_address: '[email protected]',
coordinator_agency: '',
share_contact_details: 'false'
},
project: ProjectDetailsFormInitialValues.project,
objectives: ProjectObjectivesFormInitialValues.objectives,
location: ProjectLocationFormInitialValues.location,
iucn: ProjectIUCNFormInitialValues.iucn,
funding: ProjectFundingFormInitialValues.funding,
partnerships: ProjectPartnershipsFormInitialValues.partnerships
}
});

const { getByText, findAllByText, getByTestId } = render(
<MemoryRouter initialEntries={['?draftId=1']}>
<CreateProjectPage />
</MemoryRouter>
);

const deleteButton = await findAllByText('Delete Draft', { exact: false });

fireEvent.click(deleteButton[0]);

await waitFor(() => {
expect(getByText('Are you sure you want to delete this draft?')).toBeInTheDocument();
});

const YesButton = await getByTestId('yes-button');
fireEvent.click(YesButton);

await waitFor(() => {
expect(mockBiohubApi().draft.deleteDraft).toBeCalled();
});
});
});

it('preloads draft data and populates on form fields', async () => {
mockBiohubApi().codes.getAllCodeSets.mockResolvedValue(({
coordinator_agency: [{ id: 1, name: 'A Rocha Canada' }]
Expand Down
45 changes: 43 additions & 2 deletions app/src/features/projects/create/CreateProjectPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ import makeStyles from '@material-ui/core/styles/makeStyles';
import Typography from '@material-ui/core/Typography';
import EditDialog from 'components/dialog/EditDialog';
import { IErrorDialogProps } from 'components/dialog/ErrorDialog';
import YesNoDialog from 'components/dialog/YesNoDialog';
import { DATE_FORMAT } from 'constants/dateTimeFormats';
import { CreateProjectDraftI18N, CreateProjectI18N } from 'constants/i18n';
import { CreateProjectDraftI18N, CreateProjectI18N, DeleteProjectDraftI18N } from 'constants/i18n';
import { DialogContext } from 'contexts/dialogContext';
import ProjectDraftForm, {
IProjectDraftForm,
Expand Down Expand Up @@ -86,6 +87,7 @@ const CreateProjectPage: React.FC = () => {

// Whether or not to show the 'Save as draft' dialog
const [openDraftDialog, setOpenDraftDialog] = useState(false);
const [openDeleteDraftDialog, setOpenDeleteDraftDialog] = useState(false);

const [draft, setDraft] = useState({ id: 0, date: '' });

Expand Down Expand Up @@ -114,6 +116,16 @@ const CreateProjectPage: React.FC = () => {
}
};

const showDeleteDraftErrorDialog = (textDialogProps?: Partial<IErrorDialogProps>) => {
dialogContext.setErrorDialog({
dialogTitle: DeleteProjectDraftI18N.draftErrorTitle,
dialogText: DeleteProjectDraftI18N.draftErrorText,
...defaultErrorDialogProps,
...textDialogProps,
open: true
});
};

const showDraftErrorDialog = (textDialogProps?: Partial<IErrorDialogProps>) => {
dialogContext.setErrorDialog({
dialogTitle: CreateProjectDraftI18N.draftErrorTitle,
Expand Down Expand Up @@ -196,7 +208,8 @@ const CreateProjectPage: React.FC = () => {

try {
await biohubApi.draft.deleteDraft(draftId);
} catch (error) {
} catch (error: any) {
showDeleteDraftErrorDialog({ dialogError: error });
return error;
}
};
Expand Down Expand Up @@ -248,6 +261,14 @@ const CreateProjectPage: React.FC = () => {
return true;
};

const handleDeleteDraft = async () => {
await deleteDraft();

setEnableCancelCheck(false);

history.push(`/admin/projects/`);
};

if (!codesDataLoader.data) {
return <CircularProgress className="pageProgress" size={40} />;
}
Expand All @@ -270,6 +291,15 @@ const CreateProjectPage: React.FC = () => {
onSave={(values) => handleSubmitDraft(values)}
/>

<YesNoDialog
dialogTitle="Delete Draft"
dialogText="Are you sure you want to delete this draft?"
open={openDeleteDraftDialog}
onClose={() => setOpenDeleteDraftDialog(false)}
onNo={() => setOpenDeleteDraftDialog(false)}
onYes={() => handleDeleteDraft()}
/>

<Container maxWidth="xl">
<Box py={5}>
<Box mb={3} display="flex" justifyContent="space-between" alignItems="flex-start">
Expand All @@ -288,6 +318,16 @@ const CreateProjectPage: React.FC = () => {
className={classes.actionButton}>
Save Draft
</Button>
{queryParams.draftId && (
<Button
color="primary"
size="large"
variant="outlined"
onClick={() => setOpenDeleteDraftDialog(true)}
className={classes.actionButton}>
Delete Draft
</Button>
)}
<Button
color="primary"
size="large"
Expand All @@ -311,6 +351,7 @@ const CreateProjectPage: React.FC = () => {
handleSubmit={createProject}
handleCancel={handleCancel}
handleDraft={setOpenDraftDialog}
handleDeleteDraft={setOpenDeleteDraftDialog}
codes={codesDataLoader.data}
formikRef={formikRef}
/>
Expand Down

0 comments on commit 0c75e56

Please sign in to comment.