-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'task/digital-rocks' into task/WC-166--sort-pub-requests
- Loading branch information
Showing
24 changed files
with
473 additions
and
79 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
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
251 changes: 251 additions & 0 deletions
251
...ponents/_custom/drp/DataFilesManageProjectModalAddon/DataFilesManageProjectModalAddon.jsx
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,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; |
45 changes: 45 additions & 0 deletions
45
..._custom/drp/DataFilesManageProjectModalAddon/DataFilesManageProjectModalAddon.module.scss
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,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; | ||
} |
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
Oops, something went wrong.