Skip to content

Commit

Permalink
feat: project-page
Browse files Browse the repository at this point in the history
initial project page wip
  • Loading branch information
vuyaniShabangu committed Jul 22, 2024
1 parent 3a379af commit 1bd80e6
Show file tree
Hide file tree
Showing 9 changed files with 625 additions and 56 deletions.
215 changes: 215 additions & 0 deletions components/ProjectDetails/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
/*
*
* Copyright (c) 2022 The Ontario Institute for Cancer Research. All rights reserved
*
* This program and the accompanying materials are made available under the terms of
* the GNU Affero General Public License v3.0. You should have received a copy of the
* GNU Affero General Public License along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/

import React, { useState, useEffect } from 'react';
import { Card, Divider, Modal, Button, message } from 'antd';
import { useRouter } from 'next/router';
import { EditOutlined, DeleteOutlined, UserAddOutlined } from '@ant-design/icons';
import { Toaster } from 'react-hot-toast';

import { authorizedApiRequest } from '@/global/utils/api';
import { API_ROUTES_PATHS, HttpMethods, INTERNAL_PATHS } from '@/global/utils/constants';
import toast, { ToastType } from '@/global/utils/toast';

import useAuthContext from '../../global/hooks/useAuthContext';
import UpdateProject from '../ProjectUpdate';

const CardDivColumn: React.CSSProperties = {
display: 'flex',
justifyContent: 'space-between',
};

type Project = {
title?: string;
projectId?: string;
pathogen?: {
commonName?: string;
scientificName?: string;
};
description?: string;
owner?: string;
users?: [];
studyCount?: number;
};

type User = {
firstName: string;
lastName: string;
};

function convertToTableData(responseData: any): Project {
return {
title: responseData?.title,
projectId: responseData?.pid,
pathogen: {
commonName: '',
scientificName: '',
},
description: responseData?.description,
owner: responseData?.owner,
users: [],
studyCount: responseData?.study_count,
};
}
const ProjectDetails: React.FC = () => {
const [origin, setOrigin] = useState('');
const [loading, setLoading] = useState(true);
const [project, setProject] = useState<Project>();
const [id, setId] = useState('');
const [isGroupMember, setIsGroupMember] = useState<boolean>(false);
const [username, setUsername] = useState('');
const [isModalOpen, setIsModalOpen] = useState(false);

const { user } = useAuthContext();

useEffect(() => {
window && setOrigin(window.location.origin);
}, []);

const router = useRouter().query;
const projectId = router['project-id'];

useEffect(() => {
getProject();
if (typeof projectId === 'string') {
setId(projectId);
}
}, []);

const userIsGroupMember = (group?: string[], id?: string) => {
const response = group?.filter((proj) => proj === id).length != 0 ? true : false;
if (response) {
setIsGroupMember(true);
}
};

const getProject = () => {
const url = `${API_ROUTES_PATHS.PROJECTS}/${projectId}`;
if (projectId) {
authorizedApiRequest(HttpMethods.GET, url)
.then((data) => {
authorizedApiRequest(HttpMethods.GET, API_ROUTES_PATHS.USERS)
.then((datas) => {
const user: User = [...datas.users].filter((da) => da.id === data.owner)[0];
if (user) {
setUsername(`${user?.firstName.split('')[0]}. ${user?.lastName}`);
}
})
.catch((error) => console.log(error));
userIsGroupMember(user?.groups, data?.admin_group);
setProject(convertToTableData(data));
setLoading(false);
})
.catch((error) => {
console.log(error);
});
}
};

const actions: React.ReactNode[] = [
<>
<DeleteOutlined
key="ellipsis"
color="red"
onClick={() => showDeleteModal()}
style={{ color: 'red' }}
/>
<span onClick={() => showDeleteModal()} style={{ color: 'red' }}>
Delete
</span>
</>,
];

if (isGroupMember) {
actions.unshift(<UpdateProject id={id} refetchProject={getProject} />);
} else {
actions.unshift(
<>
<EditOutlined key="edit" />
<span>Edit</span>
</>,
);
}

const showDeleteModal = () => {
setIsModalOpen(true);
};

const handleDeleteConfirmation = () => {
authorizedApiRequest(HttpMethods.DELETE, `${API_ROUTES_PATHS.PROJECTS}/${id}`)
.then((data) => {
toast(ToastType.SUCCESS, 'Project successfully deleted');
setTimeout(() => {
location.href = INTERNAL_PATHS.PROJECTS;
}, 500);
})
.catch((error) => console.log(error));
};

const handleDeleteCancellation = () => {
setIsModalOpen(false);
};

return (
<>
<Toaster />
<Modal
title="Confirm Delete"
open={isModalOpen}
onOk={handleDeleteConfirmation}
onCancel={handleDeleteCancellation}
>
<p>Are you sure you want to delete?</p>
</Modal>
<Card
loading={loading}
actions={actions}
style={{ minWidth: 300, marginTop: '40px', width: '70%' }}
>
<Card.Meta
title={project?.title}
description={
<>
<div style={CardDivColumn}>
<span>Project ID</span>
<code>{project?.projectId}</code>
</div>
<div style={CardDivColumn}>
<span>Created by:</span>
<span>{username}</span>
</div>
<div style={CardDivColumn}>
<span>Description:</span>
<span style={{ textAlign: 'right', maxWidth: 600 }}>{project?.description} </span>
</div>
<Divider />
<Button type="primary" icon={<UserAddOutlined />} ghost>
Invite users to project
</Button>
</>
}
/>
</Card>
</>
);
};

export default ProjectDetails;
Loading

0 comments on commit 1bd80e6

Please sign in to comment.