Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Task/wg 243 manage project #313

Merged
merged 23 commits into from
Feb 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
6144687
Use large panel for map project instead of modal
nathanfranklin Jan 27, 2025
a0d7cef
task/WG-243-manage-project
sophia-massie Jan 31, 2025
b5ab7c7
Merge branch 'main' into task/wg-243-manage-project
sophia-massie Jan 31, 2025
36e2d80
- Adds taggit button to Map tab
sophia-massie Feb 3, 2025
c35db81
- Adds all tabs, notifications for success,
sophia-massie Feb 4, 2025
b9bbe89
- adds key to table rows
sophia-massie Feb 4, 2025
7f9f22d
- Disables trash on project listing if not deletable
sophia-massie Feb 4, 2025
68a159a
- Adds test for manage ManageMapProjectPanel
sophia-massie Feb 4, 2025
dfcf9f7
Merge branch 'main' into task/WG-243-manage-project
sophia-massie Feb 5, 2025
d76d998
- After merging main, MapProject had this
sophia-massie Feb 5, 2025
e1d0cea
Merge branch 'task/WG-243-manage-project' of github.com:TACC-Cloud/ha…
sophia-massie Feb 5, 2025
58fa2e6
- Adds option to hook prevent showing members if
sophia-massie Feb 5, 2025
1b9948a
- Fixes hook to include projectID
sophia-massie Feb 5, 2025
bbc64db
Update react/src/hooks/projects/useProjects.ts
sophia-massie Feb 6, 2025
e4bdef9
Merge branch 'main' into task/WG-243-manage-project
sophia-massie Feb 7, 2025
287bd45
- Addresses requested changes
sophia-massie Feb 7, 2025
2ccb20c
Merge branch 'main' into task/WG-243-manage-project
sophia-massie Feb 11, 2025
3c579e3
Merge branch 'main' into task/WG-243-manage-project
rstijerina Feb 11, 2025
0a5b195
- Adds better state handling when deleting a project
sophia-massie Feb 11, 2025
72e91ad
Merge remote-tracking branch 'origin/task/WG-243-manage-project' into…
sophia-massie Feb 11, 2025
fbe0f42
- Adds suggested patch
sophia-massie Feb 12, 2025
961fa86
- Moves notifications to bottom left like DS
sophia-massie Feb 12, 2025
958388b
Change replacement approach (#319)
nathanfranklin Feb 12, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 0 additions & 10 deletions react/src/components/DeleteMapModal/DeleteMapModal.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,15 +118,5 @@ describe('DeleteMapModal', () => {
);
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();
});
});
});
31 changes: 25 additions & 6 deletions react/src/components/DeleteMapModal/DeleteMapModal.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import { Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap';
import { Button, SectionMessage } from '@tacc/core-components';
import { useNavigate, useLocation } from 'react-router-dom';
import { Project } from '../../types';
import { useDeleteProject } from '../../hooks/projects/';

Expand All @@ -15,18 +16,41 @@ const DeleteMapModal = ({
close: parentToggle,
project,
}: DeleteMapModalProps) => {
const navigate = useNavigate();
const location = useLocation();
const {
mutate: deleteProject,
isPending: isDeletingProject,
isError,
isSuccess,
} = useDeleteProject();

sophia-massie marked this conversation as resolved.
Show resolved Hide resolved
const handleClose = () => {
parentToggle();
};

const handleDeleteProject = () => {
deleteProject({ projectId: project.id });
deleteProject(
{ projectId: project.id },
{
onSuccess: () => {
parentToggle();
if (location.pathname.includes(`/project/${project.uuid}`)) {
// If on project page, navigate home with success state
navigate('/', {
replace: true,
state: { onSuccess: true },
});
} else {
// If not on project page, just navigate to current location with success state
navigate(location, {
replace: true,
state: { onSuccess: true },
});
}
},
}
);
};

return (
Expand Down Expand Up @@ -63,11 +87,6 @@ const DeleteMapModal = ({
>
Delete
</Button>
{isSuccess && (
<SectionMessage type="success">
{'Succesfully deleted the map.'}
</SectionMessage>
)}
{isError && (
<SectionMessage type="error">
{'There was an error deleting your map.'}
Expand Down

This file was deleted.

1 change: 0 additions & 1 deletion react/src/components/ManageMapProjectModal/index.tsx

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import React from 'react';
import { screen, fireEvent } from '@testing-library/react';
import ManageMapProjectPanel from './ManageMapProjectPanel';
import { projectMock } from '@hazmapper/__fixtures__/projectFixtures';
import { renderInTest, testQueryClient } from '@hazmapper/test/testUtil';

// Mock the child components
jest.mock('./MapTabContent', () => {
return function MockMapTabContent() {
return <div data-testid="map-tab-content">Map Tab Content</div>;
};
});

jest.mock('./MembersTabContent', () => {
return function MockMembersTabContent() {
return <div data-testid="members-tab-content">Members Tab Content</div>;
};
});

jest.mock('./PublicTabContent', () => {
return function MockPublicTabContent() {
return <div data-testid="public-tab-content">Public Tab Content</div>;
};
});

jest.mock('./SaveTabContent', () => {
return function MockSaveTabContent() {
return <div data-testid="save-tab-content">Save Tab Content</div>;
};
});

describe('ManageMapProjectPanel', () => {
const defaultProps = {
project: projectMock,
onProjectUpdate: jest.fn(),
};

beforeEach(() => {
jest.clearAllMocks();
testQueryClient.clear();
});

it('renders all tab buttons', () => {
renderInTest(<ManageMapProjectPanel {...defaultProps} />);

expect(screen.getByRole('tab', { name: 'Map' })).toBeTruthy();
expect(screen.getByRole('tab', { name: 'Members' })).toBeTruthy();
expect(screen.getByRole('tab', { name: 'Public' })).toBeTruthy();
expect(screen.getByRole('tab', { name: 'Save' })).toBeTruthy();
});

it('renders map tab content by default', () => {
renderInTest(<ManageMapProjectPanel {...defaultProps} />);

expect(screen.getByTestId('map-tab-content')).toBeTruthy();
});
it('switches between tabs correctly', () => {
renderInTest(<ManageMapProjectPanel {...defaultProps} />);

// Click Members tab
const membersTab = screen.getByRole('tab', { name: 'Members' });
fireEvent.click(membersTab);
expect(screen.getByTestId('members-tab-content')).toBeTruthy();

// Click Public tab
const publicTab = screen.getByRole('tab', { name: 'Public' });
fireEvent.click(publicTab);
expect(screen.getByTestId('public-tab-content')).toBeTruthy();

// Click Save tab
const saveTab = screen.getByRole('tab', { name: 'Save' });
fireEvent.click(saveTab);
expect(screen.getByTestId('save-tab-content')).toBeTruthy();
});
});
115 changes: 115 additions & 0 deletions react/src/components/ManageMapProjectPanel/ManageMapProjectPanel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import React, { useState } from 'react';
import styles from './ManageMapProjectPanel.module.css';
import type { TabsProps } from 'antd';
import { Flex, Tabs, notification, Card } from 'antd';
import { Project, ProjectRequest } from '@hazmapper/types';
import MapTabContent from './MapTabContent';
import MembersTabContent from './MembersTabContent';
import PublicTabContent from './PublicTabContent';
import { useUpdateProjectInfo } from '@hazmapper/hooks';
import SaveTabContent from './SaveTabContent';

interface ManageMapProjectModalProps {
project: Project;
}

const ManageMapProjectPanel: React.FC<ManageMapProjectModalProps> = ({
project: activeProject,
}) => {
const [activeKey, setActiveKey] = useState('1');
const [updateApi, contextHolder] = notification.useNotification();

const { mutate, isPending } = useUpdateProjectInfo();

const handleProjectUpdate = (updateData: Partial<ProjectRequest>) => {
const newData: ProjectRequest = {
name: updateData.name ?? activeProject.name,
description: updateData.description ?? activeProject.description,
public: updateData.public ?? activeProject.public,
};

mutate(newData, {
onSuccess: () => {
updateApi.open({
type: 'success',
message: 'Success!',
description: 'Your project was successfully updated.',
placement: 'bottomLeft',
closable: false,
});
},
onError: () => {
updateApi.open({
type: 'error',
message: 'Error!',
description: 'There was an error updating your project.',
placement: 'bottomLeft',
closable: false,
});
},
});
};

const items: TabsProps['items'] = [
{
label: 'Map',
key: '1',
children: (
<Card title="Map Details" type="inner">
<MapTabContent
project={activeProject}
onProjectUpdate={handleProjectUpdate}
isPending={isPending}
/>
</Card>
),
},
{
label: 'Members',
key: '2',
children: (
<Card title="Members" type="inner">
<MembersTabContent project={activeProject} />
</Card>
),
},
{
label: 'Public',
key: '3',
children: (
<Card type="inner" title="Public Access">
<PublicTabContent
project={activeProject}
onProjectUpdate={handleProjectUpdate}
isPending={isPending}
/>
</Card>
),
},
{
label: 'Save',
key: '4',
children: (
<Card type="inner" title="Save Location">
<SaveTabContent project={activeProject}></SaveTabContent>
</Card>
),
},
];

return (
<Flex vertical className={styles.root}>
{contextHolder}
<Tabs
type="card"
size="small"
activeKey={activeKey}
onChange={setActiveKey}
items={items}
style={{ marginTop: 20, marginLeft: 30, marginRight: 30 }}
/>
</Flex>
);
};

export default ManageMapProjectPanel;
Loading
Loading