src/pages/ProjectSettingsPage/index.jsx
import React from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import { Redirect } from "react-router-dom";
import PrimaryButton from "../../components/PrimaryButton";
import {
handleGetRequest,
handlePostRequestWithOutDataObject,
handlePatchRequest,
handleDeleteRequest,
} from "../../apis/apis.js";
import Spinner from "../../components/Spinner";
import Avatar from "../../components/Avatar";
import Modal from "../../components/Modal";
import TextArea from "../../components/TextArea";
import Feedback from "../../components/Feedback";
import DeleteWarning from "../../components/DeleteWarning";
import BlackInputText from "../../components/BlackInputText";
import styles from "./ProjectSettingsPage.module.css";
// import "./ProjectSettingsPage.module.css";
import Select from "../../components/Select";
import { retrieveProjectTypes } from "../../helpers/projecttypes";
import { validateName } from "../../helpers/validation";
import { ReactComponent as CopyText } from "../../assets/images/copy.svg";
import { ReactComponent as Checked } from "../../assets/images/checked.svg";
import SettingsModal from "../../components/SettingsModal/index.jsx";
import DisableModalContent from "../../components/DisableModalContent/index.jsx";
import { ReactComponent as Bin } from "../../assets/images/bin.svg";
import { ReactComponent as Send } from "../../assets/images/send.svg";
import { retrieveMembershipRoles } from "../../helpers/membershipRoles";
import DashboardLayout from "../../components/Layouts/DashboardLayout";
import { namedOrganisations } from "../../helpers/projectOrganisations";
import SettingsActionRow from "../../components/SettingsActionRow/index.jsx";
class ProjectSettingsPage extends React.Component {
constructor(props) {
super(props);
const projectInfo = { ...JSON.parse(localStorage.getItem("project")) };
const { name, description, organisation, project_type, age } = projectInfo;
this.state = {
openUpdateAlert: false,
openRoleUpdateAlert: false,
openDeleteAlert: false,
openDropDown: false,
projectName: name ? name : "",
projectID: this.props.match.params.projectID,
projectDescription: description ? description : "",
projectAge: age ? age : "",
error: "",
updatingProjectDetails: false,
nameChecked: false,
idChecked: false,
tokenChecked: false,
descriptionChecked: false,
Confirmprojectname: "",
disableDelete: true,
projectOrganisation: organisation ? organisation : "",
projectType: project_type ? project_type : "",
othersBool: false,
otherType: "",
showInviteModel: false,
role: "",
email: "",
removeMemberModal: false,
isCurrentUserRemoved: false,
projectUsers: [],
fetchingProjectMembersError: "",
projectUnregisteredUsers: [],
fetchingProjectMembers: true,
invitingMembers: false,
invitingMembersError: "",
updateMemberError: "",
updatingMemberRole: false,
removeMemberError: "",
removingMember: false,
currentUserIsAdminOrMember: false,
currentUserIsAdminOrOwner: false,
currentUserIsMemberOnly: false,
deleteProjectError: "",
deletingProject: false,
disableProjectError: "",
fetchingProjectDetails: false,
disableProjectAlert: false,
disableProjectProgress: false,
projectDetails: [],
};
this.handleDeleteProject = this.handleDeleteProject.bind(this);
this.showUpdateAlert = this.showUpdateAlert.bind(this);
this.updateRoleAlert = this.updateRoleAlert.bind(this);
this.hideUpdateAlert = this.hideUpdateAlert.bind(this);
this.hideRoleUpdateAlert = this.hideRoleUpdateAlert.bind(this);
this.showDeleteAlert = this.showDeleteAlert.bind(this);
this.hideDeleteAlert = this.hideDeleteAlert.bind(this);
this.nameOnClick = this.nameOnClick.bind(this);
this.projectIDOnClick = this.projectIDOnClick.bind(this);
this.projectDescriptionOnClick = this.projectDescriptionOnClick.bind(this);
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.checkProjectInputValidity = this.checkProjectInputValidity.bind(this);
this.handleTypeSelectChange = this.handleTypeSelectChange.bind(this);
this.handleClick = this.handleClick.bind(this);
this.hideModal = this.hideModal.bind(this);
this.showInviteMenu = this.showInviteMenu.bind(this);
this.handleMemberInvitation = this.handleMemberInvitation.bind(this);
this.handleMemberRoleUpdate = this.handleMemberRoleUpdate.bind(this);
this.handleInvitationRole = this.handleInvitationRole.bind(this);
this.hideInviteMenu = this.hideInviteMenu.bind(this);
this.showMenu = this.showMenu.bind(this);
this.renderRedirect = this.renderRedirect.bind(this);
this.removeProjectMember = this.removeProjectMember.bind(this);
this.checkMembership = this.checkMembership.bind(this);
this.updateRoleValue = this.updateRoleValue.bind(this);
this.showRemoveMemberModal = this.showRemoveMemberModal.bind(this);
this.closeRemoveMemberModal = this.closeRemoveMemberModal.bind(this);
this.getProjectMemberz = this.getProjectMemberz.bind(this);
this.inviteMember = this.inviteMember.bind(this);
this.updateMemberRoles = this.updateMemberRoles.bind(this);
this.removeMember = this.removeMember.bind(this);
this.updateProjectDetails = this.updateProjectDetails.bind(this);
this.deleteThisProject = this.deleteThisProject.bind(this);
this.handleOrganisationSelectChange =
this.handleOrganisationSelectChange.bind(this);
this.handleEnableButtonClick = this.handleEnableButtonClick.bind(this);
this.getProjectDetails = this.getProjectDetails.bind(this);
this.disableProjectAlertFunc = this.disableProjectAlertFunc.bind(this);
}
componentDidMount() {
this.getProjectMemberz();
this.getProjectDetails();
}
disableProjectAlertFunc(disableBool) {
this.setState({
disableProjectAlert: disableBool,
disableProjectError: "",
});
}
getProjectMemberz() {
const projectID = this.props.match.params.projectID;
handleGetRequest(`/projects/${projectID}/users`)
.then((response) => {
this.setState({
projectUsers: response.data.data.project_users,
projectUnregisteredUsers: response.data.data.project_anonymous_users,
fetchingProjectMembers: false,
});
this.checkMembership();
})
.catch((error) => {
this.setState({
fetchingProjectMembersError: "Failed to fetch project members",
fetchingProjectMembers: false,
});
});
}
inviteMember() {
const { email, role } = this.state;
this.setState({
invitingMembers: true,
});
const projectID = this.props.match.params.projectID;
handlePostRequestWithOutDataObject(
{ email: email, role: role },
`/projects/${projectID}/users`
)
.then(() => {
//page reset also resets loader
window.location.href = `/projects/${projectID}/settings`;
})
.catch((error) => {
this.setState({
invitingMembersError: "Failed to invite user",
invitingMembers: false,
});
});
}
updateMemberRoles() {
const { email, role } = this.state;
this.setState({
updatingMemberRole: true,
});
const projectID = this.props.match.params.projectID;
handlePatchRequest(`/projects/${projectID}/users`, {
email,
role,
})
.then(() => {
window.location.href = `/projects/${projectID}/settings`;
})
.catch((error) => {
this.setState({
updateMemberError: "Failed to update user",
updatingMemberRole: false,
});
});
}
removeMember(email) {
const projectID = this.props.match.params.projectID;
const data = { data: email };
this.setState({ removingMember: true });
handleDeleteRequest(`/projects/${projectID}/users`, data)
.then(() => {
window.location.href = `/projects/${projectID}/settings`;
})
.catch(() => {
this.setState({
removeMemberError: "Failed to remove user",
removingMember: false,
});
});
}
componentDidUpdate(prevProps) {
const { isDeleted } = this.props;
if (isDeleted !== prevProps.isDeleted) {
this.hideDeleteAlert();
}
}
handleClick = (e) => {
if (this.state.actionsMenu) {
return;
}
this.setState({ actionsMenu: true });
e.stopPropagation();
document.addEventListener("click", this.hideModal);
};
hideModal = () => {
this.setState({ actionsMenu: false });
document.removeEventListener("click", this.hideModal);
};
showMenu(userEmail) {
this.setState({ email: userEmail });
}
showRemoveMemberModal(email) {
this.setState({
removeMemberModal: true,
removeMemberError: "",
email: email,
});
}
closeRemoveMemberModal() {
this.setState({
removeMemberModal: false,
});
}
removeProjectMember(e) {
e.preventDefault();
const { data } = this.props;
const { email } = this.state;
const emailDetails = {
email: email,
};
this.removeMember(emailDetails);
if (email === data.email) {
this.setState({
isCurrentUserRemoved: true,
});
}
}
handleMemberInvitation(e) {
e.preventDefault();
const { email, role } = this.state;
if (email !== "" && role !== "") {
this.validateEmail(email);
this.inviteMember();
}
}
handleMemberRoleUpdate(e) {
e.preventDefault();
const { email, role } = this.state;
if (email !== "" && role !== "") {
this.validateEmail(email);
this.updateMemberRoles();
}
}
validateEmail(email) {
const emailRegEx =
// eslint-disable-next-line no-useless-escape
/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return emailRegEx.test(String(email).toLowerCase());
}
handleChange(e) {
const { error, openDeleteAlert } = this.state;
const projectInfo = { ...JSON.parse(localStorage.getItem("project")) };
const { name } = projectInfo;
this.setState({
[e.target.name]: e.target.value,
});
if (error) {
this.setState({
error: "",
});
}
if (e.target.value === name && openDeleteAlert) {
this.setState({
disableDelete: false,
});
} else if (e.target.value !== name && openDeleteAlert) {
this.setState({
disableDelete: true,
});
}
}
showInviteMenu() {
this.setState({ showInviteModel: true, invitingMembersError: "" });
}
hideInviteMenu() {
this.setState({ showInviteModel: false });
}
handleSubmit() {
const {
projectName,
projectDescription,
projectOrganisation,
projectType,
otherType,
othersBool,
} = this.state;
const {
match: {
params: { projectID },
},
} = this.props;
const projectInfo = { ...JSON.parse(localStorage.getItem("project")) };
const { name, description, organisation, project_type } = projectInfo;
const Trim = (input) => input.trim();
const capitalizeFirstLetter = (input) =>
input.charAt(0).toUpperCase() + input.slice(1);
const type = othersBool
? capitalizeFirstLetter(otherType)
: capitalizeFirstLetter(projectType);
const trimedprojectName = Trim(projectName);
const trimedprojectDescription = Trim(projectDescription);
const trimedprojectOrganisation = Trim(projectOrganisation);
const trimedprojectType = Trim(type);
if (
trimedprojectName !== name ||
trimedprojectDescription !== description ||
trimedprojectOrganisation !== organisation ||
trimedprojectType !== project_type
) {
if (
!trimedprojectName ||
!trimedprojectDescription ||
!trimedprojectOrganisation ||
!trimedprojectType
) {
this.setState({
error:
"Can't update when an empty field is submited, please fill the missing field or leave it unchanged.",
});
} else {
if (trimedprojectName !== name) {
const nameCheckResult = this.checkProjectInputValidity(
trimedprojectName,
"name"
);
if (nameCheckResult !== "") {
this.setState({
error: nameCheckResult,
});
} else {
const organisationCheckResult = this.checkProjectInputValidity(
trimedprojectOrganisation,
"organisation"
);
const typeCheckResult = this.checkProjectInputValidity(
trimedprojectType,
"type"
);
if (organisationCheckResult !== "" || typeCheckResult !== "") {
if (organisationCheckResult !== "") {
this.setState({
error: organisationCheckResult,
});
}
if (typeCheckResult !== "") {
this.setState({
error: typeCheckResult,
});
}
}
if (typeCheckResult === "" && organisationCheckResult === "") {
const newProject = {
name: trimedprojectName,
project_type: trimedprojectType,
organisation: trimedprojectOrganisation,
description: trimedprojectDescription,
};
//updateProject(projectID, newProject);
this.updateProjectDetails(projectID, newProject);
}
}
} else {
const organisationCheckResult = this.checkProjectInputValidity(
trimedprojectOrganisation,
"organisation"
);
const typeCheckResult = this.checkProjectInputValidity(
trimedprojectType,
"type"
);
if (organisationCheckResult !== "" || typeCheckResult !== "") {
if (organisationCheckResult !== "") {
this.setState({
error: organisationCheckResult,
});
}
if (typeCheckResult !== "") {
this.setState({
error: typeCheckResult,
});
}
}
if (typeCheckResult === "" && organisationCheckResult === "") {
const newProject = {
project_type: trimedprojectType,
organisation: trimedprojectOrganisation,
description: trimedprojectDescription,
};
//updateProject(projectID, newProject);
this.updateProjectDetails(projectID, newProject);
}
}
}
} else {
this.setState({
error: "Please provide new information in atleast one of the fields",
});
}
}
nameOnClick(e) {
const projectInfo = { ...JSON.parse(localStorage.getItem("project")) };
const { name } = projectInfo;
navigator.clipboard.writeText(name);
this.setState({ nameChecked: true });
e.preventDefault();
}
projectIDOnClick() {
const projectInfo = { ...JSON.parse(localStorage.getItem("project")) };
const { project_id } = projectInfo;
navigator.clipboard.writeText(project_id);
this.setState({ idChecked: true });
}
projectDescriptionOnClick() {
const projectInfo = { ...JSON.parse(localStorage.getItem("project")) };
const { description } = projectInfo;
navigator.clipboard.writeText(description);
this.setState({ descriptionChecked: true });
}
handleDeleteProject(e, projectID) {
// const { deleteProject } = this.props;
e.preventDefault();
this.deleteThisProject(projectID);
}
getProjectDetails() {
const {
match: { params },
} = this.props;
const { projectID } = params;
handleGetRequest(`/projects/${projectID}`)
.then((response) => {
this.setState({
projectDetails: response.data.data.project,
fetchingProjectDetails: false,
});
})
.catch((error) => {
this.setState({
error: "Failed to fetch project details",
fetchingProjectDetails: false,
});
});
}
handleEnableButtonClick = () => {
let { projectDetails } = this.state;
const { projectID } = this.props.match.params;
this.setState({ disableProjectProgress: true });
try {
if (projectDetails.disabled) {
handlePostRequestWithOutDataObject({}, `/projects/${projectID}/enable`)
.then(() => {
window.location.reload();
})
.catch((error) => {
this.setState({
disableProjectError:
"Failed to complete this action. Please try again later",
});
});
} else {
handlePostRequestWithOutDataObject({}, `/projects/${projectID}/disable`)
.then(() => {
window.location.reload();
})
.catch((error) => {
this.setState({
disableProjectError:
"Failed to complete this action. Please try again later",
disableProjectProgress: false,
});
});
}
} catch (error) {
//console.error("API call error:", error);
this.setState({
disableProjectError:
"Failed to complete this action. Please try again later",
disableProjectProgress: false,
});
}
};
showUpdateAlert() {
this.setState({ openUpdateAlert: true });
}
updateRoleAlert(email) {
this.setState({
openRoleUpdateAlert: true,
email: email,
});
}
showDeleteAlert() {
this.setState({ openDeleteAlert: true });
}
checkProjectInputValidity(input, output) {
if (!validateName(input)) {
return `${output} should start with a letter`;
} else if (validateName(input) === "false_convention") {
return `${output} may only contain letters and a hypen -`;
} else if (input.length > 22) {
return `Project ${output} cannot exceed 22 characters`;
} else {
return "";
}
}
hideUpdateAlert() {
this.setState({ openUpdateAlert: false });
}
hideRoleUpdateAlert() {
this.setState({ openRoleUpdateAlert: false });
}
hideDeleteAlert() {
this.setState({ openDeleteAlert: false });
}
handleTypeSelectChange(selected) {
const { othersBool } = this.state;
if (selected.id === 6) {
if (!othersBool) {
this.setState({ othersBool: true });
}
} else {
this.setState({ projectType: selected.value });
if (othersBool) {
this.setState({ othersBool: false });
}
}
}
handleInvitationRole(selected) {
this.setState({ role: selected.value });
}
handleOrganisationSelectChange(selected) {
this.setState({ projectOrganisation: selected.value });
}
checkMembership() {
const { data } = this.props;
const { projectUsers } = this.state;
const result = projectUsers?.filter((item) => item.user?.id === data.id);
//either member or admin
if (
result[0]?.role === "RolesList.member" ||
result[0]?.role === "RolesList.admin"
) {
this.setState({ currentUserIsAdminOrMember: true });
}
//either owner or admin
if (
result[0]?.role === "RolesList.owner" ||
result[0]?.role === "RolesList.admin"
) {
this.setState({ currentUserIsAdminOrOwner: true });
}
if (result[0]?.role === "RolesList.member") {
this.setState({ currentUserIsMemberOnly: true });
}
}
updateRoleValue(string) {
let role = string[1];
return role.charAt(0).toUpperCase() + role.slice(1);
}
renderRedirect = () => {
const { isDeleted, isUpdated } = this.props;
const { isCurrentUserRemoved } = this.state;
if (isDeleted || isUpdated || isCurrentUserRemoved) {
return <Redirect to={`/projects`} noThrow />;
}
};
updateProjectDetails(projectID, data) {
this.setState({
updatingProjectDetails: true,
});
handlePatchRequest(`/projects/${projectID}`, data)
.then(() => {
window.location.href = `/projects`;
})
.catch((error) => {
this.setState({
error: "Failed to update project",
updatingProjectDetails: false,
});
});
}
deleteThisProject(projectID) {
this.setState({ deletingProject: true, deleteProjectError: "" });
handleDeleteRequest(`/projects/${projectID}`, {})
.then(() => {
window.location.href = `/projects`;
})
.catch(() => {
this.setState({
deleteProjectError: "Failed to delete this project",
deletingProject: false,
});
});
}
render() {
const {
match: { params },
isDeleted,
isUpdated,
errorMessage,
data,
} = this.props;
const projectInfo = { ...JSON.parse(localStorage.getItem("project")) };
let currentUserEmail = data.email;
const { name } = projectInfo;
const {
openUpdateAlert,
openDeleteAlert,
openRoleUpdateAlert,
projectName,
projectDescription,
projectAge,
error,
Confirmprojectname,
disableDelete,
projectOrganisation,
projectType,
othersBool,
otherType,
nameChecked,
// idChecked,
// descriptionChecked,
showInviteModel,
email,
role,
currentUserIsAdminOrMember,
removeMemberModal,
projectUsers,
projectUnregisteredUsers,
currentUserIsAdminOrOwner,
currentUserIsMemberOnly,
fetchingProjectMembers,
invitingMembers,
invitingMembersError,
updateMemberError,
updatingMemberRole,
removingMember,
removeMemberError,
updatingProjectDetails,
deletingProject,
deleteProjectError,
disableProjectError,
disableProjectAlert,
disableProjectProgress,
} = this.state;
const types = retrieveProjectTypes();
const roles = retrieveMembershipRoles();
const { projectID } = params;
const presetOrganisations = namedOrganisations();
return (
<DashboardLayout name={name} header="Project Settings" short>
{isUpdated || isDeleted ? this.renderRedirect() : null}
<div className="SectionTitle">Project Details</div>
<div className={`${styles.ProjectInstructions}`}>
<div className={`${styles.ProjectsDetailsInnerSection}`}>
<div className={styles.InnerContentGrid}>
<div className={`${styles.SectionSubTitle}`}>Project Name</div>
<div className={styles.ProjectButtonRow}>
<div className={`${styles.SettingsSectionInfo}`}>
<div>{projectName}</div>
</div>
<div className={styles.CopyIcon}>
<CopyText onClick={this.nameOnClick} />
{nameChecked ? <Checked /> : null}
</div>
</div>
<div>
<div className={`${styles.SectionSubTitle}`}>Project Description</div>
<div className={styles.ProjectButtonRow}>
<div className={styles.SettingsSectionInfo}>
<div>{projectDescription}</div>
</div>
</div>
</div>
</div>
<div className={styles.InnerContentGrid}>
<div>
<div className={`${styles.SectionSubTitle}`}>Organization</div>
<div className={styles.ProjectButtonRow}>
<div className={styles.SettingsSectionInfo}>
<div>{projectOrganisation}</div>
</div>
</div>
</div>
<div>
<div className={`${styles.SectionSubTitle}`}>Age</div>
<div className={styles.ProjectButtonRow}>
<div className={styles.SettingsSectionInfo}>
<div>{projectAge}</div>
</div>
</div>
</div>
</div>
<div className={styles.InnerContentGrid}>
<div>
<div className={`${styles.SectionSubTitle}`}>Project Type</div>
<div className={styles.ProjectButtonRow}>
<div className={styles.SettingsSectionInfo}>
<div>{projectType}</div>
</div>
</div>
</div>
<div>
<div className={`${styles.SectionSubTitle}`}>Status</div>
<div className={styles.ProjectButtonRow}>
<div className={styles.SettingsSectionInfo}>
<div>
{this.state.projectDetails?.disabled === true ? (
<span style={{ color: "red" }}>Disabled</span>
) : (
"Enabled"
)}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div className={`${styles.SectionSubTitle}`}>Membership</div>
<div className={styles.ProjectInstructions}>
{fetchingProjectMembers ? (
<Spinner />
) : (
<>
<div className={styles.MembershipHeader}>
<div className={styles.MemberSection}>
<div className={styles.SettingsSectionInfoHeader}>
{projectUsers?.length === 1 ? (
<div className="SectionSubTitle">
Project has 1 Team Member
</div>
) : (
<div>Project has {projectUsers?.length} Team Members</div>
)}
</div>
<div className="SubText" style={{ maxWidth: "90%" }}>
Members that have accounts on crane cloud can perform
different operations on the project depending on their
permission.
</div>
</div>
{currentUserIsAdminOrOwner && (
<PrimaryButton
// className={styles.SettingsButton}
color="primary"
onClick={() => {
this.showInviteMenu();
}}
>
Invite member
</PrimaryButton>
)}
</div>
<div className={styles.MemberTable}>
<div className={styles.MemberBody}>
{projectUsers?.map((entry, index) => (
<div className={styles.MemberTableRow} key={index}>
<div className={styles.MemberInfo}>
<Avatar
name={entry.user.name}
className={styles.MemberAvatar}
/>
<div className={styles.MemberNameEmail}>
<div className={styles.UserHeader}>
{entry.user.name}
</div>
<div className={styles.Wrap}>{entry.user.email}</div>
</div>
</div>
{entry.role !== "RolesList.owner" &&
entry.accepted_collaboration_invite === false && (
<div className="SubText">Pending Invitation</div>
)}
<div className={styles.MemberOptions}>
<div
className={styles.MemberRole}
onClick={() => {
!currentUserIsMemberOnly &&
this.updateRoleAlert(entry.user.email);
}}
title="Change Role"
>
<span>Role:</span>
{this.updateRoleValue(entry.role.split("."))}
</div>
<div>
{entry.user.email === currentUserEmail
? entry.role !== "RolesList.owner" && (
<PrimaryButton
small
noPadding
transparent
onClick={() => {
this.showRemoveMemberModal(
entry.user.email
);
}}
>
Leave
</PrimaryButton>
)
: currentUserIsAdminOrOwner && (
<PrimaryButton
small
noPadding
transparent
onClick={() => {
this.showRemoveMemberModal(
entry.user.email
);
}}
>
Remove
</PrimaryButton>
)}
</div>
</div>
</div>
))}
</div>
</div>
{projectUnregisteredUsers.length > 0 && (
<div className={styles.LowerSection}>
<div className={styles.SettingsSectionInfoHeader}>
Unregistered Members
</div>
<div className="SubText">
Members invited to this project by email but have no crane
cloud accounts.
</div>
<div className={styles.MemberTable}>
<div className={styles.MemberBody}>
{projectUnregisteredUsers?.map((entry, index) => (
<div className={styles.MemberTableRow} key={index}>
<div className={styles.MemberTableCell}>
<div className={styles.NameSecting}>
{
<Avatar
name={entry.email}
className={styles.MemberAvatar}
/>
}
{/* <div className={styles.MemberNameEmail}> */}
<div className={styles.Wrap}>{entry.email}</div>
{/* </div> */}
</div>
</div>
<div className={styles.MemberActionArea}>
<div className={styles.MemberTableCell}>
<div className={styles.MemberRole}>
<span>Role:</span>
{entry.role}
</div>
</div>
<div className={styles.OptionButtons}>
<Send
className={styles.SendButton}
title="Resend Invite"
/>
<Bin
className={styles.BinButton}
onClick={() => {
this.showRemoveMemberModal(entry.email);
}}
title="Delete Invite"
/>
</div>
</div>
</div>
))}
</div>
</div>
</div>
)}
</>
)}
</div>
{openRoleUpdateAlert && (
<div className={styles.ProjectDeleteModel}>
<Modal
showModal={openRoleUpdateAlert}
onClickAway={this.hideRoleUpdateAlert}
>
<div>
<div className={styles.ModelHeader}>Change Member Role</div>
<div className={styles.UpdateForm}>
<div className={styles.UpdateInputSection}>
<div className={styles.DeleteDescription}>
Search member (by email)
</div>
<BlackInputText
placeholder="Enter email here"
name="email"
value={email}
// should not be editable
// onChange={(e) => {
// this.handleChange(e);
// }}
/>
</div>
<div className={styles.UpdateInputSection}>
<div className={styles.DeleteDescription}>
Member Role (in connection with user permission)
</div>
<Select
required
placeholder={role ? role : "Choose membership role"}
options={roles}
onChange={this.handleInvitationRole}
/>
</div>
{updateMemberError && (
<Feedback message={updateMemberError} type="error" />
)}
<div className={styles.SendInvitationButton}>
<PrimaryButton
onClick={this.handleMemberRoleUpdate}
color="primary"
>
{updatingMemberRole ? <Spinner /> : "Update Role"}
</PrimaryButton>
</div>
</div>
</div>
</Modal>
</div>
)}
{currentUserIsAdminOrMember === false ? (
<>
<div className="SectionTitle">Manage Project</div>
<div className="ProjectInstructions">
<div className="MemberBody">
<SettingsActionRow
title="Update Project"
content="Modify the project name and description"
buttonLabel="Update"
onButtonClick={this.showUpdateAlert}
buttonColor="primary"
/>
<SettingsActionRow
title={`${
this.state.projectDetails?.disabled ? "Enable" : "Disable"
} project
`}
content={
this.state.projectDetails?.disabled
? "Allow access to project resources and enable billing"
: "Prevent project from being billed by blocking access to it's resources."
}
buttonLabel={
this.state.projectDetails?.disabled ? "Enable" : "Disable"
}
buttonColor={
this.state.projectDetails?.disabled ? "primary" : "red"
}
onButtonClick={() => {
this.disableProjectAlertFunc(true);
}}
/>
<SettingsActionRow
title="Delete Project"
content="Take down your entire project, delete all apps under it."
buttonLabel="Delete"
buttonColor="red"
onButtonClick={this.showDeleteAlert}
/>
</div>
</div>
</>
) : null}
{openUpdateAlert && (
<div className={styles.ProjectDeleteModel}>
<Modal
showModal={openUpdateAlert}
onClickAway={this.hideUpdateAlert}
>
<div>
<div
onSubmit={(e) => {
this.handleSubmit();
e.preventDefault();
}}
>
<div className={styles.UpdateForm}>
<div className={styles.UpdateInputSection}>
<div className={styles.DeleteDescription}>
Project name
</div>
<BlackInputText
placeholder="Project Name"
name="projectName"
value={projectName}
onChange={(e) => {
this.handleChange(e);
}}
/>
</div>
<div className={styles.UpdateInputSection}>
<div className={styles.DeleteDescription}>
Organisation
</div>
<Select
required
placeholder={
projectOrganisation
? projectOrganisation
: "Update project Organization"
}
options={presetOrganisations}
onChange={this.handleOrganisationSelectChange}
/>
{othersBool && (
<BlackInputText
placeholder="Organisation"
name="projectOrganisation"
value={projectOrganisation}
onChange={(e) => {
this.handleChange(e);
}}
/>
)}
</div>
<div className={styles.UpdateInputSection}>
<div className={styles.DeleteDescription}>
Project type
</div>
<Select
required
placeholder={
projectType ? projectType : "Update project type"
}
options={types}
onChange={this.handleTypeSelectChange}
/>
{othersBool && (
<BlackInputText
required
placeholder="Type of project"
name="otherType"
value={otherType}
onChange={(e) => {
this.handleChange(e);
}}
/>
)}
</div>
<div className={styles.UpdateInputSection}>
<div className={styles.DeleteDescription}>
Project description
</div>
<TextArea
placeholder="Description"
name="projectDescription"
style={styles.TextArea}
value={projectDescription}
onChange={(e) => {
this.handleChange(e);
}}
/>
</div>
{(errorMessage || error) && (
<Feedback
type="error"
message={
errorMessage ? "Failed to update Project" : error
}
/>
)}
<div className={styles.UpdateProjectModelButtons}>
<PrimaryButton
className="CancelBtn"
onClick={this.hideUpdateAlert}
>
Cancel
</PrimaryButton>
<PrimaryButton
onClick={this.handleSubmit}
color="primary"
>
{updatingProjectDetails ? (
<Spinner />
) : (
"update project"
)}
</PrimaryButton>
</div>
</div>
</div>
</div>
</Modal>
</div>
)}
{showInviteModel === true && (
<div className={styles.ProjectDeleteModel}>
<Modal
showModal={showInviteModel}
onClickAway={this.hideInviteMenu}
>
<div>
<div className={styles.ModelHeader}>Invite Member </div>
<div className={styles.UpdateForm}>
<div className={styles.UpdateInputSection}>
<div className={styles.DeleteDescription}>
Search member (by email)
</div>
<BlackInputText
placeholder="Enter email here"
name="email"
value={email}
onChange={(e) => {
this.handleChange(e);
}}
/>
</div>
<div className={styles.UpdateInputSection}>
<div className={styles.DeleteDescription}>
Member Role (in connection with user permission)
</div>
<Select
required
placeholder={role ? role : "Choose membership role"}
options={roles}
onChange={this.handleInvitationRole}
/>
</div>
{invitingMembersError && (
<Feedback type="error" message={invitingMembersError} />
)}
<div className={styles.SendInvitationButton}>
<PrimaryButton
color="primary"
onClick={this.handleMemberInvitation}
>
{invitingMembers ? <Spinner /> : "Send Invitation"}
</PrimaryButton>
</div>
</div>
</div>
</Modal>
</div>
)}
{openDeleteAlert && (
<div className={styles.ProjectDeleteModel}>
<Modal
showModal={openDeleteAlert}
onClickAway={this.hideDeleteAlert}
>
<div className={styles.DeleteProjectModel}>
<div className={styles.DeleteProjectModalUpperSection}>
<div className={styles.WarningContainer}>
<div className={styles.DeleteDescription}>
Are you sure you want to delete
<span>{name}</span>
?
</div>
<div className={styles.DeleteSubDescription}>
This will permanently delete the project and all its
resources.
<br />
<br />
Please confirm by typing
<b className={styles.DeleteWarning}>{name}</b>
below.
</div>
<div className={styles.InnerModalDescription}>
<BlackInputText
required
placeholder={name}
name="Confirmprojectname"
value={Confirmprojectname}
onChange={(e) => {
this.handleChange(e);
}}
/>
<DeleteWarning textAlignment="Left" />
</div>
</div>
</div>
<div className={styles.DeleteProjectModalLowerSection}>
<div className={styles.DeleteProjectModelButtons}>
<PrimaryButton
className="CancelBtn"
onClick={this.hideDeleteAlert}
>
Cancel
</PrimaryButton>
<button
className={
disableDelete ? styles.InactiveDelete : styles.DeleteBtn
}
disabled={disableDelete}
onClick={(e) =>
this.handleDeleteProject(e, params.projectID)
}
>
{deletingProject ? <Spinner /> : "Delete"}
</button>
</div>
{deleteProjectError && (
<Feedback message={deleteProjectError} type="error" />
)}
</div>
</div>
</Modal>
</div>
)}
<Modal
showModal={removeMemberModal}
onClickAway={this.closeRemoveMemberModal}
>
<div className={styles.DeleteProjectModel}>
<div className={styles.DeleteProjectModalUpperSection}>
<div className={styles.WarningContainer}>
<div className={styles.DeleteDescription}>
{currentUserEmail === email ? (
<>Are you sure you want to remove yourself?</>
) : (
<>
Are you sure you want to remove the member with
<br /> email: {email}?
</>
)}
</div>
</div>
</div>
<div className={styles.DeleteProjectModalLowerSection}>
<div className={styles.DeleteProjectModelButtons}>
<PrimaryButton
type="button"
className="CancelBtn"
onClick={this.closeRemoveMemberModal}
>
Cancel
</PrimaryButton>
<PrimaryButton
type="button"
color="red"
onClick={(e) => this.removeProjectMember(e)}
>
{removingMember ? <Spinner /> : "Confirm"}
</PrimaryButton>
</div>
</div>
{removeMemberError && (
<Feedback type="error" message={"Failed to remove member"} />
)}
</div>
</Modal>
{disableProjectAlert && (
<SettingsModal
showModal={disableProjectAlert}
onClickAway={() => {
this.disableProjectAlertFunc(false);
}}
>
<DisableModalContent
item={{
name: projectName,
type: "project",
disabled: this.state.projectDetails?.disabled,
}}
disableProgress={disableProjectProgress}
handleDisableButtonClick={() => {
this.handleEnableButtonClick();
}}
hideDisableAlert={() => {
this.disableProjectAlertFunc(false);
}}
message={disableProjectError}
isFailed={disableProjectError ? true : false}
/>
</SettingsModal>
)}
</DashboardLayout>
);
}
}
ProjectSettingsPage.propTypes = {
name: PropTypes.string,
description: PropTypes.string,
};
ProjectSettingsPage.defaultProps = {
message: "",
name: "",
description: "",
};
export const mapStateToProps = (state) => {
const { data } = state.user;
return {
data,
};
};
const mapDispatchToProps = {};
export default connect(
mapStateToProps,
mapDispatchToProps
)(ProjectSettingsPage);