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

Swathi - Add Project Name to Projects>Members Pages #3032

Open
wants to merge 4 commits into
base: development
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
44 changes: 23 additions & 21 deletions src/components/Projects/Members/Members.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,15 @@ import { boxStyle, boxStyleDark } from 'styles';
import ToggleSwitch from 'components/UserProfile/UserProfileEdit/ToggleSwitch';
import Loading from 'components/common/Loading';


const Members = props => {
const darkMode = props.state.theme.darkMode;

const projectId = props.match.params.projectId;

// Get the project name from props or sessionStorage
const projectName = props.location.state && props.location.state.projectName
? props.location.state.projectName
: sessionStorage.getItem('projectName') || 'Unknown Project';

const [showFindUserList, setShowFindUserList] = useState(false);
const [membersList, setMembersList] = useState(props.state.projectMembers.members);
const [lastTimeoutId, setLastTimeoutId] = useState(null);
Expand All @@ -45,9 +49,8 @@ const Members = props => {
}, [projectId]);

const assignAll = async () => {
const allUsers = props.state.projectMembers.foundUsers.filter(user => user.assigned === false);
const allUsers = props.state.projectMembers.foundUsers.filter(user => !user.assigned);

// Wait for all members to be assigned
await Promise.all(
allUsers.map(user =>
props.assignProject(projectId, user._id, 'Assign', user.firstName, user.lastName),
Expand All @@ -63,7 +66,6 @@ const Members = props => {
}
}, [props.state.projectMembers.members, isLoading]);

// ADDED: State for toggling display of active members only
const [showActiveMembersOnly, setShowActiveMembersOnly] = useState(false);

const displayedMembers = showActiveMembersOnly
Expand All @@ -76,7 +78,6 @@ const Members = props => {
setMembersList(props.state.projectMembers.members);
};

// Waits for user to finsh typing before calling API
const handleInputChange = event => {
const currentValue = event.target.value;

Expand All @@ -92,7 +93,7 @@ const Members = props => {

return (
<React.Fragment>
<div className={darkMode ? 'bg-oxford-blue text-light' : ''} style={{minHeight: "100%"}}>
<div className={darkMode ? 'bg-oxford-blue text-light' : ''} style={{ minHeight: "100%" }}>
<div className="container pt-2">
<nav aria-label="breadcrumb">
<ol className={`breadcrumb ${darkMode ? 'bg-space-cadet' : ''}`} style={darkMode ? boxStyleDark : boxStyle}>
Expand All @@ -102,9 +103,11 @@ const Members = props => {
</button>
</NavItem>

<div id="member_project__name">PROJECTS {props.projectId}</div>
{/* Display Project Name */}
<div id="member_project__name">PROJECT: {projectName}</div>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was wondering, both the member's page and the WBS page have a project header. Do you think it might be helpful to make it a shared component, or is there a specific reason for keeping them separate?

</ol>
</nav>

{canAssignProjectToUsers ? (
<div className="input-group" id="new_project">
<div className="input-group-prepend">
Expand All @@ -124,7 +127,7 @@ const Members = props => {
<button
className="btn btn-outline-primary"
type="button"
onClick={e => {
onClick={() => {
props.getAllUserProfiles();
setShowFindUserList(true);
}}
Expand All @@ -135,7 +138,7 @@ const Members = props => {
<button
className="btn btn-outline-danger"
type="button"
onClick={() => setShowFindUserList(false)} // Hide the find user list
onClick={() => setShowFindUserList(false)}
>
Cancel
</button>
Expand All @@ -147,9 +150,7 @@ const Members = props => {
<table className={`table table-bordered table-responsive-sm ${darkMode ? 'text-light' : ''}`}>
<thead>
<tr className={darkMode ? 'bg-space-cadet' : ''}>
<th scope="col" id="foundUsers__order">
#
</th>
<th scope="col" id="foundUsers__order">#</th>
<th scope="col">Name</th>
<th scope="col">Email</th>
{canAssignProjectToUsers ? (
Expand Down Expand Up @@ -191,15 +192,15 @@ const Members = props => {
handleUserProfile={handleToggle}
/>

{isLoading ? ( <Loading align="center" /> ) : (
{isLoading ? (
<Loading align="center" />
) : (
<table className={`table table-bordered table-responsive-sm ${darkMode ? 'text-light' : ''}`}>
<thead>
<tr className={darkMode ? 'bg-space-cadet' : ''}>
<th scope="col" id="members__order">
#
</th>
<th scope="col" id="members__name"></th>
{canUnassignUserInProject ? <th scope="col" id="members__name"></th> : null}
<th scope="col" id="members__order">#</th>
<th scope="col" id="members__name">Name</th>
{canUnassignUserInProject ? <th scope="col" id="members__action">Action</th> : null}
</tr>
</thead>
<tbody>
Expand All @@ -209,12 +210,12 @@ const Members = props => {
key={member._id ?? i}
projectId={projectId}
uid={member._id}
fullName={member.firstName + ' ' + member.lastName}
fullName={`${member.firstName} ${member.lastName}`}
darkMode={darkMode}
/>
))}
</tbody>
</table>
</table>
)}
</div>
</div>
Expand All @@ -225,6 +226,7 @@ const Members = props => {
const mapStateToProps = state => {
return { state };
};

export default connect(mapStateToProps, {
fetchAllMembers,
findUserProfiles,
Expand Down
144 changes: 47 additions & 97 deletions src/components/Projects/Project/Project.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,137 +7,89 @@ import { connect } from 'react-redux';
import hasPermission from 'utils/permissions';
import { boxStyle } from 'styles';
import { toast } from 'react-toastify';
import { modifyProject, clearError } from '../../../actions/projects';
import ModalTemplate from './../../common/Modal';
import { CONFIRM_ARCHIVE } from './../../../languages/en/messages';

const Project = props => {
const Project = (props) => {
const { darkMode, index } = props;
const [firstLoad, setFirstLoad] = useState(true);
const [projectData, setProjectData] = useState(props.projectData);
const { projectName, isActive,isArchived, _id: projectId } = projectData;
const { projectName, isActive, _id: projectId } = projectData;
const [displayName, setDisplayName] = useState(projectName);
const initialModalData = {
showModal: false,
modalMessage: "",
modalTitle: "",
hasConfirmBtn: false,
hasInactiveBtn: false,
};

const [modalData, setModalData] = useState(initialModalData);

const onCloseModal = () => {
setModalData(initialModalData);
props.clearError();
}; const [category, setCategory] = useState(props.category || 'Unspecified'); // Initialize with props or default
const [category, setCategory] = useState(props.category || 'Unspecified');

const canPutProject = props.hasPermission('putProject');
const canDeleteProject = props.hasPermission('deleteProject');

const canSeeProjectManagementFullFunctionality = props.hasPermission('seeProjectManagement');
const canEditCategoryAndStatus = props.hasPermission('editProject');

const updateProject = ({ updatedProject, status }) => async dispatch => {
try {
dispatch(updateProject({ updatedProject, status }));
} catch (err) {
const status = err?.response?.status || 500;
const error = err?.response?.data || { message: 'An error occurred' };
dispatch(updateProject({ status, error }));
}
const updateProject = (key, value) => {
setProjectData({
...projectData,
[key]: value,
});
};

const onDisplayNameChange = (e) => {
setDisplayName(e.target.value);
}
};

const onUpdateProjectName = () => {
if (displayName.length < 3) {
toast.error('Project name must be at least 3 characters long');
setDisplayName(displayName);
} else if (displayName !== projectName) {
updateProject('projectName', displayName);
}
}
};

const onUpdateProjectActive = () => {
updateProject('isActive', !isActive);
}
};

const onUpdateProjectCategory = (e) => {
setCategory(e.target.value);
updateProject('category', e.target.value); // Update the projectData state
updateProject('category', e.target.value);
};

const onArchiveProject = () => {
setModalData({
showModal: true,
modalMessage: `<p>Do you want to archive ${projectData.projectName}?</p>`,
modalTitle: CONFIRM_ARCHIVE,
hasConfirmBtn: true,
hasInactiveBtn: isActive,
});
}

const setProjectInactive = () => {
updateProject('isActive', !isActive);
onCloseModal();
}
const confirmArchive = () => {
updateProject('isArchived', !isArchived);
props.onProjectArchived();
onCloseModal();
props.onClickArchiveBtn(projectData);
};

useEffect(() => {
const onUpdateProject = async () => {
if (firstLoad) {
setFirstLoad(false);
} else {
await props.modifyProject(projectData);
}
};

onUpdateProject();
if (firstLoad) {
setFirstLoad(false);
} else {
props.onUpdateProject(projectData);
}
if (props.projectData.category) {
setCategory(props.projectData.category);
}
}, [projectData]);

return (
<>
<tr className="projects__tr" id={'tr_' + props.projectId}>

<th className="projects__order--input" scope="row">
<div className={darkMode ? 'text-light' : ''}>{index + 1}</div>
</th>


<td data-testid="projects__name--input" className="projects__name--input">
{(canPutProject || canSeeProjectManagementFullFunctionality) ? (


{canPutProject || canSeeProjectManagementFullFunctionality ? (
<input
type="text"
className={`form-control ${darkMode ? 'bg-yinmn-blue border-0 text-light' : ''}`}
value={displayName}
onChange={onDisplayNameChange}
onBlur={() => onUpdateProjectName(displayName)}
onBlur={onUpdateProjectName}
/>
) : (
projectName
)}
</td>
<td className="projects__category--input">

<td className="projects__category--input">
{canEditCategoryAndStatus || canPutProject ? (

<select

data-testid="projects__category--input" //added for unit test
data-testid="projects__category--input"
value={category}
onChange={e => {
onUpdateProjectCategory(e);
}}

onChange={onUpdateProjectCategory}
>
<option value="Unspecified">Unspecified</option>
<option value="Food">Food</option>
Expand All @@ -153,31 +105,40 @@ const Project = props => {
category
)}
</td>
{/* <td className="projects__active--input" data-testid="project-active" onClick={canPutProject ? updateActive : null}>
{props.active ? ( */}
<td className="projects__active--input" data-testid="project-active" onClick={canEditCategoryAndStatus || canPutProject ? onUpdateProjectActive : null}>
{isActive ? (

<td
className="projects__active--input"
data-testid="project-active"
onClick={canEditCategoryAndStatus || canPutProject ? onUpdateProjectActive : null}
>
{isActive ? (
<div className="isActive">
<i className="fa fa-circle" aria-hidden="true"></i>
</div>
) : (
<div className="isNotActive">
<i className="fa fa-circle" aria-hidden="true" color='#dee2e6'></i>
<i className="fa fa-circle" aria-hidden="true" color="#dee2e6"></i>
</div>
)}
</td>

<td>
<NavItem tag={Link} to={`/inventory/${projectId}`}>
<button type="button" className="btn btn-outline-info" style={darkMode ? {} : boxStyle}>
{' '}
<i className="fa fa-archive" aria-hidden="true"></i>
</button>
</NavItem>
</td>

<td>
<NavItem tag={Link} to={`/project/members/${projectId}`}>
<NavItem
tag={Link}
to={{
pathname: `/project/members/${projectId}`,
state: { projectName: projectName },
}}
>
<button type="button" className="btn btn-outline-info" style={darkMode ? {} : boxStyle}>
{' '}
<i className="fa fa-users" aria-hidden="true"></i>
</button>
</NavItem>
Expand All @@ -191,33 +152,22 @@ const Project = props => {
</NavItem>
</td>


{(canDeleteProject) ? (

{canDeleteProject ? (
<td>
<button
data-testid="delete-button"
type="button"
className="btn btn-outline-danger"
onClick={onArchiveProject}
style={darkMode ? {} : boxStyle}
disabled = {isArchived}
>
{ARCHIVE}
</button>
</td>
) : null}
</tr>
<ModalTemplate
isOpen={modalData.showModal}
closeModal={onCloseModal}
confirmModal={modalData.hasConfirmBtn ? confirmArchive : null}
setInactiveModal={modalData.hasInactiveBtn ? setProjectInactive : null}
modalMessage={modalData.modalMessage}
modalTitle={modalData.modalTitle}
/>
</>
);
};
const mapStateToProps = state => state;
export default connect(mapStateToProps, { hasPermission, modifyProject, clearError })(Project);

const mapStateToProps = (state) => state;
export default connect(mapStateToProps, { hasPermission })(Project);
Loading
Loading