Merge branch 'master' of https://github.com/ONLYOFFICE/AppServer
This commit is contained in:
commit
e04a0bee27
@ -255,26 +255,6 @@ class ProfileInfo extends React.PureComponent {
|
|||||||
>
|
>
|
||||||
{email}
|
{email}
|
||||||
</Link>
|
</Link>
|
||||||
{(isAdmin || isSelf) &&
|
|
||||||
<IconButtonWrapper title={t('EmailChangeButton')} >
|
|
||||||
<IconButton
|
|
||||||
color="#A3A9AE"
|
|
||||||
size={16}
|
|
||||||
iconName='AccessEditIcon'
|
|
||||||
isFill={true}
|
|
||||||
onClick={this.onEmailChange} />
|
|
||||||
</IconButtonWrapper>
|
|
||||||
}
|
|
||||||
{activationStatus === 2 && (isAdmin || isSelf) &&
|
|
||||||
<IconButtonWrapper title={t('SendInviteAgain')}>
|
|
||||||
<IconButton
|
|
||||||
color="#A3A9AE"
|
|
||||||
size={16}
|
|
||||||
iconName='FileActionsConvertIcon'
|
|
||||||
isFill={true}
|
|
||||||
onClick={this.onSentInviteAgain.bind(this, id)} />
|
|
||||||
</IconButtonWrapper>
|
|
||||||
}
|
|
||||||
</>
|
</>
|
||||||
</InfoItemValue>
|
</InfoItemValue>
|
||||||
</InfoItem>
|
</InfoItem>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React, { useCallback } from "react";
|
import React from "react";
|
||||||
import { withRouter } from "react-router";
|
import { withRouter } from "react-router";
|
||||||
import { useTranslation } from 'react-i18next';
|
import { withTranslation } from 'react-i18next';
|
||||||
import {
|
import {
|
||||||
Text,
|
Text,
|
||||||
Avatar,
|
Avatar,
|
||||||
@ -67,93 +67,90 @@ const createContacts = contacts => {
|
|||||||
return styledContacts;
|
return styledContacts;
|
||||||
};
|
};
|
||||||
|
|
||||||
const SectionBodyContent = props => {
|
class SectionBodyContent extends React.PureComponent {
|
||||||
const { t } = useTranslation();
|
|
||||||
const { profile, updateProfileCulture, history, settings, isAdmin, viewer } = props;
|
|
||||||
|
|
||||||
const contacts = profile.contacts && getUserContacts(profile.contacts);
|
onEditSubscriptionsClick = () => console.log("Edit subscriptions onClick()");
|
||||||
const role = getUserRole(profile);
|
|
||||||
const socialContacts = (contacts && contacts.social && contacts.social.length > 0 && createContacts(contacts.social)) || null;
|
|
||||||
const infoContacts = contacts && createContacts(contacts.contact);
|
|
||||||
const isSelf = isMe(viewer, profile.userName);
|
|
||||||
|
|
||||||
const onEditSubscriptionsClick = useCallback(
|
onEditProfileClick = () => this.props.history.push(`${this.props.settings.homepage}/edit/${this.props.profile.userName}`);
|
||||||
() => console.log("Edit subscriptions onClick()"),
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
|
|
||||||
const onEditProfileClick = useCallback(
|
render() {
|
||||||
() => history.push(`${settings.homepage}/edit/${profile.userName}`),
|
const { profile, updateProfileCulture, settings, isAdmin, viewer, t } = this.props;
|
||||||
[history, settings.homepage, profile.userName]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
const contacts = profile.contacts && getUserContacts(profile.contacts);
|
||||||
<ProfileWrapper>
|
const role = getUserRole(profile);
|
||||||
<AvatarWrapper>
|
const socialContacts = (contacts && contacts.social && contacts.social.length > 0 && createContacts(contacts.social)) || null;
|
||||||
<Avatar
|
const infoContacts = contacts && createContacts(contacts.contact);
|
||||||
size="max"
|
const isSelf = isMe(viewer, profile.userName);
|
||||||
role={role}
|
|
||||||
source={profile.avatarMax}
|
return (
|
||||||
userName={profile.displayName}
|
<ProfileWrapper>
|
||||||
/>
|
<AvatarWrapper>
|
||||||
{(isAdmin || isSelf) && (
|
<Avatar
|
||||||
<EditButtonWrapper>
|
size="max"
|
||||||
<Button
|
role={role}
|
||||||
size="big"
|
source={profile.avatarMax}
|
||||||
scale={true}
|
userName={profile.displayName}
|
||||||
label={t("EditUserDialogTitle")}
|
/>
|
||||||
title={t("EditUserDialogTitle")}
|
{(isAdmin || isSelf) && (
|
||||||
onClick={onEditProfileClick}
|
<EditButtonWrapper>
|
||||||
/>
|
|
||||||
</EditButtonWrapper>
|
|
||||||
)}
|
|
||||||
</AvatarWrapper>
|
|
||||||
<ProfileInfo profile={profile} updateProfileCulture={updateProfileCulture} isSelf={isSelf} isAdmin={isAdmin} t={t} cultures={settings.cultures} culture={settings.culture} />
|
|
||||||
{isSelf && (
|
|
||||||
<ToggleWrapper isSelf={true} >
|
|
||||||
<ToggleContent label={t('Subscriptions')} isOpen={true} >
|
|
||||||
<Text.Body as="span">
|
|
||||||
<Button
|
<Button
|
||||||
size="big"
|
size="big"
|
||||||
label={t('EditSubscriptionsBtn')}
|
scale={true}
|
||||||
primary={true}
|
label={t("EditUserDialogTitle")}
|
||||||
onClick={onEditSubscriptionsClick}
|
title={t("EditUserDialogTitle")}
|
||||||
|
onClick={this.onEditProfileClick}
|
||||||
/>
|
/>
|
||||||
</Text.Body>
|
</EditButtonWrapper>
|
||||||
</ToggleContent>
|
)}
|
||||||
</ToggleWrapper>
|
</AvatarWrapper>
|
||||||
)}
|
<ProfileInfo profile={profile} updateProfileCulture={updateProfileCulture} isSelf={isSelf} isAdmin={isAdmin} t={t} cultures={settings.cultures} culture={settings.culture} />
|
||||||
{profile.notes && (
|
{isSelf && (
|
||||||
<ToggleWrapper>
|
<ToggleWrapper isSelf={true} >
|
||||||
<ToggleContent label={t('Comments')} isOpen={true} >
|
<ToggleContent label={t('Subscriptions')} isOpen={true} >
|
||||||
<Text.Body as="span">{profile.notes}</Text.Body>
|
<Text.Body as="span">
|
||||||
</ToggleContent>
|
<Button
|
||||||
</ToggleWrapper>
|
size="big"
|
||||||
)}
|
label={t('EditSubscriptionsBtn')}
|
||||||
{profile.contacts && (
|
primary={true}
|
||||||
<ToggleWrapper isContacts={true} >
|
onClick={this.onEditSubscriptionsClick}
|
||||||
<ToggleContent label={t('ContactInformation')} isOpen={true} >
|
/>
|
||||||
<Text.Body as="span">{infoContacts}</Text.Body>
|
</Text.Body>
|
||||||
</ToggleContent>
|
</ToggleContent>
|
||||||
</ToggleWrapper>
|
</ToggleWrapper>
|
||||||
)}
|
)}
|
||||||
{socialContacts && (
|
{profile.notes && (
|
||||||
<ToggleWrapper isContacts={true} >
|
<ToggleWrapper>
|
||||||
<ToggleContent label={t('SocialProfiles')} isOpen={true} >
|
<ToggleContent label={t('Comments')} isOpen={true} >
|
||||||
<Text.Body as="span">{socialContacts}</Text.Body>
|
<Text.Body as="span">{profile.notes}</Text.Body>
|
||||||
</ToggleContent>
|
</ToggleContent>
|
||||||
</ToggleWrapper>
|
</ToggleWrapper>
|
||||||
)}
|
)}
|
||||||
</ProfileWrapper>
|
{profile.contacts && (
|
||||||
);
|
<ToggleWrapper isContacts={true} >
|
||||||
};
|
<ToggleContent label={t('ContactInformation')} isOpen={true} >
|
||||||
|
<Text.Body as="span">{infoContacts}</Text.Body>
|
||||||
|
</ToggleContent>
|
||||||
|
</ToggleWrapper>
|
||||||
|
)}
|
||||||
|
{socialContacts && (
|
||||||
|
<ToggleWrapper isContacts={true} >
|
||||||
|
<ToggleContent label={t('SocialProfiles')} isOpen={true} >
|
||||||
|
<Text.Body as="span">{socialContacts}</Text.Body>
|
||||||
|
</ToggleContent>
|
||||||
|
</ToggleWrapper>
|
||||||
|
)}
|
||||||
|
</ProfileWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function mapStateToProps(state) {
|
const mapStateToProps = state => {
|
||||||
return {
|
return {
|
||||||
settings: state.auth.settings,
|
settings: state.auth.settings,
|
||||||
|
profile: state.profile.targetUser,
|
||||||
isAdmin: isAdmin(state.auth.user),
|
isAdmin: isAdmin(state.auth.user),
|
||||||
viewer: state.auth.user
|
viewer: state.auth.user
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(mapStateToProps, { updateProfileCulture })(withRouter(SectionBodyContent));
|
export default connect(mapStateToProps, { updateProfileCulture })(withRouter(withTranslation()(SectionBodyContent)));
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import React, { useCallback, useState } from "react";
|
import React from "react";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import {
|
import {
|
||||||
Text,
|
Text,
|
||||||
|
Link,
|
||||||
IconButton,
|
IconButton,
|
||||||
ContextMenuButton,
|
ContextMenuButton,
|
||||||
toastr,
|
toastr,
|
||||||
@ -13,13 +14,14 @@ import {
|
|||||||
} from "asc-web-components";
|
} from "asc-web-components";
|
||||||
import { withRouter } from "react-router";
|
import { withRouter } from "react-router";
|
||||||
import { isAdmin, isMe } from "../../../../../store/auth/selectors";
|
import { isAdmin, isMe } from "../../../../../store/auth/selectors";
|
||||||
import { getUserStatus } from "../../../../../store/people/selectors";
|
import { getUserStatus, toEmployeeWrapper } from "../../../../../store/people/selectors";
|
||||||
import { useTranslation } from 'react-i18next';
|
import { withTranslation } from 'react-i18next';
|
||||||
import { resendUserInvites } from "../../../../../store/services/api";
|
import { resendUserInvites } from "../../../../../store/services/api";
|
||||||
import { EmployeeStatus } from "../../../../../helpers/constants";
|
import { EmployeeStatus } from "../../../../../helpers/constants";
|
||||||
import { updateUserStatus } from "../../../../../store/people/actions";
|
import { updateUserStatus } from "../../../../../store/people/actions";
|
||||||
import { fetchProfile } from '../../../../../store/profile/actions';
|
import { fetchProfile } from '../../../../../store/profile/actions';
|
||||||
import {
|
import {
|
||||||
|
sendInstructionsToDelete,
|
||||||
sendInstructionsToChangePassword,
|
sendInstructionsToChangePassword,
|
||||||
sendInstructionsToChangeEmail,
|
sendInstructionsToChangeEmail,
|
||||||
createThumbnailsAvatar,
|
createThumbnailsAvatar,
|
||||||
@ -42,97 +44,128 @@ const Header = styled(Text.ContentHeader)`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const SectionHeaderContent = props => {
|
class SectionHeaderContent extends React.PureComponent {
|
||||||
const { profile, history, settings, isAdmin, viewer, updateUserStatus, fetchProfile } = props;
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
const [newEmailState, setNewEmail] = useState(profile.email);
|
this.state = this.mapPropsToState(props);
|
||||||
const [dialogState, setDialog] = useState(
|
}
|
||||||
{
|
|
||||||
visible: false,
|
|
||||||
header: "",
|
|
||||||
body: "",
|
|
||||||
buttons: [],
|
|
||||||
newEmail: profile.email,
|
|
||||||
});
|
|
||||||
const [avatarState, setAvatar] = useState(
|
|
||||||
{
|
|
||||||
tmpFile: "",
|
|
||||||
image: profile.avatarDefault ? "data:image/png;base64," + profile.avatarDefault : null,
|
|
||||||
defaultWidth: 0,
|
|
||||||
defaultHeight: 0
|
|
||||||
});
|
|
||||||
const [avatarEditorState, setAvatarEditorVisible] = useState(false);
|
|
||||||
|
|
||||||
const openAvatarEditor = () => {
|
componentDidUpdate(prevProps) {
|
||||||
let avatarDefault = profile.avatarDefault ? "data:image/png;base64," + profile.avatarDefault : null;
|
if (this.props.profile.userName !== prevProps.profile.userName) {
|
||||||
|
console.log(this.props.profile.userName);
|
||||||
|
this.setState(this.mapPropsToState(this.props));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mapPropsToState = props => {
|
||||||
|
let profile = toEmployeeWrapper(props.profile);
|
||||||
|
|
||||||
|
const newState = {
|
||||||
|
profile: profile,
|
||||||
|
visibleAvatarEditor: false,
|
||||||
|
dialog: {
|
||||||
|
visible: false,
|
||||||
|
header: "",
|
||||||
|
body: "",
|
||||||
|
buttons: [],
|
||||||
|
newEmail: profile.email,
|
||||||
|
},
|
||||||
|
avatar: {
|
||||||
|
tmpFile: "",
|
||||||
|
image: profile.avatarDefault ? "data:image/png;base64," + profile.avatarDefault : null,
|
||||||
|
defaultWidth: 0,
|
||||||
|
defaultHeight: 0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return newState;
|
||||||
|
}
|
||||||
|
|
||||||
|
openAvatarEditor = () => {
|
||||||
|
let avatarDefault = this.state.profile.avatarDefault ? "data:image/png;base64," + this.state.profile.avatarDefault : null;
|
||||||
|
let _this = this;
|
||||||
if (avatarDefault !== null) {
|
if (avatarDefault !== null) {
|
||||||
let img = new Image();
|
let img = new Image();
|
||||||
img.onload = function () {
|
img.onload = function () {
|
||||||
setAvatar({
|
_this.setState({
|
||||||
defaultWidth: img.width,
|
avatar: {
|
||||||
defaultHeight: img.height
|
defaultWidth: img.width,
|
||||||
|
defaultHeight: img.height
|
||||||
|
}
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
img.src = avatarDefault;
|
img.src = avatarDefault;
|
||||||
}
|
}
|
||||||
setAvatarEditorVisible(true);
|
this.setState({
|
||||||
|
visibleAvatarEditor: true,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const onLoadFileAvatar = (file) => {
|
onLoadFileAvatar = file => {
|
||||||
let data = new FormData();
|
let data = new FormData();
|
||||||
|
let _this = this;
|
||||||
data.append("file", file);
|
data.append("file", file);
|
||||||
data.append("Autosave", false);
|
data.append("Autosave", false);
|
||||||
loadAvatar(profile.id, data)
|
loadAvatar(this.state.profile.id, data)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
var img = new Image();
|
var img = new Image();
|
||||||
img.onload = function () {
|
img.onload = function () {
|
||||||
var stateCopy = Object.assign({}, avatarState);
|
var stateCopy = Object.assign({}, _this.state);
|
||||||
stateCopy = {
|
stateCopy.avatar = {
|
||||||
tmpFile: response.data,
|
tmpFile: response.data,
|
||||||
image: response.data,
|
image: response.data,
|
||||||
defaultWidth: img.width,
|
defaultWidth: img.width,
|
||||||
defaultHeight: img.height
|
defaultHeight: img.height
|
||||||
}
|
}
|
||||||
|
_this.setState(stateCopy);
|
||||||
setAvatar(stateCopy);
|
|
||||||
};
|
};
|
||||||
img.src = response.data;
|
img.src = response.data;
|
||||||
})
|
})
|
||||||
.catch((error) => toastr.error(error));
|
.catch((error) => toastr.error(error));
|
||||||
}
|
}
|
||||||
|
|
||||||
const onSaveAvatar = (isUpdate, result) => {
|
onSaveAvatar = (isUpdate, result) => {
|
||||||
if (isUpdate) {
|
if (isUpdate) {
|
||||||
createThumbnailsAvatar(profile.id, {
|
createThumbnailsAvatar(this.state.profile.id, {
|
||||||
x: Math.round(result.x * avatarState.defaultWidth - result.width / 2),
|
x: Math.round(result.x * this.state.avatar.defaultWidth - result.width / 2),
|
||||||
y: Math.round(result.y * avatarState.defaultHeight - result.height / 2),
|
y: Math.round(result.y * this.state.avatar.defaultHeight - result.height / 2),
|
||||||
width: result.width,
|
width: result.width,
|
||||||
height: result.height,
|
height: result.height,
|
||||||
tmpFile: avatarState.tmpFile
|
tmpFile: this.state.avatar.tmpFile
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
setAvatarEditorVisible(false);
|
let stateCopy = Object.assign({}, this.state);
|
||||||
setAvatar({ tmpFile: '' });
|
stateCopy.visibleAvatarEditor = false;
|
||||||
fetchProfile(profile.id);
|
stateCopy.avatar.tmpFile = '';
|
||||||
|
stateCopy.profile.avatarMax = response.max + '?_=' + Math.floor(Math.random() * Math.floor(10000));
|
||||||
toastr.success("Success");
|
toastr.success("Success");
|
||||||
|
this.setState(stateCopy);
|
||||||
})
|
})
|
||||||
.catch((error) => toastr.error(error));
|
.catch((error) => toastr.error(error))
|
||||||
|
.then(() => this.props.fetchProfile(this.state.profile.id));
|
||||||
} else {
|
} else {
|
||||||
deleteAvatar(profile.id)
|
deleteAvatar(this.state.profile.id)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
setAvatarEditorVisible(false);
|
let stateCopy = Object.assign({}, this.state);
|
||||||
fetchProfile(profile.id);
|
stateCopy.visibleAvatarEditor = false;
|
||||||
|
stateCopy.profile.avatarMax = response.big;
|
||||||
toastr.success("Success");
|
toastr.success("Success");
|
||||||
|
this.setState(stateCopy);
|
||||||
})
|
})
|
||||||
.catch((error) => toastr.error(error));
|
.catch((error) => toastr.error(error));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const onCloseAvatarEditor = () => setAvatarEditorVisible(false);
|
onCloseAvatarEditor = () => {
|
||||||
|
this.setState({
|
||||||
|
visibleAvatarEditor: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const onEmailChange = event => {
|
onEmailChange = event => {
|
||||||
const emailRegex = /.+@.+\..+/;
|
const emailRegex = /.+@.+\..+/;
|
||||||
const newEmail = (event && event.target.value) || newEmailState;
|
const newEmail = (event && event.target.value) || this.state.dialog.newEmail;
|
||||||
const hasError = !emailRegex.test(newEmail);
|
const hasError = !emailRegex.test(newEmail);
|
||||||
|
|
||||||
const dialog = {
|
const dialog = {
|
||||||
@ -146,7 +179,7 @@ const SectionHeaderContent = props => {
|
|||||||
scale={true}
|
scale={true}
|
||||||
isAutoFocussed={true}
|
isAutoFocussed={true}
|
||||||
value={newEmail}
|
value={newEmail}
|
||||||
onChange={onEmailChange}
|
onChange={this.onEmailChange}
|
||||||
hasError={hasError}
|
hasError={hasError}
|
||||||
/>
|
/>
|
||||||
</Text.Body>
|
</Text.Body>
|
||||||
@ -157,33 +190,32 @@ const SectionHeaderContent = props => {
|
|||||||
label="Send"
|
label="Send"
|
||||||
size="medium"
|
size="medium"
|
||||||
primary={true}
|
primary={true}
|
||||||
onClick={onSendEmailChangeInstructions}
|
onClick={this.onSendEmailChangeInstructions}
|
||||||
isDisabled={hasError}
|
isDisabled={hasError}
|
||||||
/>
|
/>
|
||||||
],
|
],
|
||||||
newEmail: newEmail
|
newEmail: newEmail
|
||||||
};
|
};
|
||||||
|
this.setState({ dialog: dialog })
|
||||||
setDialog(dialog);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const onSendEmailChangeInstructions = () => {
|
onSendEmailChangeInstructions = () => {
|
||||||
sendInstructionsToChangeEmail(profile.id, newEmailState)
|
sendInstructionsToChangeEmail(this.state.profile.id, this.state.dialog.newEmail)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
toastr.success(res);
|
toastr.success(res);
|
||||||
})
|
})
|
||||||
.catch((error) => toastr.error(error))
|
.catch((error) => toastr.error(error))
|
||||||
.finally(onDialogClose);
|
.finally(this.onDialogClose);
|
||||||
}
|
}
|
||||||
|
|
||||||
const onPasswordChange = () => {
|
onPasswordChange = () => {
|
||||||
const dialog = {
|
const dialog = {
|
||||||
visible: true,
|
visible: true,
|
||||||
header: "Change password",
|
header: "Change password",
|
||||||
body: (
|
body: (
|
||||||
<Text.Body>
|
<Text.Body>
|
||||||
Send the password change instructions to the <a href={`mailto:${profile.email}`}>{profile.email}</a> email address
|
Send the password change instructions to the <a href={`mailto:${this.state.profile.email}`}>{this.state.profile.email}</a> email address
|
||||||
</Text.Body>
|
</Text.Body>
|
||||||
),
|
),
|
||||||
buttons: [
|
buttons: [
|
||||||
<Button
|
<Button
|
||||||
@ -191,70 +223,119 @@ const SectionHeaderContent = props => {
|
|||||||
label="Send"
|
label="Send"
|
||||||
size="medium"
|
size="medium"
|
||||||
primary={true}
|
primary={true}
|
||||||
onClick={onSendPasswordChangeInstructions}
|
onClick={this.onSendPasswordChangeInstructions}
|
||||||
/>
|
/>
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
this.setState({ dialog: dialog })
|
||||||
setDialog(dialog);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const onSendPasswordChangeInstructions = () => {
|
onSendPasswordChangeInstructions = () => {
|
||||||
sendInstructionsToChangePassword(profile.email)
|
sendInstructionsToChangePassword(this.state.profile.email)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
toastr.success(res);
|
toastr.success(res);
|
||||||
})
|
})
|
||||||
.catch((error) => toastr.error(error))
|
.catch((error) => toastr.error(error))
|
||||||
.finally(onDialogClose);
|
.finally(this.onDialogClose);
|
||||||
}
|
}
|
||||||
|
|
||||||
const onDialogClose = () => {
|
onDialogClose = () => {
|
||||||
const dialog = { visible: false, newEmailState: profile.email };
|
const dialog = { visible: false, newEmail: this.state.profile.email };
|
||||||
setDialog(dialog);
|
this.setState({ dialog: dialog })
|
||||||
}
|
}
|
||||||
|
|
||||||
const selectedUserIds = new Array(profile.id);
|
onEditClick = () => {
|
||||||
|
const { history, settings } = this.props;
|
||||||
|
history.push(`${settings.homepage}/edit/${this.state.profile.userName}`);
|
||||||
|
}
|
||||||
|
|
||||||
const onEditClick = () => {
|
onUpdateUserStatus = (status, userId) => {
|
||||||
history.push(`${settings.homepage}/edit/${profile.userName}`);
|
const { fetchProfile, updateUserStatus } = this.props;
|
||||||
};
|
|
||||||
|
|
||||||
const onDisableClick = () => {
|
updateUserStatus(status, new Array(userId))
|
||||||
updateUserStatus(EmployeeStatus.Disabled, selectedUserIds)
|
.then(() => fetchProfile(userId));
|
||||||
.then(() => toastr.success(t("SuccessChangeUserStatus")))
|
}
|
||||||
.then(() => fetchProfile(profile.id));
|
|
||||||
};
|
|
||||||
|
|
||||||
const onEditPhoto = () => {
|
onDisableClick = () => this.onUpdateUserStatus(EmployeeStatus.Disabled, this.state.profile.id);
|
||||||
openAvatarEditor();
|
|
||||||
};
|
|
||||||
|
|
||||||
const onEnableClick = () => {
|
onEnableClick = () => this.onUpdateUserStatus(EmployeeStatus.Active, this.state.profile.id);
|
||||||
updateUserStatus(EmployeeStatus.Active, selectedUserIds)
|
|
||||||
.then(() => toastr.success(t("SuccessChangeUserStatus")))
|
|
||||||
.then(() => fetchProfile(profile.id));
|
|
||||||
};
|
|
||||||
|
|
||||||
const onReassignDataClick = user => {
|
onReassignDataClick = user => {
|
||||||
const { history, settings } = props;
|
const { history, settings } = this.props;
|
||||||
history.push(`${settings.homepage}/reassign/${user.userName}`);
|
history.push(`${settings.homepage}/reassign/${user.userName}`);
|
||||||
};
|
}
|
||||||
|
|
||||||
const onDeletePersonalDataClick = () => {
|
onDeletePersonalDataClick = () => {
|
||||||
toastr.success("Context action: Delete personal data");
|
toastr.success("Context action: Delete personal data");
|
||||||
};
|
}
|
||||||
|
|
||||||
const onDeleteProfileClick = () => {
|
onDeleteProfileClick = () => {
|
||||||
toastr.success("Context action: Delete profile");
|
toastr.success("Context action: Delete profile");
|
||||||
};
|
}
|
||||||
|
|
||||||
const onInviteAgainClick = () => {
|
onDeleteSelfProfileClick = email => {
|
||||||
resendUserInvites(selectedUserIds)
|
this.setState({
|
||||||
.then(() => toastr.success("The invitation was successfully sent"))
|
dialog: {
|
||||||
|
visible: true,
|
||||||
|
header: "Delete profile dialog",
|
||||||
|
body: (
|
||||||
|
<Text.Body>
|
||||||
|
Send the profile deletion instructions to the email address{" "}
|
||||||
|
<Link type="page" href={`mailto:${email}`} isHovered title={email}>
|
||||||
|
{email}
|
||||||
|
</Link>
|
||||||
|
</Text.Body>
|
||||||
|
),
|
||||||
|
buttons: [
|
||||||
|
<Button
|
||||||
|
key="OkBtn"
|
||||||
|
label="Send"
|
||||||
|
size="medium"
|
||||||
|
primary={true}
|
||||||
|
onClick={() => {
|
||||||
|
const { onLoading } = this.props;
|
||||||
|
onLoading(true);
|
||||||
|
sendInstructionsToDelete()
|
||||||
|
.then(() =>
|
||||||
|
toastr.success(
|
||||||
|
<Text.Body>
|
||||||
|
Instructions to delete your profile has been sent to{" "}
|
||||||
|
<b>{email}</b> email address
|
||||||
|
</Text.Body>
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.catch(error => toastr.error(error))
|
||||||
|
.finally(() => onLoading(false));
|
||||||
|
this.onDialogClose();
|
||||||
|
}}
|
||||||
|
/>,
|
||||||
|
<Button
|
||||||
|
key="CancelBtn"
|
||||||
|
label="Cancel"
|
||||||
|
size="medium"
|
||||||
|
primary={false}
|
||||||
|
onClick={this.onDialogClose}
|
||||||
|
style={{ marginLeft: "8px" }}
|
||||||
|
/>
|
||||||
|
]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onInviteAgainClick = () => {
|
||||||
|
resendUserInvites(new Array(this.state.profile.id))
|
||||||
|
.then(() => toastr.success(
|
||||||
|
<Text.Body>
|
||||||
|
The email activation instructions have been sent to the{" "}
|
||||||
|
<b>{this.state.profile.email}</b> email address
|
||||||
|
</Text.Body>
|
||||||
|
))
|
||||||
.catch(error => toastr.error(error));
|
.catch(error => toastr.error(error));
|
||||||
};
|
}
|
||||||
const getUserContextOptions = (user, viewer, t) => {
|
|
||||||
|
getUserContextOptions = (user, viewer) => {
|
||||||
let status = "";
|
let status = "";
|
||||||
|
const { t } = this.props;
|
||||||
|
|
||||||
if (isAdmin || (!isAdmin && isMe(user, viewer.userName))) {
|
if (isAdmin || (!isAdmin && isMe(user, viewer.userName))) {
|
||||||
status = getUserStatus(user);
|
status = getUserStatus(user);
|
||||||
@ -267,22 +348,22 @@ const SectionHeaderContent = props => {
|
|||||||
{
|
{
|
||||||
key: "edit",
|
key: "edit",
|
||||||
label: t('EditUserDialogTitle'),
|
label: t('EditUserDialogTitle'),
|
||||||
onClick: onEditClick
|
onClick: this.onEditClick
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "change-password",
|
key: "change-password",
|
||||||
label: t('PasswordChangeButton'),
|
label: t('PasswordChangeButton'),
|
||||||
onClick: onPasswordChange
|
onClick: this.onPasswordChange
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "change-email",
|
key: "change-email",
|
||||||
label: t('EmailChangeButton'),
|
label: t('EmailChangeButton'),
|
||||||
onClick: onEmailChange
|
onClick: this.onEmailChange
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "edit-photo",
|
key: "edit-photo",
|
||||||
label: t('EditPhoto'),
|
label: t('EditPhoto'),
|
||||||
onClick: onEditPhoto
|
onClick: this.openAvatarEditor
|
||||||
},
|
},
|
||||||
isMe(user, viewer.userName)
|
isMe(user, viewer.userName)
|
||||||
? viewer.isOwner
|
? viewer.isOwner
|
||||||
@ -290,12 +371,12 @@ const SectionHeaderContent = props => {
|
|||||||
: {
|
: {
|
||||||
key: "delete-profile",
|
key: "delete-profile",
|
||||||
label: t("DeleteSelfProfile"),
|
label: t("DeleteSelfProfile"),
|
||||||
onClick: onDeleteProfileClick
|
onClick: this.onDeleteSelfProfileClick.bind(this, user.email)
|
||||||
}
|
}
|
||||||
: {
|
: {
|
||||||
key: "disable",
|
key: "disable",
|
||||||
label: t("DisableUserButton"),
|
label: t("DisableUserButton"),
|
||||||
onClick: onDisableClick
|
onClick: this.onDisableClick
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
case "disabled":
|
case "disabled":
|
||||||
@ -303,27 +384,27 @@ const SectionHeaderContent = props => {
|
|||||||
{
|
{
|
||||||
key: "enable",
|
key: "enable",
|
||||||
label: t('EnableUserButton'),
|
label: t('EnableUserButton'),
|
||||||
onClick: onEnableClick
|
onClick: this.onEnableClick
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "edit-photo",
|
key: "edit-photo",
|
||||||
label: t('EditPhoto'),
|
label: t('EditPhoto'),
|
||||||
onClick: onEditPhoto
|
onClick: this.openAvatarEditor
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "reassign-data",
|
key: "reassign-data",
|
||||||
label: t('ReassignData'),
|
label: t('ReassignData'),
|
||||||
onClick: onReassignDataClick.bind(this, user)
|
onClick: this.onReassignDataClick.bind(this, user)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "delete-personal-data",
|
key: "delete-personal-data",
|
||||||
label: t('RemoveData'),
|
label: t('RemoveData'),
|
||||||
onClick: onDeletePersonalDataClick
|
onClick: this.onDeletePersonalDataClick
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "delete-profile",
|
key: "delete-profile",
|
||||||
label: t('DeleteSelfProfile'),
|
label: t('DeleteSelfProfile'),
|
||||||
onClick: onDeleteProfileClick
|
onClick: this.onDeleteProfileClick
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
case "pending":
|
case "pending":
|
||||||
@ -331,103 +412,107 @@ const SectionHeaderContent = props => {
|
|||||||
{
|
{
|
||||||
key: "edit",
|
key: "edit",
|
||||||
label: t('EditButton'),
|
label: t('EditButton'),
|
||||||
onClick: onEditClick
|
onClick: this.onEditClick
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "invite-again",
|
key: "invite-again",
|
||||||
label: t('InviteAgainLbl'),
|
label: t('InviteAgainLbl'),
|
||||||
onClick: onInviteAgainClick
|
onClick: this.onInviteAgainClick
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "edit-photo",
|
key: "edit-photo",
|
||||||
label: t('EditPhoto'),
|
label: t('EditPhoto'),
|
||||||
onClick: onEditPhoto
|
onClick: this.openAvatarEditor
|
||||||
},
|
},
|
||||||
!isMe(user, viewer.userName) &&
|
!isMe(user, viewer.userName) &&
|
||||||
(user.status === EmployeeStatus.Active
|
(user.status === EmployeeStatus.Active
|
||||||
? {
|
? {
|
||||||
key: "disable",
|
key: "disable",
|
||||||
label: t("DisableUserButton"),
|
label: t("DisableUserButton"),
|
||||||
onClick: onDisableClick
|
onClick: this.onDisableClick
|
||||||
}
|
}
|
||||||
: {
|
: {
|
||||||
key: "enable",
|
key: "enable",
|
||||||
label: t("EnableUserButton"),
|
label: t("EnableUserButton"),
|
||||||
onClick: onEnableClick
|
onClick: this.onEnableClick
|
||||||
}),
|
}),
|
||||||
isMe(user, viewer.userName) && {
|
isMe(user, viewer.userName) && {
|
||||||
key: "delete-profile",
|
key: "delete-profile",
|
||||||
label: t("DeleteSelfProfile"),
|
label: t("DeleteSelfProfile"),
|
||||||
onClick: onDeleteProfileClick
|
onClick: this.onDeleteSelfProfileClick.bind(this, user.email)
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
default:
|
default:
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
};
|
goBack = () => {
|
||||||
|
this.props.history.goBack();
|
||||||
|
}
|
||||||
|
|
||||||
const { t } = useTranslation();
|
render() {
|
||||||
const contextOptions = () => getUserContextOptions(profile, viewer, t);
|
const { profile, isAdmin, viewer, t } = this.props;
|
||||||
|
const { dialog, avatar, visibleAvatarEditor } = this.state;
|
||||||
|
|
||||||
const onClick = useCallback(() => {
|
const contextOptions = () => this.getUserContextOptions(profile, viewer);
|
||||||
history.goBack();
|
|
||||||
}, [history]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={wrapperStyle}>
|
<div style={wrapperStyle}>
|
||||||
<div style={{ width: "16px" }}>
|
<div style={{ width: "16px" }}>
|
||||||
<IconButton
|
<IconButton
|
||||||
iconName={"ArrowPathIcon"}
|
iconName={"ArrowPathIcon"}
|
||||||
color="#A3A9AE"
|
color="#A3A9AE"
|
||||||
size="16"
|
size="16"
|
||||||
onClick={onClick}
|
onClick={this.goBack}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Header truncate={true}>
|
||||||
|
{profile.displayName}
|
||||||
|
{profile.isLDAP && ` (${t('LDAPLbl')})`}
|
||||||
|
</Header>
|
||||||
|
{((isAdmin && !profile.isOwner) || isMe(viewer, profile.userName)) && (
|
||||||
|
<ContextMenuButton
|
||||||
|
directionX="right"
|
||||||
|
title={t('Actions')}
|
||||||
|
iconName="VerticalDotsIcon"
|
||||||
|
size={16}
|
||||||
|
color="#A3A9AE"
|
||||||
|
getData={contextOptions}
|
||||||
|
isDisabled={false}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<ModalDialog
|
||||||
|
visible={dialog.visible}
|
||||||
|
headerContent={dialog.header}
|
||||||
|
bodyContent={dialog.body}
|
||||||
|
footerContent={dialog.buttons}
|
||||||
|
onClose={this.onDialogClose}
|
||||||
|
/>
|
||||||
|
<AvatarEditor
|
||||||
|
image={avatar.image}
|
||||||
|
visible={visibleAvatarEditor}
|
||||||
|
onClose={this.onCloseAvatarEditor}
|
||||||
|
onSave={this.onSaveAvatar}
|
||||||
|
onLoadFile={this.onLoadFileAvatar}
|
||||||
|
headerLabel={t("editAvatar")}
|
||||||
|
chooseFileLabel={t("chooseFileLabel")}
|
||||||
|
unknownTypeError={t("unknownTypeError")}
|
||||||
|
maxSizeFileError={t("maxSizeFileError")}
|
||||||
|
unknownError={t("unknownError")}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Header truncate={true}>
|
);
|
||||||
{profile.displayName}
|
}
|
||||||
{profile.isLDAP && ` (${t('LDAPLbl')})`}
|
}
|
||||||
</Header>
|
|
||||||
{((isAdmin && !profile.isOwner) || isMe(viewer, profile.userName)) && (
|
|
||||||
<ContextMenuButton
|
|
||||||
directionX="right"
|
|
||||||
title={t('Actions')}
|
|
||||||
iconName="VerticalDotsIcon"
|
|
||||||
size={16}
|
|
||||||
color="#A3A9AE"
|
|
||||||
getData={contextOptions}
|
|
||||||
isDisabled={false}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<ModalDialog
|
|
||||||
visible={dialogState.visible}
|
|
||||||
headerContent={dialogState.header}
|
|
||||||
bodyContent={dialogState.body}
|
|
||||||
footerContent={dialogState.buttons}
|
|
||||||
onClose={onDialogClose}
|
|
||||||
/>
|
|
||||||
<AvatarEditor
|
|
||||||
image={avatarState.image}
|
|
||||||
visible={avatarEditorState}
|
|
||||||
onClose={onCloseAvatarEditor}
|
|
||||||
onSave={onSaveAvatar}
|
|
||||||
onLoadFile={onLoadFileAvatar}
|
|
||||||
headerLabel={t("editAvatar")}
|
|
||||||
chooseFileLabel={t("chooseFileLabel")}
|
|
||||||
unknownTypeError={t("unknownTypeError")}
|
|
||||||
maxSizeFileError={t("maxSizeFileError")}
|
|
||||||
unknownError={t("unknownError")}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
function mapStateToProps(state) {
|
const mapStateToProps = (state) => {
|
||||||
return {
|
return {
|
||||||
settings: state.auth.settings,
|
settings: state.auth.settings,
|
||||||
|
profile: state.profile.targetUser,
|
||||||
viewer: state.auth.user,
|
viewer: state.auth.user,
|
||||||
isAdmin: isAdmin(state.auth.user)
|
isAdmin: isAdmin(state.auth.user)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(mapStateToProps, { updateUserStatus, fetchProfile })(withRouter(SectionHeaderContent));
|
export default connect(mapStateToProps, { updateUserStatus, fetchProfile })(withRouter(withTranslation()(SectionHeaderContent)));
|
||||||
|
@ -20,9 +20,11 @@ class PureProfile extends React.Component {
|
|||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const { match, fetchProfile, t } = this.props;
|
const { match, fetchProfile, t } = this.props;
|
||||||
const { userId } = match.params;
|
const { userId } = match.params;
|
||||||
|
|
||||||
const queryParams = this.state.queryString.split('&');
|
const queryParams = this.state.queryString.split('&');
|
||||||
const arrayOfQueryParams = queryParams.map(queryParam => queryParam.split('='));
|
const arrayOfQueryParams = queryParams.map(queryParam => queryParam.split('='));
|
||||||
const linkParams = Object.fromEntries(arrayOfQueryParams);
|
const linkParams = Object.fromEntries(arrayOfQueryParams);
|
||||||
|
|
||||||
if (linkParams.email_change && linkParams.email_change === "success"){
|
if (linkParams.email_change && linkParams.email_change === "success"){
|
||||||
toastr.success(t('ChangeEmailSuccess'));
|
toastr.success(t('ChangeEmailSuccess'));
|
||||||
}
|
}
|
||||||
@ -35,13 +37,13 @@ class PureProfile extends React.Component {
|
|||||||
const { userId } = match.params;
|
const { userId } = match.params;
|
||||||
const prevUserId = prevProps.match.params.userId;
|
const prevUserId = prevProps.match.params.userId;
|
||||||
|
|
||||||
if (userId !== prevUserId) {
|
if (userId !== undefined && userId !== prevUserId) {
|
||||||
fetchProfile(userId);
|
fetchProfile(userId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
console.log("Profile render")
|
//console.log("Profile render")
|
||||||
|
|
||||||
const { profile, isVisitor } = this.props;
|
const { profile, isVisitor } = this.props;
|
||||||
|
|
||||||
@ -52,8 +54,8 @@ class PureProfile extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const sectionProps = profile ? {
|
const sectionProps = profile ? {
|
||||||
sectionHeaderContent: <SectionHeaderContent profile={profile} />,
|
sectionHeaderContent: <SectionHeaderContent />,
|
||||||
sectionBodyContent: <SectionBodyContent profile={profile} />
|
sectionBodyContent: <SectionBodyContent />
|
||||||
} : {
|
} : {
|
||||||
sectionBodyContent: <Loader className="pageLoader" type="rombs" size={40} />
|
sectionBodyContent: <Loader className="pageLoader" type="rombs" size={40} />
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user