Skip to content

Commit

Permalink
Merge branch 'task/digital-rocks' into task/WC-148--prj-ownership-cha…
Browse files Browse the repository at this point in the history
…nge-toast
  • Loading branch information
shayanaijaz authored Dec 4, 2024
2 parents fc04bc8 + dcc3967 commit 4777b60
Show file tree
Hide file tree
Showing 13 changed files with 388 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Button, Message } from '_common';
import { Modal, ModalHeader, ModalBody } from 'reactstrap';
import DataFilesProjectMembers from '../DataFilesProjectMembers/DataFilesProjectMembers';
import styles from './DataFilesManageProject.module.scss';
import { useAddonComponents } from 'hooks/datafiles';

const DataFilesManageProjectModal = () => {
const dispatch = useDispatch();
Expand Down Expand Up @@ -40,6 +41,12 @@ const DataFilesManageProjectModal = () => {
return projectSystem?.readOnly || !canEditSystem;
});

const portalName = useSelector((state) => state.workbench.portalName);

const { DataFilesManageProjectModalAddon } = useAddonComponents({
portalName,
});

const toggle = useCallback(() => {
setTransferMode(false);
dispatch({
Expand Down Expand Up @@ -154,6 +161,9 @@ const DataFilesManageProjectModal = () => {
</Button>
) : null}
</div>
{DataFilesManageProjectModalAddon && (
<DataFilesManageProjectModalAddon projectId={projectId} />
)}
</ModalBody>
</Modal>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ const DataFilesProjectEditDescriptionModal = () => {
description: values.description || '',
metadata: DataFilesProjectEditDescriptionModalAddon ? values : null,
},
modal: 'editproject',
},
});
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
import React, { useState, useCallback, useEffect, useMemo } from 'react';
import * as Yup from 'yup';
import styles from './DataFilesManageProjectModalAddon.module.scss';
import { useDispatch, useSelector } from 'react-redux';
import { useSystemRole } from '../../../DataFiles/DataFilesProjectMembers/_cells/SystemRoleSelector';
import { Input, Label } from 'reactstrap';
import { FieldArray, Form, Formik, useFormikContext } from 'formik';
import {
Button,
FormField,
InfiniteScrollTable,
LoadingSpinner,
Section,
} from '_common';

const DataFilesManageProjectModalAddon = ({ projectId }) => {
const dispatch = useDispatch();

const { metadata } = useSelector((state) => state.projects);

const { loading, error } = useSelector((state) => {
if (
state.projects.operation &&
state.projects.operation.name === 'titleDescription'
) {
return state.projects.operation;
}
return {
loading: false,
error: false,
};
});

const authenticatedUser = useSelector(
(state) => state.authenticatedUser.user.username
);

const { query: authenticatedUserQuery } = useSystemRole(
projectId ?? null,
authenticatedUser ?? null
);

const canEditSystem = ['OWNER', 'ADMIN'].includes(
authenticatedUserQuery?.data?.role
);

const readOnlyTeam = useSelector((state) => {
const projectSystem = state.systems.storage.configuration.find(
(s) => s.scheme === 'projects'
);

return projectSystem?.readOnly || !canEditSystem;
});

const handleRemoveGuestUser = useCallback(
(email) => {
const updatedGuestUsers = metadata.guest_users.filter(
(user) => user.email !== email
);

dispatch({
type: 'PROJECTS_SET_TITLE_DESCRIPTION',
payload: {
projectId,
data: {
title: metadata.title,
description: metadata.description || '',
metadata: {
guest_users: updatedGuestUsers,
},
},
modal: '',
},
});
},
[metadata, dispatch, projectId] // Dependency array
);

const columns = [
{
Header: 'Guest Members',
accessor: (el) => el,
Cell: (el) => {
const { first_name, last_name, email } = el.value;
return (
<span>
<span
className={styles['printed-name']}
>{`${first_name} ${last_name}`}</span>
{` (${email})`}
</span>
);
},
},
{
Header: loading ? (
<LoadingSpinner
placement="inline"
className={styles['guest-members__loading']}
/>
) : (
''
),
accessor: 'email',
Cell: (el) => {
return !readOnlyTeam ? (
<Button
type="link"
onClick={() => handleRemoveGuestUser(el.value)}
disabled={loading}
>
Remove
</Button>
) : null;
},
},
];

const onSubmit = useCallback(
(values) => {
dispatch({
type: 'PROJECTS_SET_TITLE_DESCRIPTION',
payload: {
projectId,
data: {
title: metadata.title,
description: metadata.description || '',
metadata: {
guest_users: [...metadata.guest_users, ...values.guestUsers],
},
},
modal: '',
},
});
},
[projectId, dispatch, metadata]
);

const validationSchema = Yup.object().shape({
guestUsers: Yup.array().of(
Yup.object().shape({
first_name: Yup.string().required('First Name is required'),
last_name: Yup.string().required('Last Name is required'),
email: Yup.string()
.email('Invalid email address')
.required('Email is required'),
})
),
});

return (
<div className={styles.root}>
{metadata?.guest_users?.length > 0 && (
<InfiniteScrollTable
tableColumns={columns}
tableData={metadata.guest_users}
className={styles['guest-user-listing']}
columnMemoProps={[loading]}
/>
)}

{!readOnlyTeam && (
<>
<Label className="form-field__label" size="sm">
Add Guest Member
</Label>
<Formik
initialValues={{ guestUsers: [] }}
validationSchema={validationSchema}
onSubmit={onSubmit}
>
{({ values, isValid, resetForm }) => {
useEffect(() => {
resetForm();
}, [metadata, resetForm]);

return (
<Form>
<FieldArray name="guestUsers">
{({ remove, push }) => (
<>
{/* Render only if there are guest users */}
{values.guestUsers.length > 0 &&
values.guestUsers.map((_, index) => (
<Section
key={index}
contentClassName={`${styles['form-div']}`}
content={
<>
<FormField
name={`guestUsers.${index}.first_name`}
label="First Name"
required
/>
<FormField
name={`guestUsers.${index}.last_name`}
label="Last Name"
required
/>
<FormField
name={`guestUsers.${index}.email`}
label="Email"
required
/>
<Button
type="primary"
attr="submit"
className={styles['remove-button']}
isLoading={loading}
disabled={!isValid}
>
Add
</Button>
<Button
type="secondary"
onClick={() => remove(index)}
className={styles['remove-button']}
disabled={loading}
>
Remove
</Button>
</>
}
/>
))}

{/* Button to add a new guest user */}
<Button
type="secondary"
onClick={() =>
push({ first_name: '', last_name: '', email: '' })
}
iconNameBefore="add"
className={styles['button-full']}
>
Add Guest Member
</Button>
</>
)}
</FieldArray>
</Form>
);
}}
</Formik>
</>
)}
</div>
);
};

export default DataFilesManageProjectModalAddon;
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
.form-div {
display: flex;
justify-content: space-between;
width: 100%;
// align-items: center;
}

.form-div > *:not(:nth-last-child(-n + 2)) {
width: 25%;
margin-bottom: 50px;
}

.remove-button {
align-self: center;
margin-bottom: 15px;
}

.button-full {
min-width: 100% !important;
margin-bottom: 30px;
}

.printed-name {
font-weight: bold;
}

.guest-user-listing {
/* title */
th:nth-child(1),
td:nth-child(1) {
width: 80%;
}
/* date */
th:nth-child(2),
td:nth-child(2) {
width: 20%;
}

padding-bottom: 10px;
}

.guest-members__loading {
font-size: 1em;
justify-content: flex-end;
}
Loading

0 comments on commit 4777b60

Please sign in to comment.