Merge branch 'feature/loading-acceleration' of https://github.com/ONLYOFFICE/CommunityServer-AspNetCore into feature/loading-acceleration

This commit is contained in:
Nikita Gopienko 2020-10-05 14:01:39 +03:00
commit 53365f4c27
20 changed files with 1153 additions and 801 deletions

View File

@ -2,7 +2,14 @@ import React from "react";
import copy from "copy-to-clipboard";
import styled, { css } from "styled-components";
import { withRouter } from "react-router";
import { constants, Headline, store, api, toastr, Loaders } from "asc-web-common";
import {
constants,
Headline,
store,
api,
toastr,
Loaders,
} from "asc-web-common";
import { connect } from "react-redux";
import { withTranslation } from "react-i18next";
import {
@ -318,9 +325,7 @@ class SectionHeaderContent extends React.Component {
onBackToParentFolder = () => {
const { setIsLoading, parentId, filter, fetchFiles } = this.props;
setIsLoading(true);
fetchFiles(parentId, filter).finally(() =>
setIsLoading(false)
);
fetchFiles(parentId, filter).finally(() => setIsLoading(false));
};
onSelectorSelect = (item) => {
@ -345,7 +350,7 @@ class SectionHeaderContent extends React.Component {
onCheck,
title,
loopFilesOperations,
isCanCreate
isCanCreate,
} = this.props;
const {
@ -604,12 +609,7 @@ class SectionHeaderContent extends React.Component {
}
const mapStateToProps = (state) => {
const {
selectedFolder,
selection,
treeFolders,
filter,
} = state.files;
const { selectedFolder, selection, treeFolders, filter } = state.files;
const { parentId, title, id } = selectedFolder;
const { user } = state.auth;
@ -618,7 +618,7 @@ const mapStateToProps = (state) => {
return {
folder: parentId !== 0,
isAdmin: isAdmin(user),
isAdmin: isAdmin(state),
isRecycleBinFolder: checkFolderType(id, indexOfTrash, treeFolders),
parentId,
selection,
@ -635,5 +635,5 @@ export default connect(mapStateToProps, {
setProgressBarData,
setIsLoading,
clearProgressData,
fetchFiles
fetchFiles,
})(withTranslation()(withRouter(SectionHeaderContent)));

View File

@ -5,11 +5,11 @@ const { FileType, FilterType, FolderType } = constants;
const { isAdmin } = store.auth.selectors;
const presentInArray = (array, search) => {
const result = array.findIndex(item => item === search);
const result = array.findIndex((item) => item === search);
return result === -1 ? false : true;
};
export const canWebEdit = extension => {
export const canWebEdit = (extension) => {
const formats = [
".pptx",
".pptm",
@ -46,12 +46,12 @@ export const canWebEdit = extension => {
".rtf",
".mht",
".html",
".htm"
".htm",
];
return presentInArray(formats, extension);
};
export const canConvert = extension => {
export const canConvert = (extension) => {
const formats = [
".pptm",
".ppt",
@ -79,12 +79,12 @@ export const canConvert = extension => {
".odt",
".fodt",
".ott",
".rtf"
".rtf",
];
return presentInArray(formats, extension);
};
export const isArchive = extension => {
export const isArchive = (extension) => {
const formats = [
".zip",
".rar",
@ -108,12 +108,12 @@ export const isArchive = extension => {
".uue",
".xxe",
".z",
".zoo"
".zoo",
];
return presentInArray(formats, extension);
};
export const isImage = extension => {
export const isImage = (extension) => {
const formats = [
".bmp",
".cod",
@ -134,12 +134,12 @@ export const isImage = extension => {
".xwd",
".png",
".ai",
".jpeg"
".jpeg",
];
return presentInArray(formats, extension);
};
export const isSound = extension => {
export const isSound = (extension) => {
const formats = [
".aac",
".ac3",
@ -159,12 +159,12 @@ export const isSound = extension => {
".ra",
".raw",
".wav",
".wma"
".wma",
];
return presentInArray(formats, extension);
};
export const isVideo = extension => {
export const isVideo = (extension) => {
const formats = [
".3gp",
".asf",
@ -184,22 +184,22 @@ export const isVideo = extension => {
".svi",
".vob",
".webm",
".wmv"
".wmv",
];
return presentInArray(formats, extension);
};
export const isHtml = extension => {
export const isHtml = (extension) => {
const formats = [".htm", ".mht", ".html"];
return presentInArray(formats, extension);
};
export const isEbook = extension => {
export const isEbook = (extension) => {
const formats = [".fb2", ".ibk", ".prc", ".epub"];
return presentInArray(formats, extension);
};
export const isDocument = extension => {
export const isDocument = (extension) => {
const formats = [
".doc",
".docx",
@ -222,12 +222,12 @@ export const isDocument = extension => {
".xps",
".doct",
".docy",
".gdoc"
".gdoc",
];
return presentInArray(formats, extension);
};
export const isPresentation = extension => {
export const isPresentation = (extension) => {
const formats = [
".pps",
".ppsx",
@ -243,12 +243,12 @@ export const isPresentation = extension => {
".otp",
".pptt",
".ppty",
".gslides"
".gslides",
];
return presentInArray(formats, extension);
};
export const isSpreadsheet = extension => {
export const isSpreadsheet = (extension) => {
const formats = [
".xls",
".xlsx",
@ -263,7 +263,7 @@ export const isSpreadsheet = extension => {
".xlst",
".xlsy",
".xlsb",
".gsheet"
".gsheet",
];
return presentInArray(formats, extension);
};
@ -286,7 +286,7 @@ export function skipFile(selection, fileId) {
export function getFilesBySelected(files, selected) {
let newSelection = [];
files.forEach(file => {
files.forEach((file) => {
const checked = getFilesChecked(file, selected);
if (checked) newSelection.push(file);
@ -321,12 +321,9 @@ const getFilesChecked = (file, selected) => {
}
};
export const getTitleWithoutExst = item => {
export const getTitleWithoutExst = (item) => {
return item.fileExst
? item.title
.split(".")
.slice(0, -1)
.join(".")
? item.title.split(".").slice(0, -1).join(".")
: item.title;
};
@ -339,16 +336,16 @@ export const createTreeFolders = (pathParts, filterData) => {
}
if (treeFolders.length > 0) {
treeFolders = treeFolders.concat(
filterData.treeFolders.filter(x => !treeFolders.includes(x))
filterData.treeFolders.filter((x) => !treeFolders.includes(x))
);
}
return treeFolders;
};
const renameTreeFolder = (folders, newItems, currentFolder) => {
const newItem = folders.find(x => x.id === currentFolder.id);
const newItem = folders.find((x) => x.id === currentFolder.id);
const oldItemIndex = newItems.folders.findIndex(
x => x.id === currentFolder.id
(x) => x.id === currentFolder.id
);
newItem.folders = newItems.folders[oldItemIndex].folders;
newItems.folders[oldItemIndex] = newItem;
@ -361,11 +358,11 @@ const removeTreeFolder = (folders, newItems, foldersCount) => {
for (let folder of newFolders) {
let currentFolder;
if (folders) {
currentFolder = folders.find(x => x.id === folder.id);
currentFolder = folders.find((x) => x.id === folder.id);
}
if (!currentFolder) {
const arrayFolders = newItems.folders.filter(x => x.id !== folder.id);
const arrayFolders = newItems.folders.filter((x) => x.id !== folder.id);
newItems.folders = arrayFolders;
newItems.foldersCount = foldersCount;
}
@ -378,7 +375,7 @@ const addTreeFolder = (folders, newItems, foldersCount) => {
for (let folder of folders) {
let currentFolder;
if (newItemFolders) {
currentFolder = newItemFolders.find(x => x.id === folder.id);
currentFolder = newItemFolders.find((x) => x.id === folder.id);
}
if (folders.length < 1 || !currentFolder) {
@ -401,7 +398,7 @@ export const loopTreeFolders = (
) => {
const newPath = path;
while (path.length !== 0) {
const newItems = item.find(x => x.id === path[0]);
const newItems = item.find((x) => x.id === path[0]);
if (!newItems) {
return;
}
@ -433,7 +430,7 @@ export const loopTreeFolders = (
export const isCanCreate = (selectedFolder, user) => {
if (!selectedFolder || !selectedFolder.id) return false;
const admin = isAdmin(user);
const admin = isAdmin({ auth: { user } }); //TODO: Need refactoring
const rootFolderType = selectedFolder.rootFolderType;
switch (rootFolderType) {
@ -453,7 +450,7 @@ export const isCanCreate = (selectedFolder, user) => {
};
export const isCanBeDeleted = (selectedFolder, user) => {
const admin = isAdmin(user);
const admin = isAdmin({ auth: { user } }); //TODO: Need refactoring
const rootFolderType = selectedFolder.rootFolderType;
switch (rootFolderType) {
@ -471,13 +468,13 @@ export const isCanBeDeleted = (selectedFolder, user) => {
};
//TODO: Get the whole list of extensions
export const getAccessOption = selection => {
const isFolder = selection.find(x => x.fileExst === undefined);
export const getAccessOption = (selection) => {
const isFolder = selection.find((x) => x.fileExst === undefined);
const isMedia = selection.find(
x => isSound(x.fileExst) || isVideo(x.fileExst)
(x) => isSound(x.fileExst) || isVideo(x.fileExst)
);
const isPresentationOrTable = selection.find(
x => isSpreadsheet(x.fileExst) || isPresentation(x.fileExst)
(x) => isSpreadsheet(x.fileExst) || isPresentation(x.fileExst)
);
if (isFolder || isMedia) {
@ -491,7 +488,7 @@ export const getAccessOption = selection => {
"DenyAccess",
"Comment",
"Review",
"FormFilling"
"FormFilling",
];
}
};

View File

@ -227,7 +227,7 @@ function mapStateToProps(state) {
? [state.people.selectedGroup]
: ["root"],
groups,
isAdmin: isAdmin(state.auth.user),
isAdmin: isAdmin(state),
isLoaded,
};
}

View File

@ -8,21 +8,27 @@ import {
Text,
ToggleContent,
Checkbox,
CustomScrollbarsVirtualList
CustomScrollbarsVirtualList,
} from "asc-web-components";
import { FixedSizeList as List, areEqual } from "react-window";
import AutoSizer from "react-virtualized-auto-sizer";
import { withTranslation } from "react-i18next";
import { utils, toastr } from "asc-web-common";
import { utils, toastr, constants } from "asc-web-common";
import ModalDialogContainer from "../ModalDialogContainer";
import { updateUserStatus } from "../../../store/people/actions";
import { updateUserStatus, setSelected } from "../../../store/people/actions";
import { createI18N } from "../../../helpers/i18n";
import {
getActiveUsersIds,
getDisableUsersIds,
} from "../../../store/people/selectors";
const i18n = createI18N({
page: "ChangeUserStatusDialog",
localesPath: "dialogs/ChangeUserStatusDialog"
localesPath: "dialogs/ChangeUserStatusDialog",
});
const { EmployeeStatus } = constants;
const { changeLanguage } = utils;
class ChangeUserStatusDialogComponent extends React.Component {
@ -34,11 +40,11 @@ class ChangeUserStatusDialogComponent extends React.Component {
changeLanguage(i18n);
const listUsers = selectedUsers.map((item, index) => {
const disabled = userIds.find(x => x === item.id);
const disabled = userIds.find((x) => x === item.id);
return (selectedUsers[index] = {
...selectedUsers[index],
checked: disabled ? true : false,
disabled: disabled ? false : true
disabled: disabled ? false : true,
});
});
@ -51,13 +57,13 @@ class ChangeUserStatusDialogComponent extends React.Component {
userStatus,
t,
setSelected,
onClose
onClose,
} = this.props;
const { userIds } = this.state;
this.setState({ isRequestRunning: true }, () => {
updateUserStatus(userStatus, userIds, true)
.then(() => toastr.success(t("SuccessChangeUserStatus")))
.catch(error => toastr.error(error))
.catch((error) => toastr.error(error))
.finally(() => {
this.setState({ isRequestRunning: false }, () => {
setSelected("close");
@ -67,9 +73,9 @@ class ChangeUserStatusDialogComponent extends React.Component {
});
};
onChange = e => {
onChange = (e) => {
const { listUsers } = this.state;
const userIndex = listUsers.findIndex(x => x.id === e.target.value);
const userIndex = listUsers.findIndex((x) => x.id === e.target.value);
const newUsersList = listUsers;
newUsersList[userIndex].checked = !newUsersList[userIndex].checked;
@ -137,7 +143,7 @@ class ChangeUserStatusDialogComponent extends React.Component {
<Text>
{t("ChangeUserStatusDialog", {
status: statusTranslation,
userStatus: userStatusTranslation
userStatus: userStatusTranslation,
})}
</Text>
<Text>{t("ChangeUserStatusDialogMessage")}</Text>
@ -177,7 +183,7 @@ const ChangeUserStatusDialogTranslated = withTranslation()(
ChangeUserStatusDialogComponent
);
const ChangeUserStatusDialog = props => (
const ChangeUserStatusDialog = (props) => (
<ChangeUserStatusDialogTranslated i18n={i18n} {...props} />
);
@ -186,10 +192,22 @@ ChangeUserStatusDialog.propTypes = {
onClose: PropTypes.func.isRequired,
setSelected: PropTypes.func.isRequired,
userIds: PropTypes.arrayOf(PropTypes.string).isRequired,
selectedUsers: PropTypes.arrayOf(PropTypes.object).isRequired
selectedUsers: PropTypes.arrayOf(PropTypes.object).isRequired,
};
export default connect(
null,
{ updateUserStatus }
)(withRouter(ChangeUserStatusDialog));
const mapStateToProps = (state, ownProps) => {
const { selection } = state.people;
const { userType } = ownProps;
return {
userIds:
userType === EmployeeStatus.Active
? getActiveUsersIds(state)
: getDisableUsersIds(state),
selectedUsers: selection,
};
};
export default connect(mapStateToProps, { updateUserStatus, setSelected })(
withRouter(ChangeUserStatusDialog)
);

View File

@ -8,21 +8,24 @@ import {
Text,
ToggleContent,
Checkbox,
CustomScrollbarsVirtualList
CustomScrollbarsVirtualList,
} from "asc-web-components";
import { withTranslation } from "react-i18next";
import { FixedSizeList as List, areEqual } from "react-window";
import AutoSizer from "react-virtualized-auto-sizer";
import { utils, toastr } from "asc-web-common";
import { utils, toastr, constants } from "asc-web-common";
import ModalDialogContainer from "../ModalDialogContainer";
import { updateUserType } from "../../../store/people/actions";
import { updateUserType, setSelected } from "../../../store/people/actions";
import { createI18N } from "../../../helpers/i18n";
import { getEmployeesIds, getGuestsIds } from "../../../store/people/selectors";
const i18n = createI18N({
page: "ChangeUserTypeDialog",
localesPath: "dialogs/ChangeUserTypeDialog"
localesPath: "dialogs/ChangeUserTypeDialog",
});
const { EmployeeType } = constants;
const { changeLanguage } = utils;
class ChangeUserTypeDialogComponent extends React.Component {
@ -34,20 +37,20 @@ class ChangeUserTypeDialogComponent extends React.Component {
const { selectedUsers, userIds } = props;
const listUsers = selectedUsers.map((item, index) => {
const disabled = userIds.find(x => x === item.id);
const disabled = userIds.find((x) => x === item.id);
return (selectedUsers[index] = {
...selectedUsers[index],
checked: disabled ? true : false,
disabled: disabled ? false : true
disabled: disabled ? false : true,
});
});
this.state = { isRequestRunning: false, userIds, listUsers };
}
onChange = e => {
onChange = (e) => {
const { listUsers } = this.state;
const userIndex = listUsers.findIndex(x => x.id === e.target.value);
const userIndex = listUsers.findIndex((x) => x.id === e.target.value);
const newUsersList = listUsers;
newUsersList[userIndex].checked = !newUsersList[userIndex].checked;
@ -67,7 +70,7 @@ class ChangeUserTypeDialogComponent extends React.Component {
this.setState({ isRequestRunning: true }, () => {
updateUserType(userType, userIds)
.then(() => toastr.success(t("SuccessChangeUserType")))
.catch(error => toastr.error(error))
.catch((error) => toastr.error(error))
.finally(() => {
this.setState({ isRequestRunning: false }, () => {
setSelected("close");
@ -123,7 +126,7 @@ class ChangeUserTypeDialogComponent extends React.Component {
<Text>
{t("ChangeUserTypeMessage", {
firstType: firstType,
secondType: secondType
secondType: secondType,
})}
</Text>
<Text>{t("ChangeUserTypeMessageWarning")}</Text>
@ -164,7 +167,7 @@ const ChangeUserTypeDialogTranslated = withTranslation()(
ChangeUserTypeDialogComponent
);
const ChangeUserTypeDialog = props => (
const ChangeUserTypeDialog = (props) => (
<ChangeUserTypeDialogTranslated i18n={i18n} {...props} />
);
@ -173,10 +176,22 @@ ChangeUserTypeDialog.propTypes = {
onClose: PropTypes.func.isRequired,
setSelected: PropTypes.func.isRequired,
userIds: PropTypes.arrayOf(PropTypes.string).isRequired,
selectedUsers: PropTypes.arrayOf(PropTypes.object).isRequired
selectedUsers: PropTypes.arrayOf(PropTypes.object).isRequired,
};
export default connect(
null,
{ updateUserType }
)(withRouter(ChangeUserTypeDialog));
const mapStateToProps = (state, ownProps) => {
const { selection } = state.people;
const { userType } = ownProps;
return {
userIds:
userType === EmployeeType.User
? getEmployeesIds(state)
: getGuestsIds(state),
selectedUsers: selection,
};
};
export default connect(mapStateToProps, { updateUserType, setSelected })(
withRouter(ChangeUserTypeDialog)
);

View File

@ -8,18 +8,19 @@ import {
Text,
ToggleContent,
Checkbox,
CustomScrollbarsVirtualList
CustomScrollbarsVirtualList,
} from "asc-web-components";
import { FixedSizeList as List, areEqual } from "react-window";
import AutoSizer from "react-virtualized-auto-sizer";
import { withTranslation } from "react-i18next";
import { api, utils, toastr } from "asc-web-common";
import { removeUser } from "../../../store/people/actions";
import { removeUser, setSelected } from "../../../store/people/actions";
import ModalDialogContainer from "../ModalDialogContainer";
import { createI18N } from "../../../helpers/i18n";
import { getDeleteUsersIds } from "../../../store/people/selectors";
const i18n = createI18N({
page: "DeleteUsersDialog",
localesPath: "dialogs/DeleteUsersDialog"
localesPath: "dialogs/DeleteUsersDialog",
});
const { Filter } = api;
@ -34,11 +35,11 @@ class DeleteGroupUsersDialogComponent extends React.Component {
const { selectedUsers, userIds } = props;
const listUsers = selectedUsers.map((item, index) => {
const disabled = userIds.find(x => x === item.id);
const disabled = userIds.find((x) => x === item.id);
return (selectedUsers[index] = {
...selectedUsers[index],
checked: disabled ? true : false,
disabled: disabled ? false : true
disabled: disabled ? false : true,
});
});
@ -54,7 +55,7 @@ class DeleteGroupUsersDialogComponent extends React.Component {
.then(() => {
toastr.success(t("DeleteGroupUsersSuccessMessage"));
})
.catch(error => toastr.error(error))
.catch((error) => toastr.error(error))
.finally(() => {
this.setState({ isRequestRunning: false }, () => {
setSelected("close");
@ -64,9 +65,9 @@ class DeleteGroupUsersDialogComponent extends React.Component {
});
};
onChange = e => {
onChange = (e) => {
const userIndex = this.state.listUsers.findIndex(
x => x.id === e.target.value
(x) => x.id === e.target.value
);
const newUsersList = this.state.listUsers;
newUsersList[userIndex].checked = !newUsersList[userIndex].checked;
@ -170,21 +171,34 @@ const DeleteGroupUsersDialogTranslated = withTranslation()(
DeleteGroupUsersDialogComponent
);
const DeleteUsersDialog = props => (
const DeleteUsersDialog = (props) => (
<DeleteGroupUsersDialogTranslated i18n={i18n} {...props} />
);
DeleteUsersDialog.propTypes = {
visible: PropTypes.bool.isRequired,
onClose: PropTypes.func.isRequired,
setSelected: PropTypes.func.isRequired,
selectedUsers: PropTypes.arrayOf(PropTypes.object).isRequired,
userIds: PropTypes.arrayOf(PropTypes.string).isRequired,
filter: PropTypes.instanceOf(Filter).isRequired,
removeUser: PropTypes.func.isRequired
setSelected: PropTypes.func.isRequired,
removeUser: PropTypes.func.isRequired,
};
export default connect(
null,
{ removeUser }
)(withRouter(DeleteUsersDialog));
const mapStateToProps = (state) => {
const { filter, selection } = state.people;
const deleteUsersIds = getDeleteUsersIds(state);
return {
filter,
userIds: deleteUsersIds,
selectedUsers: selection,
};
};
export default connect(mapStateToProps, { removeUser, setSelected })(
withRouter(DeleteUsersDialog)
);

View File

@ -7,7 +7,7 @@ import {
Text,
ToggleContent,
Checkbox,
CustomScrollbarsVirtualList
CustomScrollbarsVirtualList,
} from "asc-web-components";
import { FixedSizeList as List, areEqual } from "react-window";
import AutoSizer from "react-virtualized-auto-sizer";
@ -15,9 +15,13 @@ import { withTranslation } from "react-i18next";
import { api, utils, toastr } from "asc-web-common";
import ModalDialogContainer from "../ModalDialogContainer";
import { createI18N } from "../../../helpers/i18n";
import { connect } from "react-redux";
import { getInactiveUsersIds } from "../../../store/people/selectors";
import { setSelected } from "../../../store/people/actions";
const i18n = createI18N({
page: "SendInviteDialog",
localesPath: "dialogs/SendInviteDialog"
localesPath: "dialogs/SendInviteDialog",
});
const { resendUserInvites } = api.people;
const { changeLanguage } = utils;
@ -31,18 +35,18 @@ class SendInviteDialogComponent extends React.Component {
const { userIds, selectedUsers } = props;
const listUsers = selectedUsers.map((item, index) => {
const disabled = userIds.find(x => x === item.id);
const disabled = userIds.find((x) => x === item.id);
return (selectedUsers[index] = {
...selectedUsers[index],
checked: disabled ? true : false,
disabled: disabled ? false : true
disabled: disabled ? false : true,
});
});
this.state = {
listUsers,
isRequestRunning: false,
userIds
userIds,
};
}
@ -53,7 +57,7 @@ class SendInviteDialogComponent extends React.Component {
this.setState({ isRequestRunning: true }, () => {
resendUserInvites(userIds)
.then(() => toastr.success(t("SuccessSendInvitation")))
.catch(error => toastr.error(error))
.catch((error) => toastr.error(error))
.finally(() => {
this.setState({ isRequestRunning: false }, () => {
setSelected("close");
@ -63,9 +67,9 @@ class SendInviteDialogComponent extends React.Component {
});
};
onChange = e => {
onChange = (e) => {
const userIndex = this.state.listUsers.findIndex(
x => x.id === e.target.value
(x) => x.id === e.target.value
);
const newUsersList = this.state.listUsers;
newUsersList[userIndex].checked = !newUsersList[userIndex].checked;
@ -159,7 +163,7 @@ class SendInviteDialogComponent extends React.Component {
const SendInviteDialogTranslated = withTranslation()(SendInviteDialogComponent);
const SendInviteDialog = props => (
const SendInviteDialog = (props) => (
<SendInviteDialogTranslated i18n={i18n} {...props} />
);
@ -168,7 +172,19 @@ SendInviteDialog.propTypes = {
onClose: PropTypes.func.isRequired,
userIds: PropTypes.arrayOf(PropTypes.string).isRequired,
selectedUsers: PropTypes.arrayOf(PropTypes.object).isRequired,
setSelected: PropTypes.func.isRequired
setSelected: PropTypes.func.isRequired,
};
export default withRouter(SendInviteDialog);
const mapStateToProps = (state) => {
const { selection } = state.people;
const inactiveUsersIds = getInactiveUsersIds(state);
return {
userIds: inactiveUsersIds,
selectedUsers: selection,
};
};
export default connect(mapStateToProps, { setSelected })(
withRouter(SendInviteDialog)
);

View File

@ -117,7 +117,7 @@ function mapStateToProps(state) {
return {
settings: state.auth.settings,
group: state.group.targetGroup,
isAdmin: isAdmin(state.auth.user),
isAdmin: isAdmin(state),
};
}

View File

@ -21,12 +21,8 @@ import {
fetchPeople,
selectGroup,
} from "../../../../../store/people/actions";
import {
isUserSelected,
getUserStatus,
getUserRole,
} from "../../../../../store/people/selectors";
import { isMobileOnly } from "react-device-detect";
import { getPeopleList } from "../../../../../store/people/selectors";
import isEqual from "lodash/isEqual";
import { store, api, constants, toastr, Loaders } from "asc-web-common";
import {
@ -41,7 +37,7 @@ const i18n = createI18N({
localesPath: "pages/Home",
});
const { isArrayEqual } = utils.array;
const { isAdmin, isMe } = store.auth.selectors;
const { getCurrentUser, getSettings } = store.auth.selectors;
const { resendUserInvites } = api.people;
const { EmployeeStatus } = constants;
const { Filter } = api;
@ -63,9 +59,9 @@ class SectionBodyContent extends React.PureComponent {
}
componentDidMount() {
const { users, fetchPeople } = this.props;
const { isUsersLoaded, fetchPeople } = this.props;
if (users != null) return;
if (isUsersLoaded) return;
const filter = Filter.getDefault();
filter.employeeStatus = EmployeeStatus.Active;
@ -73,45 +69,26 @@ class SectionBodyContent extends React.PureComponent {
fetchPeople(filter).catch((error) => toastr.error(error));
}
onEmailSentClick = (email) => {
window.open("mailto:" + email);
findUserById = (id) => this.props.peopleList.find((man) => man.id === id);
onEmailSentClick = (e) => {
const user = this.findUserById(e.currentTarget.dataset.id);
window.open("mailto:" + user.email);
};
onSendMessageClick = (mobilePhone) => {
window.open(`sms:${mobilePhone}`);
onSendMessageClick = (e) => {
const user = this.findUserById(e.currentTarget.dataset.id);
window.open(`sms:${user.mobilePhone}`);
};
onEditClick = (user) => {
onEditClick = (e) => {
const { history, settings } = this.props;
const user = this.findUserById(e.currentTarget.dataset.id);
history.push(`${settings.homepage}/edit/${user.userName}`);
};
toggleChangePasswordDialog = (email) => {
const checkedEmail = typeof email === "string" ? email : undefined;
this.setState({
dialogsVisible: {
...this.state.dialogsVisible,
changePassword: !this.state.dialogsVisible.changePassword,
},
user: { email: checkedEmail },
});
};
toggleChangeEmailDialog = (user) => {
const checkedUser = user ? user : {};
this.setState({
dialogsVisible: {
...this.state.dialogsVisible,
changeEmail: !this.state.dialogsVisible.changeEmail,
},
user: {
email: checkedUser.email,
id: checkedUser.id,
},
});
};
onDisableClick = (user) => {
onDisableClick = (e) => {
const user = this.findUserById(e.currentTarget.dataset.id);
const { updateUserStatus, onLoading, t } = this.props;
onLoading(true);
@ -121,7 +98,8 @@ class SectionBodyContent extends React.PureComponent {
.finally(() => onLoading(false));
};
onEnableClick = (user) => {
onEnableClick = (e) => {
const user = this.findUserById(e.currentTarget.dataset.id);
const { updateUserStatus, onLoading, t } = this.props;
onLoading(true);
@ -131,42 +109,99 @@ class SectionBodyContent extends React.PureComponent {
.finally(() => onLoading(false));
};
onReassignDataClick = (user) => {
onReassignDataClick = (e) => {
const user = this.findUserById(e.currentTarget.dataset.id);
const { history, settings } = this.props;
history.push(`${settings.homepage}/reassign/${user.userName}`);
};
onDeletePersonalDataClick = (user) => {
onDeletePersonalDataClick = (e) => {
//const user = this.findUserById(e.currentTarget.dataset.id);
toastr.success("Context action: Delete personal data");
};
toggleDeleteProfileEverDialog = (user) => {
const checkedUser = user ? user : {};
onCloseDialog = () => {
this.setState({
dialogsVisible: {
...this.state.dialogsVisible,
deleteProfileEver: !this.state.dialogsVisible.deleteProfileEver,
changeEmail: false,
changePassword: false,
deleteSelfProfile: false,
deleteProfileEver: false,
},
});
};
toggleChangeEmailDialog = (e) => {
const user = this.findUserById(e.currentTarget.dataset.id);
if (!user) return;
const { id, email } = user;
this.setState({
dialogsVisible: {
changeEmail: true,
},
user: {
id: checkedUser.id,
displayName: checkedUser.displayName,
userName: checkedUser.userName,
email,
id,
},
});
};
toggleDeleteSelfProfileDialog = (email) => {
const checkedEmail = typeof email === "string" ? email : undefined;
toggleChangePasswordDialog = (e) => {
const user = this.findUserById(e.currentTarget.dataset.id);
if (!user) return;
const { email } = user;
this.setState({
dialogsVisible: {
...this.state.dialogsVisible,
deleteSelfProfile: !this.state.dialogsVisible.deleteSelfProfile,
changePassword: true,
},
user: { email: checkedEmail },
user: { email },
});
};
onInviteAgainClick = (user) => {
toggleDeleteSelfProfileDialog = (e) => {
this.onCloseDialog();
const user = this.findUserById(e.currentTarget.dataset.id);
if (!user) return;
const { email } = user;
this.setState({
dialogsVisible: {
deleteSelfProfile: true,
},
user: { email },
});
};
toggleDeleteProfileEverDialog = (e) => {
this.onCloseDialog();
const user = this.findUserById(e.currentTarget.dataset.id);
if (!user) return;
const { id, displayName, userName } = user;
this.setState({
dialogsVisible: {
deleteProfileEver: true,
},
user: {
id,
displayName,
userName,
},
});
};
onInviteAgainClick = (e) => {
const user = this.findUserById(e.currentTarget.dataset.id);
const { onLoading } = this.props;
onLoading(true);
resendUserInvites([user.id])
@ -184,123 +219,104 @@ class SectionBodyContent extends React.PureComponent {
.catch((error) => toastr.error(error))
.finally(() => onLoading(false));
};
getUserContextOptions = (user, viewer) => {
let status = "";
getUserContextOptions = (options, id) => {
const { t } = this.props;
const isViewerAdmin = isAdmin(viewer);
const isSelf = isMe(user, viewer.userName);
if (isViewerAdmin || (!isViewerAdmin && isSelf)) {
status = getUserStatus(user);
}
//console.log("getUserContextOptions", user, viewer, status);
switch (status) {
case "normal":
case "unknown":
return [
{
key: "send-email",
return options.map((option) => {
switch (option) {
case "send-email":
return {
key: option,
label: t("LblSendEmail"),
onClick: this.onEmailSentClick.bind(this, user.email),
},
user.mobilePhone &&
isMobileOnly && {
key: "send-message",
label: t("LblSendMessage"),
onClick: this.onSendMessageClick.bind(this, user.mobilePhone),
},
{ key: "separator", isSeparator: true },
{
key: "edit",
"data-id": id,
onClick: this.onEmailSentClick,
};
case "send-message":
return {
key: option,
label: t("LblSendMessage"),
"data-id": id,
onClick: this.onSendMessageClick,
};
case "separator":
return { key: option, isSeparator: true };
case "edit":
return {
key: option,
label: t("EditButton"),
onClick: this.onEditClick.bind(this, user),
},
{
key: "change-password",
"data-id": id,
onClick: this.onEditClick,
};
case "change-password":
return {
key: option,
label: t("PasswordChangeButton"),
onClick: this.toggleChangePasswordDialog.bind(this, user.email),
},
{
key: "change-email",
"data-id": id,
onClick: this.toggleChangePasswordDialog,
};
case "change-email":
return {
key: option,
label: t("EmailChangeButton"),
onClick: this.toggleChangeEmailDialog.bind(this, user),
},
isSelf
? viewer.isOwner
? null
: {
key: "delete-profile",
label: t("DeleteSelfProfile"),
onClick: this.toggleDeleteSelfProfileDialog.bind(
this,
user.email
),
}
: {
key: "disable",
label: t("DisableUserButton"),
onClick: this.onDisableClick.bind(this, user),
},
];
case "disabled":
return [
{
key: "enable",
"data-id": id,
onClick: this.toggleChangeEmailDialog,
};
case "delete-self-profile":
return {
key: option,
label: t("DeleteSelfProfile"),
"data-id": id,
onClick: this.toggleDeleteSelfProfileDialog,
};
case "disable":
return {
key: option,
label: t("DisableUserButton"),
"data-id": id,
onClick: this.onDisableClick,
};
case "enable":
return {
key: option,
label: t("EnableUserButton"),
onClick: this.onEnableClick.bind(this, user),
},
{
key: "reassign-data",
"data-id": id,
onClick: this.onEnableClick,
};
case "reassign-data":
return {
key: option,
label: t("ReassignData"),
onClick: this.onReassignDataClick.bind(this, user),
},
{
key: "delete-personal-data",
"data-id": id,
onClick: this.onReassignDataClick,
};
case "delete-personal-data":
return {
key: option,
label: t("RemoveData"),
onClick: this.onDeletePersonalDataClick.bind(this, user),
},
{
key: "delete-profile",
"data-id": id,
onClick: this.onDeletePersonalDataClick,
};
case "delete-profile":
return {
key: option,
label: t("DeleteSelfProfile"),
onClick: this.toggleDeleteProfileEverDialog.bind(this, user),
},
];
case "pending":
return [
{
key: "edit",
label: t("EditButton"),
onClick: this.onEditClick.bind(this, user),
},
{
key: "invite-again",
"data-id": id,
onClick: this.toggleDeleteProfileEverDialog,
};
case "invite-again":
return {
key: option,
label: t("LblInviteAgain"),
onClick: this.onInviteAgainClick.bind(this, user),
},
!isSelf &&
(user.status === EmployeeStatus.Active
? {
key: "disable",
label: t("DisableUserButton"),
onClick: this.onDisableClick.bind(this, user),
}
: {
key: "enable",
label: t("EnableUserButton"),
onClick: this.onEnableClick.bind(this, user),
}),
isSelf && {
key: "delete-profile",
label: t("DeleteSelfProfile"),
onClick: this.toggleDeleteSelfProfileDialog.bind(this, user.email),
},
];
default:
return [];
}
"data-id": id,
onClick: this.onInviteAgainClick,
};
default:
break;
}
return undefined;
});
};
onContentRowSelect = (checked, user) => {
@ -337,47 +353,56 @@ class SectionBodyContent extends React.PureComponent {
render() {
//console.log("Home SectionBodyContent render()");
const {
users,
viewer,
selection,
isUsersLoaded,
peopleList,
history,
settings,
t,
filter,
widthProp,
isMobile,
selectGroup,
} = this.props;
const { dialogsVisible, user } = this.state;
return users == null ? (
return !isUsersLoaded ? (
<Loaders.Rows />
) : users.length > 0 ? (
) : peopleList.length > 0 ? (
<>
<RowContainer useReactWindow={false}>
{users.map((user) => {
const contextOptions = this.getUserContextOptions(
user,
viewer
).filter((o) => o);
const contextOptionsProps = !contextOptions.length
? {}
: { contextOptions };
const checked = isUserSelected(selection, user.id);
const checkedProps = isAdmin(viewer) ? { checked } : {};
{peopleList.map((man) => {
const {
checked,
role,
displayName,
avatar,
id,
status,
options,
} = man;
const contextOptionsProps =
options && options.length > 0
? { contextOptions: this.getUserContextOptions(options, id) }
: {};
const checkedProps = checked !== null ? { checked } : {};
const element = (
<Avatar
size="small"
role={getUserRole(user)}
userName={user.displayName}
source={user.avatar}
role={role}
userName={displayName}
source={avatar}
/>
);
return (
<Row
key={user.id}
status={getUserStatus(user)}
data={user}
key={id}
status={status}
data={man}
element={element}
onSelect={this.onContentRowSelect}
{...checkedProps}
@ -388,10 +413,10 @@ class SectionBodyContent extends React.PureComponent {
<UserContent
isMobile={isMobile}
widthProp={widthProp}
user={user}
user={man}
history={history}
settings={settings}
selectGroup={this.props.selectGroup}
selectGroup={selectGroup}
/>
</Row>
);
@ -401,14 +426,14 @@ class SectionBodyContent extends React.PureComponent {
{dialogsVisible.changeEmail && (
<ChangeEmailDialog
visible={dialogsVisible.changeEmail}
onClose={this.toggleChangeEmailDialog}
onClose={this.onCloseDialog}
user={user}
/>
)}
{dialogsVisible.changePassword && (
<ChangePasswordDialog
visible={dialogsVisible.changePassword}
onClose={this.toggleChangePasswordDialog}
onClose={this.onCloseDialog}
email={user.email}
/>
)}
@ -416,7 +441,7 @@ class SectionBodyContent extends React.PureComponent {
{dialogsVisible.deleteSelfProfile && (
<DeleteSelfProfileDialog
visible={dialogsVisible.deleteSelfProfile}
onClose={this.toggleDeleteSelfProfileDialog}
onClose={this.onCloseDialog}
email={user.email}
/>
)}
@ -424,7 +449,7 @@ class SectionBodyContent extends React.PureComponent {
{dialogsVisible.deleteProfileEver && (
<DeleteProfileEverDialog
visible={dialogsVisible.deleteProfileEver}
onClose={this.toggleDeleteProfileEverDialog}
onClose={this.onCloseDialog}
user={user}
filter={filter}
settings={settings}
@ -452,18 +477,13 @@ class SectionBodyContent extends React.PureComponent {
}
}
SectionBodyContent.defaultProps = {
users: null,
};
const mapStateToProps = (state) => {
const { users, filter } = state.people;
return {
selection: state.people.selection,
selected: state.people.selected,
users: state.people.users,
viewer: state.auth.user,
settings: state.auth.settings,
filter: state.people.filter,
isUsersLoaded: users !== null,
filter,
peopleList: getPeopleList(state),
settings: getSettings(state),
};
};

View File

@ -6,13 +6,13 @@ import result from "lodash/result";
import { withTranslation } from "react-i18next";
import { withRouter } from "react-router";
import { getFilterByLocation } from "../../../../../helpers/converters";
import { store, FilterInput } from 'asc-web-common';
import { isMobileOnly } from 'react-device-detect';
import { store, FilterInput } from "asc-web-common";
import { isMobileOnly } from "react-device-detect";
const { isAdmin } = store.auth.selectors;
const getEmployeeStatus = filterValues => {
const getEmployeeStatus = (filterValues) => {
const employeeStatus = result(
find(filterValues, value => {
find(filterValues, (value) => {
return value.group === "filter-status";
}),
"key"
@ -21,9 +21,9 @@ const getEmployeeStatus = filterValues => {
return employeeStatus ? +employeeStatus : null;
};
const getActivationStatus = filterValues => {
const getActivationStatus = (filterValues) => {
const activationStatus = result(
find(filterValues, value => {
find(filterValues, (value) => {
return value.group === "filter-email";
}),
"key"
@ -32,9 +32,9 @@ const getActivationStatus = filterValues => {
return activationStatus ? +activationStatus : null;
};
const getRole = filterValues => {
const getRole = (filterValues) => {
const employeeStatus = result(
find(filterValues, value => {
find(filterValues, (value) => {
return value.group === "filter-type";
}),
"key"
@ -43,9 +43,9 @@ const getRole = filterValues => {
return employeeStatus || null;
};
const getGroup = filterValues => {
const getGroup = (filterValues) => {
const groupId = result(
find(filterValues, value => {
find(filterValues, (value) => {
return value.group === "filter-group";
}),
"key"
@ -66,7 +66,7 @@ class SectionFilterContent extends React.Component {
fetchPeople(newFilter).finally(() => onLoading(false));
}
onFilter = data => {
onFilter = (data) => {
const { onLoading, fetchPeople, filter } = this.props;
const employeeStatus = getEmployeeStatus(data.filterValues);
@ -93,36 +93,36 @@ class SectionFilterContent extends React.Component {
};
getData = () => {
const { user, groups, t, settings } = this.props;
const { groups, t, settings, isAdmin } = this.props;
const { guestCaption, userCaption, groupCaption } = settings.customNames;
const options = !isAdmin(user)
const options = !isAdmin
? []
: [
{
key: "filter-status",
group: "filter-status",
label: t("UserStatus"),
isHeader: true
},
{
key: "1",
group: "filter-status",
label: t("LblActive")
},
{
key: "2",
group: "filter-status",
label: t("LblTerminated")
}
];
{
key: "filter-status",
group: "filter-status",
label: t("UserStatus"),
isHeader: true,
},
{
key: "1",
group: "filter-status",
label: t("LblActive"),
},
{
key: "2",
group: "filter-status",
label: t("LblTerminated"),
},
];
const groupOptions = groups.map(group => {
const groupOptions = groups.map((group) => {
return {
key: group.id,
inSubgroup: true,
group: "filter-group",
label: group.name
label: group.name,
};
});
@ -132,49 +132,49 @@ class SectionFilterContent extends React.Component {
key: "filter-email",
group: "filter-email",
label: t("Email"),
isHeader: true
isHeader: true,
},
{
key: "1",
group: "filter-email",
label: t("LblActive")
label: t("LblActive"),
},
{
key: "2",
group: "filter-email",
label: t("LblPending")
label: t("LblPending"),
},
{
key: "filter-type",
group: "filter-type",
label: t("UserType"),
isHeader: true
isHeader: true,
},
{ key: "admin", group: "filter-type", label: t("Administrator") },
{
key: "user",
group: "filter-type",
label: userCaption
label: userCaption,
},
{
key: "guest",
group: "filter-type",
label: guestCaption
label: guestCaption,
},
{
key: "filter-other",
group: "filter-other",
label: t("LblOther"),
isHeader: true
isHeader: true,
},
{
key: "filter-type-group",
group: "filter-other",
subgroup: "filter-group",
label: groupCaption,
defaultSelectLabel: t("LblSelect")
defaultSelectLabel: t("LblSelect"),
},
...groupOptions
...groupOptions,
];
//console.log("getData (filterOptions)", filterOptions);
@ -187,7 +187,7 @@ class SectionFilterContent extends React.Component {
return [
{ key: "firstname", label: t("ByFirstNameSorting"), default: true },
{ key: "lastname", label: t("ByLastNameSorting"), default: true }
{ key: "lastname", label: t("ByLastNameSorting"), default: true },
];
};
@ -196,7 +196,7 @@ class SectionFilterContent extends React.Component {
const selectedFilterData = {
filterValues: [],
sortDirection: filter.sortOrder === "ascending" ? "asc" : "desc",
sortId: filter.sortBy
sortId: filter.sortBy,
};
selectedFilterData.inputValue = filter.search;
@ -204,28 +204,28 @@ class SectionFilterContent extends React.Component {
if (filter.employeeStatus) {
selectedFilterData.filterValues.push({
key: `${filter.employeeStatus}`,
group: "filter-status"
group: "filter-status",
});
}
if (filter.activationStatus) {
selectedFilterData.filterValues.push({
key: `${filter.activationStatus}`,
group: "filter-email"
group: "filter-email",
});
}
if (filter.role) {
selectedFilterData.filterValues.push({
key: filter.role,
group: "filter-type"
group: "filter-type",
});
}
if (filter.group) {
selectedFilterData.filterValues.push({
key: filter.group,
group: "filter-group"
group: "filter-group",
});
}
@ -239,7 +239,6 @@ class SectionFilterContent extends React.Component {
return false;
};
render() {
const selectedFilterData = this.getSelectedFilterData();
const { t, i18n } = this.props;
@ -266,11 +265,11 @@ function mapStateToProps(state) {
user: state.auth.user,
groups: state.people.groups,
filter: state.people.filter,
settings: state.auth.settings
settings: state.auth.settings,
isAdmin: isAdmin(state),
};
}
export default connect(
mapStateToProps,
{ fetchPeople }
)(withRouter(withTranslation()(SectionFilterContent)));
export default connect(mapStateToProps, { fetchPeople })(
withRouter(withTranslation()(SectionFilterContent))
);

View File

@ -1,4 +1,4 @@
import React, { useCallback, useState } from "react";
import React, { useCallback, useState, useMemo } from "react";
import styled, { css } from "styled-components";
import { withRouter } from "react-router";
import {
@ -11,11 +11,13 @@ import { Headline, toastr, Loaders } from "asc-web-common";
import { connect } from "react-redux";
import {
getSelectedGroup,
getUserType,
getUsersStatus,
getInactiveUsers,
getDeleteUsers,
getUsersIds,
isEmployeesSelected,
isGuestsSelected,
isActiveSelected,
isDisableSelected,
isInactiveSelected,
isDeleteSelected,
isAnythingSelected,
} from "../../../../../store/people/selectors";
import { withTranslation } from "react-i18next";
import {
@ -93,13 +95,13 @@ const StyledContainer = styled.div`
`;
const SectionHeaderContent = (props) => {
const [dialogVisible, setDialogVisible] = useState(false);
const [showDeleteDialog, setDeleteDialog] = useState(false);
const [showSendInviteDialog, setSendInviteDialog] = useState(false);
const [showDisableDialog, setShowDisableDialog] = useState(false);
const [showActiveDialog, setShowActiveDialog] = useState(false);
const [showGuestDialog, setShowGuestDialog] = useState(false);
const [showEmployeeDialog, setShowEmployeeDialog] = useState(false);
const [invitationDialogVisible, setInvitationDialogVisible] = useState(false);
const [deleteDialogVisible, setDeleteDialogVisible] = useState(false);
const [sendInviteDialogVisible, setSendInviteDialogVisible] = useState(false);
const [disableDialogVisible, setDisableDialogVisible] = useState(false);
const [activeDialogVisible, setActiveDialogVisible] = useState(false);
const [guestDialogVisible, setGuestDialogVisible] = useState(false);
const [employeeDialogVisible, setEmployeeDialogVisible] = useState(false);
const {
isHeaderVisible,
@ -111,50 +113,64 @@ const SectionHeaderContent = (props) => {
group,
isAdmin,
t,
filter,
history,
settings,
customNames,
homepage,
deleteGroup,
usersWithEmployeeType,
usersWithGuestType,
usersWithActiveStatus,
usersWithDisableStatus,
usersToInvite,
usersToRemove,
setSelected,
selection,
isAnythingSelected,
isEmployeesSelected,
isGuestsSelected,
isActiveSelected,
isDisableSelected,
isInactiveSelected,
isDeleteSelected,
isLoaded,
} = props;
const {
userCaption,
guestCaption,
groupCaption,
groupsCaption,
} = customNames;
//console.log("SectionHeaderContent render");
const onSetEmployee = useCallback(
() => setShowEmployeeDialog(!showEmployeeDialog),
[showEmployeeDialog]
const toggleEmployeeDialog = useCallback(
() => setEmployeeDialogVisible(!employeeDialogVisible),
[employeeDialogVisible]
);
const onSetGuest = useCallback(() => setShowGuestDialog(!showGuestDialog), [
showGuestDialog,
]);
const onSetActive = useCallback(
() => setShowActiveDialog(!showActiveDialog),
[showActiveDialog]
const toggleGuestDialog = useCallback(
() => setGuestDialogVisible(!guestDialogVisible),
[guestDialogVisible]
);
const onSetDisabled = useCallback(
() => setShowDisableDialog(!showDisableDialog),
[showDisableDialog]
const toggleActiveDialog = useCallback(
() => setActiveDialogVisible(!activeDialogVisible),
[activeDialogVisible]
);
const onSendInviteAgain = useCallback(
() => setSendInviteDialog(!showSendInviteDialog),
[showSendInviteDialog]
const toggleDisableDialog = useCallback(
() => setDisableDialogVisible(!disableDialogVisible),
[disableDialogVisible]
);
const onDelete = useCallback(() => setDeleteDialog(!showDeleteDialog), [
showDeleteDialog,
]);
const toggleSendInviteDialog = useCallback(
() => setSendInviteDialogVisible(!sendInviteDialogVisible),
[sendInviteDialogVisible]
);
const toggleDeleteDialog = useCallback(
() => setDeleteDialogVisible(!deleteDialogVisible),
[deleteDialogVisible]
);
const onSendEmail = useCallback(() => {
let str = "";
@ -171,68 +187,90 @@ const SectionHeaderContent = (props) => {
[onSelect]
);
const menuItems = [
{
label: t("LblSelect"),
isDropdown: true,
isSeparator: true,
isSelect: true,
fontWeight: "bold",
children: [
<DropDownItem key="active" label={t("LblActive")} data-index={0} />,
<DropDownItem
key="disabled"
label={t("LblTerminated")}
data-index={1}
/>,
<DropDownItem key="invited" label={t("LblInvited")} data-index={2} />,
],
onSelect: onSelectorSelect,
},
{
label: t("ChangeToUser", {
userCaption: settings.customNames.userCaption,
}),
disabled: !usersWithEmployeeType.length,
onClick: onSetEmployee,
},
{
label: t("ChangeToGuest", {
guestCaption: settings.customNames.guestCaption,
}),
disabled: !usersWithGuestType.length,
onClick: onSetGuest,
},
{
label: t("LblSetActive"),
disabled: !usersWithActiveStatus.length,
onClick: onSetActive,
},
{
label: t("LblSetDisabled"),
disabled: !usersWithDisableStatus.length,
onClick: onSetDisabled,
},
{
label: t("LblInviteAgain"),
disabled: !usersToInvite.length,
onClick: onSendInviteAgain,
},
{
label: t("LblSendEmail"),
disabled: !selection.length,
onClick: onSendEmail,
},
{
label: t("DeleteButton"),
disabled: !usersToRemove.length,
onClick: onDelete,
},
];
const menuItems = useMemo(
() => [
{
label: t("LblSelect"),
isDropdown: true,
isSeparator: true,
isSelect: true,
fontWeight: "bold",
children: [
<DropDownItem key="active" label={t("LblActive")} data-index={0} />,
<DropDownItem
key="disabled"
label={t("LblTerminated")}
data-index={1}
/>,
<DropDownItem key="invited" label={t("LblInvited")} data-index={2} />,
],
onSelect: onSelectorSelect,
},
{
label: t("ChangeToUser", {
userCaption,
}),
disabled: !isEmployeesSelected,
onClick: toggleEmployeeDialog,
},
{
label: t("ChangeToGuest", {
guestCaption,
}),
disabled: !isGuestsSelected,
onClick: toggleGuestDialog,
},
{
label: t("LblSetActive"),
disabled: !isActiveSelected,
onClick: toggleActiveDialog,
},
{
label: t("LblSetDisabled"),
disabled: !isDisableSelected,
onClick: toggleDisableDialog,
},
{
label: t("LblInviteAgain"),
disabled: !isInactiveSelected,
onClick: toggleSendInviteDialog,
},
{
label: t("LblSendEmail"),
disabled: !isAnythingSelected,
onClick: onSendEmail,
},
{
label: t("DeleteButton"),
disabled: !isDeleteSelected,
onClick: toggleDeleteDialog,
},
],
[
t,
userCaption,
guestCaption,
onSelectorSelect,
toggleEmployeeDialog,
toggleGuestDialog,
toggleActiveDialog,
toggleDisableDialog,
toggleSendInviteDialog,
onSendEmail,
toggleDeleteDialog,
isAnythingSelected,
isEmployeesSelected,
isGuestsSelected,
isActiveSelected,
isDisableSelected,
isInactiveSelected,
isDeleteSelected,
]
);
const onEditGroup = useCallback(
() => history.push(`${settings.homepage}/group/edit/${group.id}`),
[history, settings, group]
() => history.push(`${homepage}/group/edit/${group.id}`),
[history, homepage, group]
);
const onDeleteGroup = useCallback(() => {
@ -257,24 +295,23 @@ const SectionHeaderContent = (props) => {
}, [t, onEditGroup, onDeleteGroup]);
const goToEmployeeCreate = useCallback(() => {
history.push(`${settings.homepage}/create/user`);
}, [history, settings]);
history.push(`${homepage}/create/user`);
}, [history, homepage]);
const goToGuestCreate = useCallback(() => {
history.push(`${settings.homepage}/create/guest`);
}, [history, settings]);
history.push(`${homepage}/create/guest`);
}, [history, homepage]);
const goToGroupCreate = useCallback(() => {
history.push(`${settings.homepage}/group/create`);
}, [history, settings]);
history.push(`${homepage}/group/create`);
}, [history, homepage]);
const onInvitationDialogClick = useCallback(
() => setDialogVisible(!dialogVisible),
[dialogVisible]
() => setInvitationDialogVisible(!invitationDialogVisible),
[invitationDialogVisible]
);
const getContextOptionsPlus = useCallback(() => {
const { guestCaption, userCaption, groupCaption } = settings.customNames;
return [
{
key: "new-employee",
@ -304,7 +341,9 @@ const SectionHeaderContent = (props) => {
} */,
];
}, [
settings,
userCaption,
guestCaption,
groupCaption,
t,
goToEmployeeCreate,
goToGuestCreate,
@ -319,66 +358,46 @@ const SectionHeaderContent = (props) => {
isHeaderVisible={isHeaderVisible}
isArticlePinned={isArticlePinned}
>
{showEmployeeDialog && (
{employeeDialogVisible && (
<ChangeUserTypeDialog
visible={showEmployeeDialog}
userIds={getUsersIds(usersWithEmployeeType)}
selectedUsers={selection}
onClose={onSetEmployee}
visible={employeeDialogVisible}
onClose={toggleEmployeeDialog}
userType={EmployeeType.User}
setSelected={setSelected}
/>
)}
{showGuestDialog && (
{guestDialogVisible && (
<ChangeUserTypeDialog
visible={showGuestDialog}
userIds={getUsersIds(usersWithGuestType)}
selectedUsers={selection}
onClose={onSetGuest}
onClose={toggleGuestDialog}
userType={EmployeeType.Guest}
setSelected={setSelected}
/>
)}
{showActiveDialog && (
{activeDialogVisible && (
<ChangeUserStatusDialog
visible={showActiveDialog}
userIds={getUsersIds(usersWithActiveStatus)}
selectedUsers={selection}
onClose={onSetActive}
visible={activeDialogVisible}
onClose={toggleActiveDialog}
userStatus={EmployeeStatus.Active}
setSelected={setSelected}
/>
)}
{showDisableDialog && (
{disableDialogVisible && (
<ChangeUserStatusDialog
visible={showDisableDialog}
userIds={getUsersIds(usersWithDisableStatus)}
selectedUsers={selection}
onClose={onSetDisabled}
visible={disableDialogVisible}
onClose={toggleDisableDialog}
userStatus={EmployeeStatus.Disabled}
setSelected={setSelected}
/>
)}
{showSendInviteDialog && (
{sendInviteDialogVisible && (
<SendInviteDialog
visible={showSendInviteDialog}
onClose={onSendInviteAgain}
userIds={getUsersIds(usersToInvite)}
selectedUsers={selection}
setSelected={setSelected}
visible={sendInviteDialogVisible}
onClose={toggleSendInviteDialog}
/>
)}
{showDeleteDialog && (
{deleteDialogVisible && (
<DeleteUsersDialog
visible={showDeleteDialog}
onClose={onDelete}
userIds={getUsersIds(usersToRemove)}
selectedUsers={selection}
filter={filter}
setSelected={setSelected}
visible={deleteDialogVisible}
onClose={toggleDeleteDialog}
/>
)}
@ -429,7 +448,7 @@ const SectionHeaderContent = (props) => {
truncate={true}
type="content"
>
{settings.customNames.groupsCaption}
{groupsCaption}
</Headline>
{isAdmin && (
<>
@ -443,9 +462,9 @@ const SectionHeaderContent = (props) => {
getData={getContextOptionsPlus}
isDisabled={false}
/>
{dialogVisible && (
{invitationDialogVisible && (
<InviteDialog
visible={dialogVisible}
visible={invitationDialogVisible}
onClose={onInvitationDialogClick}
onCloseButton={onInvitationDialogClick}
/>
@ -461,40 +480,25 @@ const SectionHeaderContent = (props) => {
};
const mapStateToProps = (state) => {
const { isLoaded, settings, user } = state.auth;
const { filter, groups, selection, selectedGroup } = state.people;
const activeUsers = 1;
const disabledUsers = 2;
const currentUserId = user && user.id;
const employeeStatus = true;
const guestStatus = false;
const { isLoaded, settings } = state.auth;
const { groups, selection, selectedGroup } = state.people;
const { homepage, customNames } = settings;
return {
group: getSelectedGroup(groups, selectedGroup),
isAdmin: isAdmin(state),
homepage,
customNames,
selection,
isAdmin: isAdmin(user),
filter,
settings: settings,
usersWithEmployeeType: getUserType(
selection,
employeeStatus,
currentUserId
),
usersWithGuestType: getUserType(selection, guestStatus, currentUserId),
usersWithActiveStatus: getUsersStatus(
selection,
activeUsers,
currentUserId
),
usersWithDisableStatus: getUsersStatus(
selection,
disabledUsers,
currentUserId
),
usersToInvite: getInactiveUsers(selection),
usersToRemove: getDeleteUsers(selection),
isAnythingSelected: isAnythingSelected(state),
isEmployeesSelected: isEmployeesSelected(state),
isGuestsSelected: isGuestsSelected(state),
isActiveSelected: isActiveSelected(state),
isDisableSelected: isDisableSelected(state),
isInactiveSelected: isInactiveSelected(state),
isDeleteSelected: isDeleteSelected(state),
isLoaded,
};
};

View File

@ -100,7 +100,9 @@ class PureHome extends React.Component {
isHeaderChecked,
selected,
} = this.state;
const { isAdmin } = this.props;
return (
<>
{/* <RequestLoader
@ -183,6 +185,7 @@ Home.propTypes = {
};
function mapStateToProps(state) {
const { isLoaded, settings } = state.auth;
const { users, selection, selected, selectedGroup, groups } = state.people;
return {
users,
@ -190,9 +193,9 @@ function mapStateToProps(state) {
selected,
selectedGroup,
groups,
isLoaded: state.auth.isLoaded,
organizationName: state.auth.settings.organizationName,
isAdmin: isAdmin(state.auth.user),
isLoaded,
organizationName: settings.organizationName,
isAdmin: isAdmin(state),
};
}

View File

@ -4,18 +4,21 @@ import {
IconButton,
Text,
ToggleContent,
Link
Link,
} from "asc-web-components";
import { getUserContacts, getUserRole } from "../../../../../store/people/selectors";
import {
getUserContacts,
getUserRole,
} from "../../../../../store/people/selectors";
import ProfileInfo from "./ProfileInfo/ProfileInfo";
import React from "react";
import { connect } from "react-redux";
import { store } from 'asc-web-common';
import styled from 'styled-components';
import { store } from "asc-web-common";
import styled from "styled-components";
import { updateProfileCulture } from "../../../../../store/profile/actions";
import { withRouter } from "react-router";
import { withTranslation } from 'react-i18next';
import { withTranslation } from "react-i18next";
const { isAdmin, isMe } = store.auth.selectors;
@ -43,8 +46,8 @@ const EditButtonWrapper = styled.div`
const ToggleWrapper = styled.div`
width: 100%;
min-width: 100%;
${props => props.isSelf && `margin-bottom: 24px;`}
${props => props.isContacts && `margin-top: 24px;`}
${(props) => props.isSelf && `margin-bottom: 24px;`}
${(props) => props.isContacts && `margin-top: 24px;`}
max-width: 1024px;
`;
@ -62,7 +65,7 @@ const ContactWrapper = styled.div`
}
`;
const createContacts = contacts => {
const createContacts = (contacts) => {
const styledContacts = contacts.map((contact, index) => {
let url = null;
if (contact.link && contact.link.length > 0) {
@ -70,12 +73,14 @@ const createContacts = contacts => {
}
return (
<ContactWrapper key={index}>
<IconButton className='icon-button' color="#333333" size={16} iconName={contact.icon} isFill={true} />
<Link
className='contact-link'
isTextOverflow
href={url}
>
<IconButton
className="icon-button"
color="#333333"
size={16}
iconName={contact.icon}
isFill={true}
/>
<Link className="contact-link" isTextOverflow href={url}>
{contact.value}
</Link>
</ContactWrapper>
@ -85,20 +90,35 @@ const createContacts = contacts => {
return styledContacts;
};
const stringFormat = (string, data) => string.replace(/\{(\d+)\}/g, (m, n) => data[n] || m);
const stringFormat = (string, data) =>
string.replace(/\{(\d+)\}/g, (m, n) => data[n] || m);
class SectionBodyContent extends React.PureComponent {
onEditSubscriptionsClick = () => console.log("Edit subscriptions onClick()");
onEditProfileClick = () => this.props.history.push(`${this.props.settings.homepage}/edit/${this.props.profile.userName}`);
onEditProfileClick = () =>
this.props.history.push(
`${this.props.settings.homepage}/edit/${this.props.profile.userName}`
);
render() {
const { profile, updateProfileCulture, settings, isAdmin, viewer, t } = this.props;
const {
profile,
updateProfileCulture,
settings,
isAdmin,
viewer,
t,
} = this.props;
const contacts = profile.contacts && getUserContacts(profile.contacts);
const role = getUserRole(profile);
const socialContacts = (contacts && contacts.social && contacts.social.length > 0 && createContacts(contacts.social)) || null;
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);
@ -123,14 +143,22 @@ class SectionBodyContent extends React.PureComponent {
</EditButtonWrapper>
)}
</AvatarWrapper>
<ProfileInfo profile={profile} updateProfileCulture={updateProfileCulture} isSelf={isSelf} isAdmin={isAdmin} t={t} cultures={settings.cultures} culture={settings.culture} />
{(isSelf && false) && (
<ToggleWrapper isSelf={true} >
<ToggleContent label={t('Subscriptions')} isOpen={true} >
<ProfileInfo
profile={profile}
updateProfileCulture={updateProfileCulture}
isSelf={isSelf}
isAdmin={isAdmin}
t={t}
cultures={settings.cultures}
culture={settings.culture}
/>
{isSelf && false && (
<ToggleWrapper isSelf={true}>
<ToggleContent label={t("Subscriptions")} isOpen={true}>
<Text as="span">
<Button
size="big"
label={t('EditSubscriptionsBtn')}
label={t("EditSubscriptionsBtn")}
primary={true}
onClick={this.onEditSubscriptionsClick}
/>
@ -140,21 +168,21 @@ class SectionBodyContent extends React.PureComponent {
)}
{profile.notes && (
<ToggleWrapper>
<ToggleContent label={t('Comments')} isOpen={true} >
<ToggleContent label={t("Comments")} isOpen={true}>
<Text as="span">{profile.notes}</Text>
</ToggleContent>
</ToggleWrapper>
)}
{profile.contacts && (
<ToggleWrapper isContacts={true} >
<ToggleContent label={t('ContactInformation')} isOpen={true} >
<ToggleWrapper isContacts={true}>
<ToggleContent label={t("ContactInformation")} isOpen={true}>
<Text as="span">{infoContacts}</Text>
</ToggleContent>
</ToggleWrapper>
)}
{socialContacts && (
<ToggleWrapper isContacts={true} >
<ToggleContent label={t('SocialProfiles')} isOpen={true} >
<ToggleWrapper isContacts={true}>
<ToggleContent label={t("SocialProfiles")} isOpen={true}>
<Text as="span">{socialContacts}</Text>
</ToggleContent>
</ToggleWrapper>
@ -164,13 +192,15 @@ class SectionBodyContent extends React.PureComponent {
}
}
const mapStateToProps = state => {
const mapStateToProps = (state) => {
return {
settings: state.auth.settings,
profile: state.profile.targetUser,
isAdmin: isAdmin(state.auth.user),
viewer: state.auth.user
isAdmin: isAdmin(state),
viewer: state.auth.user,
};
}
};
export default connect(mapStateToProps, { updateProfileCulture })(withRouter(withTranslation()(SectionBodyContent)));
export default connect(mapStateToProps, { updateProfileCulture })(
withRouter(withTranslation()(SectionBodyContent))
);

View File

@ -3,20 +3,20 @@ import { connect } from "react-redux";
import {
IconButton,
ContextMenuButton,
AvatarEditor
AvatarEditor,
} from "asc-web-components";
import { Headline, toastr } from "asc-web-common";
import { withRouter } from "react-router";
import {
getUserStatus,
toEmployeeWrapper
toEmployeeWrapper,
} from "../../../../../store/people/selectors";
import { withTranslation, Trans } from "react-i18next";
import { updateUserStatus } from "../../../../../store/people/actions";
import { updateProfile } from "../../../../../store/profile/actions";
import {
fetchProfile,
getUserPhoto
getUserPhoto,
} from "../../../../../store/profile/actions";
import styled from "styled-components";
import { store, api, constants } from "asc-web-common";
@ -24,19 +24,19 @@ import {
DeleteSelfProfileDialog,
ChangePasswordDialog,
ChangeEmailDialog,
DeleteProfileEverDialog
DeleteProfileEverDialog,
} from "../../../../dialogs";
import { createI18N } from "../../../../../helpers/i18n";
const i18n = createI18N({
page: "Profile",
localesPath: "pages/Profile"
localesPath: "pages/Profile",
});
const { isAdmin, isMe } = store.auth.selectors;
const {
resendUserInvites,
createThumbnailsAvatar,
loadAvatar,
deleteAvatar
deleteAvatar,
} = api.people;
const { EmployeeStatus } = constants;
@ -85,7 +85,7 @@ class SectionHeaderContent extends React.PureComponent {
}
}
mapPropsToState = props => {
mapPropsToState = (props) => {
let profile = toEmployeeWrapper(props.profile);
const newState = {
@ -95,21 +95,21 @@ class SectionHeaderContent extends React.PureComponent {
tmpFile: "",
image: null,
defaultWidth: 0,
defaultHeight: 0
defaultHeight: 0,
},
dialogsVisible: {
deleteSelfProfile: false,
changePassword: false,
changeEmail: false,
deleteProfileEver: false
}
deleteProfileEver: false,
},
};
return newState;
};
openAvatarEditor = () => {
getUserPhoto(this.state.profile.id).then(userPhotoData => {
getUserPhoto(this.state.profile.id).then((userPhotoData) => {
if (userPhotoData.original) {
let avatarDefaultSizes = /_(\d*)-(\d*)./g.exec(userPhotoData.original);
if (avatarDefaultSizes !== null && avatarDefaultSizes.length > 2) {
@ -122,9 +122,9 @@ class SectionHeaderContent extends React.PureComponent {
? userPhotoData.original.indexOf("default_user_photo") !== -1
? null
: userPhotoData.original
: null
: null,
},
visibleAvatarEditor: true
visibleAvatarEditor: true,
});
} else {
this.setState({
@ -132,9 +132,9 @@ class SectionHeaderContent extends React.PureComponent {
tmpFile: this.state.avatar.tmpFile,
defaultWidth: 0,
defaultHeight: 0,
image: null
image: null,
},
visibleAvatarEditor: true
visibleAvatarEditor: true,
});
}
}
@ -147,22 +147,22 @@ class SectionHeaderContent extends React.PureComponent {
data.append("file", file);
data.append("Autosave", false);
loadAvatar(this.state.profile.id, data)
.then(response => {
.then((response) => {
var img = new Image();
img.onload = function() {
img.onload = function () {
var stateCopy = Object.assign({}, _this.state);
stateCopy.avatar = {
tmpFile: response.data,
image: response.data,
defaultWidth: img.width,
defaultHeight: img.height
defaultHeight: img.height,
};
_this.setState(stateCopy);
if (typeof callback === "function") callback();
};
img.src = response.data;
})
.catch(error => toastr.error(error));
.catch((error) => toastr.error(error));
};
onSaveAvatar = (isUpdate, result) => {
@ -176,9 +176,9 @@ class SectionHeaderContent extends React.PureComponent {
),
width: result.width,
height: result.height,
tmpFile: this.state.avatar.tmpFile
tmpFile: this.state.avatar.tmpFile,
})
.then(response => {
.then((response) => {
let stateCopy = Object.assign({}, this.state);
stateCopy.visibleAvatarEditor = false;
stateCopy.avatar.tmpFile = "";
@ -189,25 +189,25 @@ class SectionHeaderContent extends React.PureComponent {
toastr.success(this.props.t("ChangesApplied"));
this.setState(stateCopy);
})
.catch(error => toastr.error(error))
.catch((error) => toastr.error(error))
.then(() => this.props.updateProfile(this.props.profile))
.then(() => this.props.fetchProfile(this.state.profile.id));
} else {
deleteAvatar(this.state.profile.id)
.then(response => {
.then((response) => {
let stateCopy = Object.assign({}, this.state);
stateCopy.visibleAvatarEditor = false;
stateCopy.profile.avatarMax = response.big;
toastr.success(this.props.t("ChangesApplied"));
this.setState(stateCopy);
})
.catch(error => toastr.error(error));
.catch((error) => toastr.error(error));
}
};
onCloseAvatarEditor = () => {
this.setState({
visibleAvatarEditor: false
visibleAvatarEditor: false,
});
};
@ -215,16 +215,16 @@ class SectionHeaderContent extends React.PureComponent {
this.setState({
dialogsVisible: {
...this.state.dialogsVisible,
changePassword: !this.state.dialogsVisible.changePassword
}
changePassword: !this.state.dialogsVisible.changePassword,
},
});
toggleChangeEmailDialog = () =>
this.setState({
dialogsVisible: {
...this.state.dialogsVisible,
changeEmail: !this.state.dialogsVisible.changeEmail
}
changeEmail: !this.state.dialogsVisible.changeEmail,
},
});
onEditClick = () => {
@ -239,7 +239,7 @@ class SectionHeaderContent extends React.PureComponent {
.then(() => this.props.updateProfile(this.props.profile))
.then(() => fetchProfile(userId))
.then(() => toastr.success(t("SuccessChangeUserStatus")))
.catch(error => toastr.error(error));
.catch((error) => toastr.error(error));
};
onDisableClick = () =>
@ -248,7 +248,7 @@ class SectionHeaderContent extends React.PureComponent {
onEnableClick = () =>
this.onUpdateUserStatus(EmployeeStatus.Active, this.state.profile.id);
onReassignDataClick = user => {
onReassignDataClick = (user) => {
const { history, settings } = this.props;
history.push(`${settings.homepage}/reassign/${user.userName}`);
};
@ -261,16 +261,16 @@ class SectionHeaderContent extends React.PureComponent {
this.setState({
dialogsVisible: {
...this.state.dialogsVisible,
deleteProfileEver: !this.state.dialogsVisible.deleteProfileEver
}
deleteProfileEver: !this.state.dialogsVisible.deleteProfileEver,
},
});
toggleDeleteSelfProfileDialog = () => {
this.setState({
dialogsVisible: {
...this.state.dialogsVisible,
deleteSelfProfile: !this.state.dialogsVisible.deleteSelfProfile
}
deleteSelfProfile: !this.state.dialogsVisible.deleteSelfProfile,
},
});
};
@ -287,7 +287,7 @@ class SectionHeaderContent extends React.PureComponent {
</Trans>
)
)
.catch(error => toastr.error(error));
.catch((error) => toastr.error(error));
};
getUserContextOptions = (user, viewer) => {
@ -305,22 +305,22 @@ class SectionHeaderContent extends React.PureComponent {
{
key: "edit",
label: t("EditUserDialogTitle"),
onClick: this.onEditClick
onClick: this.onEditClick,
},
{
key: "change-password",
label: t("PasswordChangeButton"),
onClick: this.toggleChangePasswordDialog
onClick: this.toggleChangePasswordDialog,
},
{
key: "change-email",
label: t("EmailChangeButton"),
onClick: this.toggleChangeEmailDialog
onClick: this.toggleChangeEmailDialog,
},
{
key: "edit-photo",
label: t("EditPhoto"),
onClick: this.openAvatarEditor
onClick: this.openAvatarEditor,
},
isMe(user, viewer.userName)
? viewer.isOwner
@ -328,76 +328,76 @@ class SectionHeaderContent extends React.PureComponent {
: {
key: "delete-profile",
label: t("DeleteSelfProfile"),
onClick: this.toggleDeleteSelfProfileDialog
onClick: this.toggleDeleteSelfProfileDialog,
}
: {
key: "disable",
label: t("DisableUserButton"),
onClick: this.onDisableClick
}
onClick: this.onDisableClick,
},
];
case "disabled":
return [
{
key: "enable",
label: t("EnableUserButton"),
onClick: this.onEnableClick
onClick: this.onEnableClick,
},
{
key: "edit-photo",
label: t("EditPhoto"),
onClick: this.openAvatarEditor
onClick: this.openAvatarEditor,
},
{
key: "reassign-data",
label: t("ReassignData"),
onClick: this.onReassignDataClick.bind(this, user)
onClick: this.onReassignDataClick.bind(this, user),
},
{
key: "delete-personal-data",
label: t("RemoveData"),
onClick: this.onDeletePersonalDataClick
onClick: this.onDeletePersonalDataClick,
},
{
key: "delete-profile",
label: t("DeleteSelfProfile"),
onClick: this.toggleDeleteProfileEverDialog
}
onClick: this.toggleDeleteProfileEverDialog,
},
];
case "pending":
return [
{
key: "edit",
label: t("EditButton"),
onClick: this.onEditClick
onClick: this.onEditClick,
},
{
key: "invite-again",
label: t("InviteAgainLbl"),
onClick: this.onInviteAgainClick
onClick: this.onInviteAgainClick,
},
{
key: "edit-photo",
label: t("EditPhoto"),
onClick: this.openAvatarEditor
onClick: this.openAvatarEditor,
},
!isMe(user, viewer.userName) &&
(user.status === EmployeeStatus.Active
? {
key: "disable",
label: t("DisableUserButton"),
onClick: this.onDisableClick
onClick: this.onDisableClick,
}
: {
key: "enable",
label: t("EnableUserButton"),
onClick: this.onEnableClick
onClick: this.onEnableClick,
}),
isMe(user, viewer.userName) && {
key: "delete-profile",
label: t("DeleteSelfProfile"),
onClick: this.toggleDeleteSelfProfileDialog
}
onClick: this.toggleDeleteSelfProfileDialog,
},
];
default:
return [];
@ -418,7 +418,7 @@ class SectionHeaderContent extends React.PureComponent {
t,
filter,
settings,
history
history,
} = this.props;
const { avatar, visibleAvatarEditor, dialogsVisible } = this.state;
const contextOptions = () => this.getUserContextOptions(profile, viewer);
@ -505,17 +505,18 @@ class SectionHeaderContent extends React.PureComponent {
}
}
const mapStateToProps = state => {
const mapStateToProps = (state) => {
return {
settings: state.auth.settings,
profile: state.profile.targetUser,
viewer: state.auth.user,
isAdmin: isAdmin(state.auth.user),
filter: state.people.filter
isAdmin: isAdmin(state),
filter: state.people.filter,
};
};
export default connect(
mapStateToProps,
{ updateUserStatus, fetchProfile, updateProfile }
)(withRouter(withTranslation()(SectionHeaderContent)));
export default connect(mapStateToProps, {
updateUserStatus,
fetchProfile,
updateProfile,
})(withRouter(withTranslation()(SectionHeaderContent)));

View File

@ -128,7 +128,7 @@ function mapStateToProps(state) {
return {
profile: targetUser,
isVisitor: user.isVisitor,
isAdmin: isAdmin(user),
isAdmin: isAdmin(state),
isLoaded,
language: cultureName || culture || "en-US",
};

View File

@ -128,7 +128,7 @@ function mapStateToProps(state) {
return {
isVisitor: state.auth.user.isVisitor,
profile: state.profile.targetUser,
isAdmin: isAdmin(state.auth.user),
isAdmin: isAdmin(state),
};
}

View File

@ -5,7 +5,7 @@ import { PageLayout, store } from "asc-web-common";
import {
ArticleHeaderContent,
ArticleMainButtonContent,
ArticleBodyContent
ArticleBodyContent,
} from "../../Article";
// import { SectionHeaderContent } from './Section';
// import { fetchProfile } from '../../../store/profile/actions';
@ -14,7 +14,7 @@ import { SectionHeaderContent, SectionBodyContent } from "./Section";
import { createI18N } from "../../../helpers/i18n";
const i18n = createI18N({
page: "Reassign",
localesPath: "pages/Reassign"
localesPath: "pages/Reassign",
});
const { isAdmin } = store.auth.selectors;
@ -88,12 +88,9 @@ Reassign.propTypes = {
function mapStateToProps(state) {
return {
isAdmin: isAdmin(state.auth.user)
isAdmin: isAdmin(state),
// profile: state.profile.targetUser
};
}
export default connect(
mapStateToProps,
{}
)(Reassign);
export default connect(mapStateToProps, {})(Reassign);

View File

@ -1,199 +1,436 @@
import { find, filter, cloneDeep } from "lodash";
import { store, constants } from 'asc-web-common';
const { isAdmin } = store.auth.selectors;
const { EmployeeActivationStatus, EmployeeStatus} = constants;
import { createSelector } from "reselect";
import { store, constants } from "asc-web-common";
import { isMobileOnly } from "react-device-detect";
const { isAdmin, isMe, getCurrentUser } = store.auth.selectors;
const { EmployeeActivationStatus, EmployeeStatus } = constants;
export function getSelectedUser(selection, userId) {
return find(selection, function (obj) {
return obj.id === userId;
});
};
return find(selection, function (obj) {
return obj.id === userId;
});
}
export function getUserByUserName(users, userName) {
return find(users, function (obj) {
return obj.userName === userName;
});
};
return find(users, function (obj) {
return obj.userName === userName;
});
}
export function isUserSelected(selection, userId) {
return getSelectedUser(selection, userId) !== undefined;
};
return getSelectedUser(selection, userId) !== undefined;
}
export function skipUser(selection, userId) {
return filter(selection, function (obj) {
return obj.id !== userId;
});
return filter(selection, function (obj) {
return obj.id !== userId;
});
}
export const getUserStatus = (user) => {
if (
user.status === EmployeeStatus.Active &&
user.activationStatus === EmployeeActivationStatus.Activated
) {
return "normal";
} else if (
user.status === EmployeeStatus.Active &&
user.activationStatus === EmployeeActivationStatus.Pending
) {
return "pending";
} else if (user.status === EmployeeStatus.Disabled) {
return "disabled";
} else {
return "unknown";
}
};
export const getUserStatus = user => {
if (user.status === EmployeeStatus.Active && user.activationStatus === EmployeeActivationStatus.Activated) {
return "normal";
}
else if (user.status === EmployeeStatus.Active && user.activationStatus === EmployeeActivationStatus.Pending) {
return "pending";
}
else if (user.status === EmployeeStatus.Disabled) {
return "disabled";
}
else {
return "unknown";
}
};
export const getUserRole = user => {
if (user.isOwner) return "owner";
else if (isAdmin(user)) return "admin";
else if (user.isVisitor) return "guest";
else return "user";
export const getUserRole = (user) => {
if (user.isOwner) return "owner";
else if (isAdmin({ auth: { user } })) return "admin";
//TODO: Need refactoring
else if (user.isVisitor) return "guest";
else return "user";
};
export const getUserContactsPattern = () => {
return {
contact: [
{ type: "mail", icon: "MailIcon", link: 'mailto:{0}' },
{ type: "phone", icon: "PhoneIcon", link: 'tel:{0}' },
{ type: "mobphone", icon: "MobileIcon", link: 'tel:{0}' },
{ type: "gmail", icon: "GmailIcon", link: 'mailto:{0}' },
{ type: "skype", icon: "SkypeIcon", link: 'skype:{0}?userinfo' },
{ type: "msn", icon: "WindowsMsnIcon" },
{ type: "icq", icon: "IcqIcon", link: 'https://www.icq.com/people/{0}' },
{ type: "jabber", icon: "JabberIcon" },
{ type: "aim", icon: "AimIcon" }
],
social: [
{ type: "facebook", icon: "ShareFacebookIcon", link: 'https://facebook.com/{0}' },
{ type: "livejournal", icon: "LivejournalIcon", link: 'https://{0}.livejournal.com' },
{ type: "myspace", icon: "MyspaceIcon", link: 'https://myspace.com/{0}' },
{ type: "twitter", icon: "ShareTwitterIcon", link: 'https://twitter.com/{0}' },
{ type: "blogger", icon: "BloggerIcon", link: 'https://{0}.blogspot.com' },
{ type: "yahoo", icon: "YahooIcon", link: 'mailto:{0}@yahoo.com' }
]
};
return {
contact: [
{ type: "mail", icon: "MailIcon", link: "mailto:{0}" },
{ type: "phone", icon: "PhoneIcon", link: "tel:{0}" },
{ type: "mobphone", icon: "MobileIcon", link: "tel:{0}" },
{ type: "gmail", icon: "GmailIcon", link: "mailto:{0}" },
{ type: "skype", icon: "SkypeIcon", link: "skype:{0}?userinfo" },
{ type: "msn", icon: "WindowsMsnIcon" },
{ type: "icq", icon: "IcqIcon", link: "https://www.icq.com/people/{0}" },
{ type: "jabber", icon: "JabberIcon" },
{ type: "aim", icon: "AimIcon" },
],
social: [
{
type: "facebook",
icon: "ShareFacebookIcon",
link: "https://facebook.com/{0}",
},
{
type: "livejournal",
icon: "LivejournalIcon",
link: "https://{0}.livejournal.com",
},
{ type: "myspace", icon: "MyspaceIcon", link: "https://myspace.com/{0}" },
{
type: "twitter",
icon: "ShareTwitterIcon",
link: "https://twitter.com/{0}",
},
{
type: "blogger",
icon: "BloggerIcon",
link: "https://{0}.blogspot.com",
},
{ type: "yahoo", icon: "YahooIcon", link: "mailto:{0}@yahoo.com" },
],
};
};
export const getUserContacts = (contacts) => {
const mapContacts = (a, b) => {
return a.map(a => ({ ...a, ...b.find(({ type }) => type === a.type) }))
.filter(c => c.icon);
}
const mapContacts = (a, b) => {
return a
.map((a) => ({ ...a, ...b.find(({ type }) => type === a.type) }))
.filter((c) => c.icon);
};
const info = {};
const pattern = getUserContactsPattern();
const info = {};
const pattern = getUserContactsPattern();
info.contact = mapContacts(contacts, pattern.contact);
info.social = mapContacts(contacts, pattern.social);
info.contact = mapContacts(contacts, pattern.contact);
info.social = mapContacts(contacts, pattern.social);
return info;
return info;
};
const getUserChecked = (user, selected) => {
const status = getUserStatus(user);
switch (selected) {
case "all":
return true;
case "active":
return status === "normal";
case "disabled":
return status === "disabled";
case "invited":
return status === "pending";
default:
return false;
}
const status = getUserStatus(user);
switch (selected) {
case "all":
return true;
case "active":
return status === "normal";
case "disabled":
return status === "disabled";
case "invited":
return status === "pending";
default:
return false;
}
};
export function getUsersBySelected(users, selected) {
let newSelection = [];
users.forEach(user => {
const checked = getUserChecked(user, selected);
let newSelection = [];
users.forEach((user) => {
const checked = getUserChecked(user, selected);
if (checked)
newSelection.push(user);
});
if (checked) newSelection.push(user);
});
return newSelection;
};
return newSelection;
}
export function isUserDisabled(user) {
return getUserStatus(user) === "disabled";
};
return getUserStatus(user) === "disabled";
}
export function getSelectedGroup(groups, selectedGroupId) {
return find(groups, (group) => group.id === selectedGroupId);
return find(groups, (group) => group.id === selectedGroupId);
}
export function toEmployeeWrapper(profile) {
const emptyData = {
id: "",
firstName: "",
lastName: "",
email: "",
password: "",
birthday: "",
sex: "male",
workFrom: "",
location: "",
title: "",
groups: [],
notes: "",
contacts: []
};
const emptyData = {
id: "",
firstName: "",
lastName: "",
email: "",
password: "",
birthday: "",
sex: "male",
workFrom: "",
location: "",
title: "",
groups: [],
notes: "",
contacts: [],
};
return cloneDeep({ ...emptyData, ...profile });
return cloneDeep({ ...emptyData, ...profile });
}
export function mapGroupsToGroupSelectorOptions(groups) {
return groups.map(group => {
return {
key: group.id,
label: group.name,
manager: group.manager,
total: 0
}
});
return groups.map((group) => {
return {
key: group.id,
label: group.name,
manager: group.manager,
total: 0,
};
});
}
export function mapGroupSelectorOptionsToGroups(options) {
return options.map(option => {
return {
id: option.key,
name: option.label,
manager: option.manager
return options.map((option) => {
return {
id: option.key,
name: option.label,
manager: option.manager,
};
});
}
export function filterGroupSelectorOptions(options, template) {
return options.filter((option) => {
return template ? option.label.indexOf(template) > -1 : true;
});
}
export const getUsers = (state) => state.people.users || [];
export const getSelection = (state) => state.people.selection;
export const isAnythingSelected = createSelector(
[getSelection],
(selection) => selection && selection.length > 0
);
const getUserContextOptions = (isMySelf, isOwner, status, haveMobileNumber) => {
// let status = "";
// const { t, isAdmin } = this.props;
// const isSelf = isMe(user, viewer.userName);
// if (isAdmin || (!isAdmin && isSelf)) {
// status = getUserStatus(user);
// }
//console.log("getUserContextOptions", user, viewer, status);
const options = [];
switch (status) {
case "normal":
case "unknown":
options.push("send-email");
if (haveMobileNumber && isMobileOnly) {
options.push("send-message");
}
options.push("separator");
options.push("edit");
options.push("change-password");
options.push("change-email");
if (isMySelf) {
if (!isOwner) {
options.push("delete-self-profile");
}
} else {
options.push("disable");
}
break;
case "disabled":
options.push("enable");
//TODO: Need implementation
/*options.push("reassign-data");
options.push("delete-personal-data");*/
options.push("delete-profile");
break;
case "pending":
options.push("edit");
options.push("invite-again");
if (isMySelf) {
options.push("delete-profile");
} else {
if (status === EmployeeStatus.Active) {
options.push("disable");
} else {
options.push("enable");
}
}
break;
default:
break;
}
return options;
};
// export const isMySelf = (user) => {
// return createSelector([getCurrentUser], (viewer) => {
// const isMySelf = isMe(user, viewer.userName);
// return isMySelf;
// });
// };
export const getPeopleList = createSelector(
[getUsers, getSelection, isAdmin, getCurrentUser],
(users, selection, isAdmin, viewer) => {
return users.map((user) => {
const {
id,
displayName,
avatar,
email,
isOwner,
mobilePhone,
userName,
} = user;
const status = getUserStatus(user);
const role = getUserRole(user);
const isMySelf = isMe(user, viewer.userName);
const options = getUserContextOptions(
isMySelf,
isOwner,
status,
!!mobilePhone
);
return {
id,
checked: isAdmin ? isUserSelected(selection, user.id) : undefined,
status,
role,
displayName,
avatar,
email,
userName,
mobilePhone,
options,
};
});
}
}
);
export function filterGroupSelectorOptions(options, template) {
return options.filter(option => {
return template ? option.label.indexOf(template) > -1 : true;
})
}
export function getUserType(users, status, currentUserId) {
export const getEmployees = createSelector(
[getUsers, getCurrentUser],
(users, currentUser) => {
return users.filter(
x =>
(x) =>
!x.isAdmin &&
!x.isOwner &&
x.isVisitor === status &&
x.isVisitor === false &&
x.status !== 2 &&
x.id !== currentUserId
x.id !== currentUser.Id
);
}
);
export function getUsersStatus(users, status, currentUserId) {
export const getEmployeesIds = createSelector([getEmployees], (users) => {
return users.map((user) => {
return user.id;
});
});
export const isEmployeesSelected = createSelector(
[getEmployeesIds],
(employeesIds) => employeesIds && employeesIds.length > 0
);
export const getGuests = createSelector(
[getUsers, getCurrentUser],
(users, currentUser) => {
return users.filter(
x => !x.isOwner && x.status !== status && x.id !== currentUserId
(x) =>
!x.isAdmin &&
!x.isOwner &&
x.isVisitor === false &&
x.status !== 2 &&
x.id !== currentUser.Id
);
}
);
export function getInactiveUsers(users) {
return users.filter(x => x.activationStatus === 2 && x.status === 1);
}
export const getGuestsIds = createSelector([getGuests], (guests) => {
return guests.map((user) => {
return user.id;
});
});
export function getDeleteUsers(users) {
return users.filter(x => x.status === 2);
}
export const isGuestsSelected = createSelector(
[getGuestsIds],
(guestsIds) => guestsIds && guestsIds.length > 0
);
export function getUsersIds(selections) {
return selections.map((user) => { return user.id });
export const getActiveUsers = createSelector(
[getUsers, getCurrentUser],
(users, currentUser) => {
return users.filter(
(x) => !x.isOwner && x.status !== 1 && x.id !== currentUser.Id
);
}
);
export const getActiveUsersIds = createSelector([getActiveUsers], (users) => {
return users.map((user) => {
return user.id;
});
});
export const isActiveSelected = createSelector(
[getGuestsIds],
(activeUsersIds) => activeUsersIds && activeUsersIds.length > 0
);
export const getDisableUsers = createSelector(
[getUsers, getCurrentUser],
(users, currentUser) => {
return users.filter(
(x) => !x.isOwner && x.status !== 2 && x.id !== currentUser.Id
);
}
);
export const getDisableUsersIds = createSelector([getDisableUsers], (users) => {
return users.map((user) => {
return user.id;
});
});
export const isDisableSelected = createSelector(
[getGuestsIds],
(disableUsersIds) => disableUsersIds && disableUsersIds.length > 0
);
export const getInactiveUsers = createSelector([getUsers], (users) => {
return users.filter((x) => x.activationStatus === 2 && x.status === 1);
});
export const getInactiveUsersIds = createSelector(
[getInactiveUsers],
(users) => {
return users.map((user) => {
return user.id;
});
}
);
export const isInactiveSelected = createSelector(
[getInactiveUsersIds],
(inactiveUsersIds) => inactiveUsersIds && inactiveUsersIds.length > 0
);
export const getDeleteUsers = createSelector([getUsers], (users) => {
return users.filter((x) => x.status === 2);
});
export const getDeleteUsersIds = createSelector([getDeleteUsers], (users) => {
return users.map((user) => {
return user.id;
});
});
export const isDeleteSelected = createSelector(
[getDeleteUsersIds],
(deleteUsersIds) => deleteUsersIds && deleteUsersIds.length > 0
);

View File

@ -75,7 +75,7 @@ const PrivateRoute = ({ component: Component, ...rest }) => {
function mapStateToProps(state) {
const { user, isLoaded, isAuthenticated } = state.auth;
return {
isAdmin: isAdmin(user),
isAdmin: isAdmin(state),
user,
isAuthenticated: !(
!localStorage.getItem(AUTH_KEY) ||

View File

@ -1,8 +1,9 @@
import { createSelector } from "reselect";
import isEmpty from "lodash/isEmpty";
export function isAdmin(user) {
let isPeopleAdmin = user.listAdminModules
export function isAdmin(state) {
const { user } = state.auth;
const isPeopleAdmin = user.listAdminModules
? user.listAdminModules.includes("people")
: false;
return user.isAdmin || user.isOwner || isPeopleAdmin;