-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
task/WG-237-Delete-Project-Modal-React (#273)
* task/WG-237-Delete-Project-Modal-React * - Linting * - Fix frontend tests * - Fixing unit tests * - Addresses commented suggestions and requested changes * - Updated more requested changes * - More updates and linting * - Added key to table rows with onClick * - Linting * - Addresses accesibility erros with table row links * - Updated changes * - Fixes unit tests - only tests UI
- Loading branch information
1 parent
25f88db
commit f5767b2
Showing
8 changed files
with
407 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
import { | ||
Project, | ||
DesignSafeProject, | ||
DesignSafeProjectCollection, | ||
ProjectRequest, | ||
} from '../types'; | ||
|
||
export const projectMock: Project = { | ||
id: 1, | ||
uuid: 'abc123', | ||
name: 'Sample Project', | ||
description: 'A sample project for testing purposes.', | ||
public: true, | ||
system_file: 'sample-file', | ||
system_id: 'sample-id', | ||
system_path: '/path/to/sample', | ||
deletable: true, | ||
streetview_instances: null, | ||
ds_project: { | ||
uuid: 'proj-uuid', | ||
projectId: 'proj-id', | ||
title: 'Sample DesignSafe Project', | ||
value: { | ||
dois: [], | ||
coPis: [], | ||
title: 'Hazmapper V3 PROD Map Test 2024.08.07', | ||
users: [ | ||
{ | ||
inst: 'University of Texas at Austin (utexas.edu)', | ||
role: 'pi', | ||
email: '[email protected]', | ||
fname: 'Fixture First Name', | ||
lname: 'Fixture Last Name', | ||
username: 'fixture1Username', | ||
}, | ||
{ | ||
inst: 'University of Texas at Austin (utexas.edu)', | ||
role: 'co_pi', | ||
email: '[email protected]', | ||
fname: 'Tester', | ||
lname: 'Test', | ||
username: 'fixture2Username', | ||
}, | ||
], | ||
authors: [], | ||
frTypes: [], | ||
nhEvent: '', | ||
nhTypes: [], | ||
fileObjs: [], | ||
fileTags: [], | ||
keywords: [], | ||
nhEvents: [], | ||
dataTypes: [], | ||
projectId: 'PRJ-5566', | ||
tombstone: false, | ||
facilities: [], | ||
nhLatitude: '', | ||
nhLocation: '', | ||
description: 'Map Test description required.', | ||
nhLongitude: '', | ||
projectType: 'None', | ||
teamMembers: [], | ||
awardNumbers: [], | ||
guestMembers: [], | ||
hazmapperMaps: [ | ||
{ | ||
name: 'Hazmapper_TestProject', | ||
path: '/', | ||
uuid: '620aeaf4-f813-4b90-ba52-bc87cfa7b07b', | ||
deployment: 'production', | ||
}, | ||
], | ||
referencedData: [], | ||
associatedProjects: [], | ||
}, | ||
}, | ||
}; | ||
|
||
export const designSafeProjectMock: DesignSafeProject = { | ||
uuid: 'proj-uuid', | ||
projectId: 'proj-id', | ||
title: 'Sample DesignSafe Project', | ||
value: {}, | ||
}; | ||
|
||
export const designSafeProjectCollectionMock: DesignSafeProjectCollection = { | ||
result: [designSafeProjectMock], | ||
}; | ||
|
||
export const projectRequestMock: ProjectRequest = { | ||
name: 'New Project Request', | ||
description: 'A description for the new project request.', | ||
public: true, | ||
system_file: 'new-project-file', | ||
system_id: 'new-system-id', | ||
system_path: '/path/to/new-project', | ||
watch_content: true, | ||
watch_users: false, | ||
}; |
133 changes: 133 additions & 0 deletions
133
react/src/components/DeleteMapModal/DeleteMapModal.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
import React from 'react'; | ||
import { render, screen } from '@testing-library/react'; | ||
import { BrowserRouter as Router } from 'react-router-dom'; | ||
import { act } from 'react-dom/test-utils'; | ||
import { QueryClient, QueryClientProvider } from 'react-query'; | ||
import DeleteMapModal from './DeleteMapModal'; | ||
import { Provider } from 'react-redux'; | ||
import store from '../../redux/store'; | ||
import { projectMock } from '../../__fixtures__/projectFixtures'; | ||
import { Project } from '../../types'; | ||
import { useDeleteProject } from '../../hooks/projects'; | ||
|
||
jest.mock('../../hooks/projects', () => ({ | ||
useDeleteProject: jest.fn(), | ||
})); | ||
|
||
const mockHookReturn = { | ||
mutate: jest.fn(), | ||
isLoading: false, | ||
isError: false, | ||
isSuccess: false, | ||
}; | ||
|
||
const nonDeletableProjectMock: Project = { | ||
...projectMock, | ||
deletable: false, | ||
name: 'Non-Deletable Project', | ||
}; | ||
|
||
const publicProjectMock: Project = { | ||
...projectMock, | ||
public: true, | ||
name: 'Public Project', | ||
}; | ||
|
||
const toggleMock = jest.fn(); | ||
const queryClient = new QueryClient(); | ||
|
||
const renderComponent = async (projectData: Project = projectMock) => { | ||
await act(async () => { | ||
render( | ||
<Provider store={store}> | ||
<QueryClientProvider client={queryClient}> | ||
<Router> | ||
<DeleteMapModal | ||
isOpen={true} | ||
close={toggleMock} | ||
project={projectData} | ||
/> | ||
</Router> | ||
</QueryClientProvider> | ||
</Provider> | ||
); | ||
}); | ||
}; | ||
|
||
describe('DeleteMapModal', () => { | ||
beforeEach(() => { | ||
jest.clearAllMocks(); | ||
(useDeleteProject as jest.Mock).mockReturnValue(mockHookReturn); | ||
}); | ||
|
||
describe('DeleteMapModal', () => { | ||
beforeEach(() => { | ||
jest.clearAllMocks(); | ||
(useDeleteProject as jest.Mock).mockReturnValue(mockHookReturn); | ||
}); | ||
|
||
it('should display the modal with correct project name', async () => { | ||
await renderComponent(); | ||
const titleElement = screen.getByText(`Delete Map: ${projectMock.name}`); | ||
expect(titleElement).toBeDefined(); | ||
}); | ||
|
||
it('should show delete confirmation message for deletable projects', async () => { | ||
await renderComponent(); | ||
const confirmMessage = screen.getByText( | ||
/Are you sure you want to delete this map?/ | ||
); | ||
const warningMessage = screen.getByText(/This cannot be undone./); | ||
expect(confirmMessage).toBeDefined(); | ||
expect(warningMessage).toBeDefined(); | ||
}); | ||
|
||
it('should show permission denied message for non-deletable projects', async () => { | ||
await renderComponent(nonDeletableProjectMock); | ||
const deniedMessage = screen.getByText('permission to delete this map', { | ||
exact: false, | ||
}); | ||
expect(deniedMessage).toBeDefined(); | ||
}); | ||
|
||
it('should disable delete button for non-deletable projects', async () => { | ||
await renderComponent(nonDeletableProjectMock); | ||
const deleteButton = screen.getByText('Delete') as HTMLButtonElement; | ||
expect(deleteButton.disabled).toBe(true); | ||
}); | ||
|
||
it('should enable delete button for deletable projects', async () => { | ||
await renderComponent(); | ||
const deleteButton = screen.getByText('Delete') as HTMLButtonElement; | ||
expect(deleteButton.disabled).toBe(false); | ||
}); | ||
|
||
it('should show additional warning for public projects', async () => { | ||
await renderComponent(publicProjectMock); | ||
const publicWarning = screen.getByText(/Note that this is a public map./); | ||
expect(publicWarning).toBeDefined(); | ||
}); | ||
|
||
it('should show error message when isError is true', async () => { | ||
(useDeleteProject as jest.Mock).mockReturnValue({ | ||
...mockHookReturn, | ||
isError: true, | ||
}); | ||
await renderComponent(); | ||
const errorMessage = screen.getByText( | ||
'There was an error deleting your map.' | ||
); | ||
expect(errorMessage).toBeDefined(); | ||
}); | ||
|
||
it('should show success message when isSuccess is true', async () => { | ||
(useDeleteProject as jest.Mock).mockReturnValue({ | ||
...mockHookReturn, | ||
isSuccess: true, | ||
}); | ||
await renderComponent(); | ||
const successMessage = screen.getByText('Succesfully deleted the map.'); | ||
expect(successMessage).toBeDefined(); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
import React from 'react'; | ||
import { Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap'; | ||
import { Button, SectionMessage } from '@tacc/core-components'; | ||
import { Project } from '../../types'; | ||
import { useDeleteProject } from '../../hooks/projects/'; | ||
|
||
type DeleteMapModalProps = { | ||
isOpen: boolean; | ||
close: () => void; | ||
project: Project; | ||
}; | ||
|
||
const DeleteMapModal = ({ | ||
isOpen, | ||
close: parentToggle, | ||
project, | ||
}: DeleteMapModalProps) => { | ||
const { | ||
mutate: deleteProject, | ||
isLoading: isDeletingProject, | ||
isError, | ||
isSuccess, | ||
} = useDeleteProject(project.id); | ||
const handleClose = () => { | ||
parentToggle(); | ||
}; | ||
|
||
const handleDeleteProject = () => { | ||
deleteProject(undefined, {}); | ||
}; | ||
|
||
return ( | ||
<Modal size="lg" isOpen={isOpen} toggle={handleClose}> | ||
<ModalHeader toggle={handleClose}> | ||
Delete Map: {project?.name}{' '} | ||
</ModalHeader> | ||
<ModalBody> | ||
{project?.deletable ? ( | ||
<> | ||
Are you sure you want to delete this map? All associated features, | ||
metadata, and saved files will be deleted. | ||
{project?.public && <b> Note that this is a public map. </b>} | ||
<br /> | ||
<b> | ||
<u>This cannot be undone.</u> | ||
</b> | ||
</> | ||
) : ( | ||
'You don’t have permission to delete this map.' | ||
)} | ||
</ModalBody> | ||
<ModalFooter className="justify-content-start"> | ||
<Button size="short" type="secondary" onClick={handleClose}> | ||
{isSuccess ? 'Close' : 'Cancel'} | ||
</Button> | ||
<Button | ||
size="short" | ||
type="primary" | ||
attr="submit" | ||
isLoading={isDeletingProject} | ||
onClick={handleDeleteProject} | ||
disabled={isSuccess || !project?.deletable} | ||
> | ||
Delete | ||
</Button> | ||
{isSuccess && ( | ||
<SectionMessage type="success"> | ||
{'Succesfully deleted the map.'} | ||
</SectionMessage> | ||
)} | ||
{isError && ( | ||
<SectionMessage type="error"> | ||
{'There was an error deleting your map.'} | ||
</SectionMessage> | ||
)} | ||
</ModalFooter> | ||
</Modal> | ||
); | ||
}; | ||
|
||
export default DeleteMapModal; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
export { | ||
useDeleteProject, | ||
useProjectsWithDesignSafeInformation, | ||
useProjects, | ||
useDsProjects, | ||
|
Oops, something went wrong.