Merge pull request #28 from ONLYOFFICE/feature/user-actions-changes
Feature/user actions changes
This commit is contained in:
commit
07413ece9b
@ -0,0 +1,54 @@
|
||||
import i18n from "i18next";
|
||||
import Backend from "i18next-xhr-backend";
|
||||
import config from "../../../../package.json";
|
||||
import { constants } from 'asc-web-common';
|
||||
const { LANGUAGE } = constants;
|
||||
|
||||
const newInstance = i18n.createInstance();
|
||||
|
||||
if (process.env.NODE_ENV === "production") {
|
||||
newInstance
|
||||
.use(Backend)
|
||||
.init({
|
||||
lng: localStorage.getItem(LANGUAGE) || 'en',
|
||||
fallbackLng: "en",
|
||||
|
||||
interpolation: {
|
||||
escapeValue: false, // not needed for react as it escapes by default
|
||||
},
|
||||
|
||||
react: {
|
||||
useSuspense: true
|
||||
},
|
||||
backend: {
|
||||
loadPath: `${config.homepage}/locales/DeleteProfileEverDialog/{{lng}}/{{ns}}.json`
|
||||
}
|
||||
});
|
||||
} else if (process.env.NODE_ENV === "development") {
|
||||
|
||||
const resources = {
|
||||
en: {
|
||||
translation: require("./locales/en/translation.json")
|
||||
},
|
||||
ru: {
|
||||
translation: require("./locales/ru/translation.json")
|
||||
},
|
||||
};
|
||||
|
||||
newInstance.init({
|
||||
resources: resources,
|
||||
lng: localStorage.getItem(LANGUAGE) || 'en',
|
||||
fallbackLng: "en",
|
||||
debug: true,
|
||||
|
||||
interpolation: {
|
||||
escapeValue: false, // not needed for react as it escapes by default
|
||||
},
|
||||
|
||||
react: {
|
||||
useSuspense: true
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export default newInstance;
|
@ -0,0 +1,194 @@
|
||||
import React, { memo } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { withRouter } from "react-router";
|
||||
import PropTypes from "prop-types";
|
||||
import {
|
||||
toastr,
|
||||
ModalDialog,
|
||||
Button,
|
||||
Text,
|
||||
ToggleContent,
|
||||
Checkbox,
|
||||
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 i18n from "./i18n";
|
||||
import { utils } from "asc-web-common";
|
||||
import ModalDialogContainer from "../ModalDialogContainer";
|
||||
import { updateUserStatus } from "../../../store/people/actions";
|
||||
|
||||
const { changeLanguage } = utils;
|
||||
|
||||
class ChangeUserStatusDialogComponent extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
const { userIds, selectedUsers } = props;
|
||||
|
||||
changeLanguage(i18n);
|
||||
|
||||
const listUsers = selectedUsers.map((item, index) => {
|
||||
const disabled = userIds.find(x => x === item.id);
|
||||
return (selectedUsers[index] = {
|
||||
...selectedUsers[index],
|
||||
checked: disabled ? true : false,
|
||||
disabled: disabled ? false : true
|
||||
});
|
||||
});
|
||||
|
||||
this.state = { isRequestRunning: false, listUsers, userIds };
|
||||
}
|
||||
|
||||
onChangeUserStatus = () => {
|
||||
const {
|
||||
updateUserStatus,
|
||||
userStatus,
|
||||
t,
|
||||
setSelected,
|
||||
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))
|
||||
.finally(() => {
|
||||
this.setState({ isRequestRunning: false }, () => {
|
||||
setSelected("close");
|
||||
onClose();
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
onChange = e => {
|
||||
const { listUsers } = this.state;
|
||||
const userIndex = listUsers.findIndex(x => x.id === e.target.value);
|
||||
const newUsersList = listUsers;
|
||||
newUsersList[userIndex].checked = !newUsersList[userIndex].checked;
|
||||
|
||||
const newUserIds = [];
|
||||
|
||||
for (let item of newUsersList) {
|
||||
if (item.checked === true) {
|
||||
newUserIds.push(item.id);
|
||||
}
|
||||
}
|
||||
|
||||
this.setState({ listUsers: newUsersList, userIds: newUserIds });
|
||||
};
|
||||
|
||||
render() {
|
||||
const { t, onClose, visible, userStatus } = this.props;
|
||||
const { listUsers, isRequestRunning, userIds } = this.state;
|
||||
const containerStyles = { height: listUsers.length * 25, maxHeight: 220 };
|
||||
const itemSize = 25;
|
||||
|
||||
const renderItems = memo(({ data, index, style }) => {
|
||||
return (
|
||||
<Checkbox
|
||||
truncate
|
||||
style={style}
|
||||
className="modal-dialog-checkbox"
|
||||
value={data[index].id}
|
||||
onChange={this.onChange}
|
||||
key={`checkbox_${index}`}
|
||||
isChecked={data[index].checked}
|
||||
label={data[index].displayName}
|
||||
isDisabled={data[index].disabled}
|
||||
/>
|
||||
);
|
||||
}, areEqual);
|
||||
|
||||
const renderList = ({ height, width }) => (
|
||||
<List
|
||||
className="List"
|
||||
height={height}
|
||||
width={width}
|
||||
itemSize={itemSize}
|
||||
itemCount={listUsers.length}
|
||||
itemData={listUsers}
|
||||
outerElementType={CustomScrollbarsVirtualList}
|
||||
>
|
||||
{renderItems}
|
||||
</List>
|
||||
);
|
||||
|
||||
const statusTranslation =
|
||||
userStatus === 1
|
||||
? t("ChangeUsersActiveStatus")
|
||||
: t("ChangeUsersDisableStatus");
|
||||
const userStatusTranslation =
|
||||
userStatus === 1 ? t("DisabledEmployeeTitle") : t("ActiveEmployeeTitle");
|
||||
|
||||
return (
|
||||
<ModalDialogContainer>
|
||||
<ModalDialog
|
||||
visible={visible}
|
||||
onClose={onClose}
|
||||
headerContent={t("ChangeUserStatusDialogHeader")}
|
||||
bodyContent={
|
||||
<>
|
||||
<Text>
|
||||
{t("ChangeUserStatusDialog", {
|
||||
status: statusTranslation,
|
||||
userStatus: userStatusTranslation
|
||||
})}
|
||||
</Text>
|
||||
<Text>{t("ChangeUserStatusDialogMessage")}</Text>
|
||||
<ToggleContent
|
||||
className="toggle-content-dialog"
|
||||
label={t("ShowUsersList")}
|
||||
>
|
||||
<div style={containerStyles} className="modal-dialog-content">
|
||||
<AutoSizer>{renderList}</AutoSizer>
|
||||
</div>
|
||||
</ToggleContent>
|
||||
</>
|
||||
}
|
||||
footerContent={
|
||||
<>
|
||||
<Button
|
||||
label={t("ChangeUsersStatusButton")}
|
||||
size="medium"
|
||||
primary
|
||||
onClick={this.onChangeUserStatus}
|
||||
isLoading={isRequestRunning}
|
||||
isDisabled={!userIds.length}
|
||||
/>
|
||||
<Button
|
||||
className="button-dialog"
|
||||
label={t("CancelButton")}
|
||||
size="medium"
|
||||
onClick={onClose}
|
||||
isDisabled={isRequestRunning}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
</ModalDialogContainer>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const ChangeUserStatusDialogTranslated = withTranslation()(
|
||||
ChangeUserStatusDialogComponent
|
||||
);
|
||||
|
||||
const ChangeUserStatusDialog = props => (
|
||||
<ChangeUserStatusDialogTranslated i18n={i18n} {...props} />
|
||||
);
|
||||
|
||||
ChangeUserStatusDialog.propTypes = {
|
||||
visible: PropTypes.bool.isRequired,
|
||||
onClose: PropTypes.func.isRequired,
|
||||
setSelected: PropTypes.func.isRequired,
|
||||
userIds: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||
selectedUsers: PropTypes.arrayOf(PropTypes.object).isRequired
|
||||
};
|
||||
|
||||
export default connect(null, { updateUserStatus })(
|
||||
withRouter(ChangeUserStatusDialog)
|
||||
);
|
@ -0,0 +1,14 @@
|
||||
{
|
||||
"CancelButton": "Cancel",
|
||||
"DisabledEmployeeTitle": "Disabled",
|
||||
"SuccessChangeUserStatus": "The user status was successfully changed",
|
||||
|
||||
"ShowUsersList": "View users list",
|
||||
"ChangeUserStatusDialogHeader": "Change user status",
|
||||
"ChangeUserStatusDialog": "The users with the '{{ status }}' status will be disabled.",
|
||||
"ChangeUserStatusDialogMessage": "You cannot change the status for portal owner and for yourself",
|
||||
"ChangeUsersStatusButton": "Change user status",
|
||||
"ActiveEmployeeTitle": "Active",
|
||||
"ChangeUsersActiveStatus": "disabled",
|
||||
"ChangeUsersDisableStatus": "enabled"
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
{
|
||||
"CancelButton": "Отмена",
|
||||
"DisabledEmployeeTitle": "Заблокирован",
|
||||
"SuccessChangeUserStatus": "Статус пользователя успешно изменен",
|
||||
|
||||
"ShowUsersList": "Показать список пользователей",
|
||||
"ChangeUserStatusDialogHeader": "Изменение статуса пользователя",
|
||||
"ChangeUserStatusDialog": "Пользователи со статусом '{{ userStatus }}' будут {{ status }}.",
|
||||
"ChangeUserStatusDialogMessage": "Вы не можете изменить статус владельца портала и свой собственный статус",
|
||||
"ChangeUsersStatusButton": "Изменить статус",
|
||||
"ActiveEmployeeTitle": "Активный",
|
||||
"ChangeUsersDisableStatus": "заблокированы",
|
||||
"ChangeUsersActiveStatus": "разблокированы"
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
import i18n from "i18next";
|
||||
import Backend from "i18next-xhr-backend";
|
||||
import config from "../../../../package.json";
|
||||
import { constants } from 'asc-web-common';
|
||||
const { LANGUAGE } = constants;
|
||||
|
||||
const newInstance = i18n.createInstance();
|
||||
|
||||
if (process.env.NODE_ENV === "production") {
|
||||
newInstance
|
||||
.use(Backend)
|
||||
.init({
|
||||
lng: localStorage.getItem(LANGUAGE) || 'en',
|
||||
fallbackLng: "en",
|
||||
|
||||
interpolation: {
|
||||
escapeValue: false, // not needed for react as it escapes by default
|
||||
},
|
||||
|
||||
react: {
|
||||
useSuspense: true
|
||||
},
|
||||
backend: {
|
||||
loadPath: `${config.homepage}/locales/DeleteProfileEverDialog/{{lng}}/{{ns}}.json`
|
||||
}
|
||||
});
|
||||
} else if (process.env.NODE_ENV === "development") {
|
||||
|
||||
const resources = {
|
||||
en: {
|
||||
translation: require("./locales/en/translation.json")
|
||||
},
|
||||
ru: {
|
||||
translation: require("./locales/ru/translation.json")
|
||||
},
|
||||
};
|
||||
|
||||
newInstance.init({
|
||||
resources: resources,
|
||||
lng: localStorage.getItem(LANGUAGE) || 'en',
|
||||
fallbackLng: "en",
|
||||
debug: true,
|
||||
|
||||
interpolation: {
|
||||
escapeValue: false, // not needed for react as it escapes by default
|
||||
},
|
||||
|
||||
react: {
|
||||
useSuspense: true
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export default newInstance;
|
@ -0,0 +1,183 @@
|
||||
import React, { memo } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { withRouter } from "react-router";
|
||||
import PropTypes from "prop-types";
|
||||
import {
|
||||
toastr,
|
||||
ModalDialog,
|
||||
Button,
|
||||
Text,
|
||||
ToggleContent,
|
||||
Checkbox,
|
||||
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 i18n from "./i18n";
|
||||
import { utils } from "asc-web-common";
|
||||
import ModalDialogContainer from "../ModalDialogContainer";
|
||||
import { updateUserType } from "../../../store/people/actions";
|
||||
|
||||
const { changeLanguage } = utils;
|
||||
|
||||
class ChangeUserTypeDialogComponent extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
changeLanguage(i18n);
|
||||
|
||||
const { selectedUsers, userIds } = props;
|
||||
|
||||
const listUsers = selectedUsers.map((item, index) => {
|
||||
const disabled = userIds.find(x => x === item.id);
|
||||
return (selectedUsers[index] = {
|
||||
...selectedUsers[index],
|
||||
checked: disabled ? true : false,
|
||||
disabled: disabled ? false : true
|
||||
});
|
||||
});
|
||||
|
||||
this.state = { isRequestRunning: false, userIds, listUsers };
|
||||
}
|
||||
|
||||
onChange = e => {
|
||||
const { listUsers } = this.state;
|
||||
const userIndex = listUsers.findIndex(x => x.id === e.target.value);
|
||||
const newUsersList = listUsers;
|
||||
newUsersList[userIndex].checked = !newUsersList[userIndex].checked;
|
||||
|
||||
const newUserIds = [];
|
||||
for (let item of newUsersList) {
|
||||
if (item.checked === true) {
|
||||
newUserIds.push(item.id);
|
||||
}
|
||||
}
|
||||
|
||||
this.setState({ listUsers: newUsersList, userIds: newUserIds });
|
||||
};
|
||||
|
||||
onChangeUserType = () => {
|
||||
const { onClose, setSelected, t, userType, updateUserType } = this.props;
|
||||
const { userIds } = this.state;
|
||||
this.setState({ isRequestRunning: true }, () => {
|
||||
updateUserType(userType, userIds)
|
||||
.then(() => toastr.success(t("SuccessChangeUserType")))
|
||||
.catch(error => toastr.error(error))
|
||||
.finally(() => {
|
||||
this.setState({ isRequestRunning: false }, () => {
|
||||
setSelected("close");
|
||||
onClose();
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { visible, onClose, t, userType } = this.props;
|
||||
const { isRequestRunning, listUsers, userIds } = this.state;
|
||||
const itemSize = 25;
|
||||
const containerStyles = { height: listUsers.length * 25, maxHeight: 220 };
|
||||
|
||||
const renderItems = memo(({ data, index, style }) => {
|
||||
return (
|
||||
<Checkbox
|
||||
truncate
|
||||
style={style}
|
||||
className="modal-dialog-checkbox"
|
||||
value={data[index].id}
|
||||
onChange={this.onChange}
|
||||
key={`checkbox_${index}`}
|
||||
isChecked={data[index].checked}
|
||||
label={data[index].displayName}
|
||||
isDisabled={data[index].disabled}
|
||||
/>
|
||||
);
|
||||
}, areEqual);
|
||||
|
||||
const renderList = ({ height, width }) => (
|
||||
<List
|
||||
className="List"
|
||||
height={height}
|
||||
width={width}
|
||||
itemSize={itemSize}
|
||||
itemCount={listUsers.length}
|
||||
itemData={listUsers}
|
||||
outerElementType={CustomScrollbarsVirtualList}
|
||||
>
|
||||
{renderItems}
|
||||
</List>
|
||||
);
|
||||
|
||||
const firstType = userType === 1 ? t("GuestCaption") : t("UserCol");
|
||||
const secondType = userType === 1 ? t("UserCol") : t("GuestCaption");
|
||||
return (
|
||||
<ModalDialogContainer>
|
||||
<ModalDialog
|
||||
visible={visible}
|
||||
onClose={onClose}
|
||||
headerContent={t("ChangeUserTypeHeader")}
|
||||
bodyContent={
|
||||
<>
|
||||
<Text>
|
||||
{t("ChangeUserTypeMessage", {
|
||||
firstType: firstType,
|
||||
secondType: secondType
|
||||
})}
|
||||
</Text>
|
||||
<Text>{t("ChangeUserTypeMessageWarning")}</Text>
|
||||
|
||||
<ToggleContent
|
||||
className="toggle-content-dialog"
|
||||
label={t("ShowUsersList")}
|
||||
>
|
||||
<div style={containerStyles} className="modal-dialog-content">
|
||||
<AutoSizer>{renderList}</AutoSizer>
|
||||
</div>
|
||||
</ToggleContent>
|
||||
</>
|
||||
}
|
||||
footerContent={
|
||||
<>
|
||||
<Button
|
||||
label={t("ChangeUserTypeButton")}
|
||||
size="medium"
|
||||
primary
|
||||
onClick={this.onChangeUserType}
|
||||
isLoading={isRequestRunning}
|
||||
isDisabled={!userIds.length}
|
||||
/>
|
||||
<Button
|
||||
className="button-dialog"
|
||||
label={t("CancelButton")}
|
||||
size="medium"
|
||||
onClick={onClose}
|
||||
isDisabled={isRequestRunning}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
</ModalDialogContainer>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const ChangeUserTypeDialogTranslated = withTranslation()(
|
||||
ChangeUserTypeDialogComponent
|
||||
);
|
||||
|
||||
const ChangeUserTypeDialog = props => (
|
||||
<ChangeUserTypeDialogTranslated i18n={i18n} {...props} />
|
||||
);
|
||||
|
||||
ChangeUserTypeDialog.propTypes = {
|
||||
visible: PropTypes.bool.isRequired,
|
||||
onClose: PropTypes.func.isRequired,
|
||||
setSelected: PropTypes.func.isRequired,
|
||||
userIds: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||
selectedUsers: PropTypes.arrayOf(PropTypes.object).isRequired
|
||||
};
|
||||
|
||||
export default connect(null, { updateUserType })(
|
||||
withRouter(ChangeUserTypeDialog)
|
||||
);
|
@ -0,0 +1,12 @@
|
||||
{
|
||||
"GuestCaption": "Guest",
|
||||
"UserCol": "User",
|
||||
"CancelButton": "Cancel",
|
||||
"SuccessChangeUserType": "The user type was successfully changed",
|
||||
|
||||
"ChangeUserTypeHeader": "Change user type",
|
||||
"ChangeUserTypeMessage": "Users with the '{{ firstType }}' type will be moved to '{{ secondType }}' type.",
|
||||
"ChangeUserTypeMessageWarning": "You cannot change the type for portal administrators and for yourself",
|
||||
"ChangeUserTypeButton": "Change type",
|
||||
"ShowUsersList": "View users list"
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
{
|
||||
"CancelButton": "Отмена",
|
||||
"GuestCaption": "Гость",
|
||||
"UserCol": "Пользователь",
|
||||
"SuccessChangeUserType": "Тип пользователя успешно изменен",
|
||||
|
||||
"ChangeUserTypeHeader": "Изменение типа пользователя",
|
||||
"ChangeUserTypeButton": "Изменить тип",
|
||||
"ChangeUserTypeMessage": "Пользователи с типом '{{ firstType }}' будут переведены в тип '{{ secondType }}'.",
|
||||
"ChangeUserTypeMessageWarning": "Вы не можете изменить тип для администраторов портала и для самого себя",
|
||||
"ShowUsersList": "Показать список пользователей"
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
import i18n from "i18next";
|
||||
import Backend from "i18next-xhr-backend";
|
||||
import config from "../../../../package.json";
|
||||
import { constants } from 'asc-web-common';
|
||||
const { LANGUAGE } = constants;
|
||||
|
||||
const newInstance = i18n.createInstance();
|
||||
|
||||
if (process.env.NODE_ENV === "production") {
|
||||
newInstance
|
||||
.use(Backend)
|
||||
.init({
|
||||
lng: localStorage.getItem(LANGUAGE) || 'en',
|
||||
fallbackLng: "en",
|
||||
|
||||
interpolation: {
|
||||
escapeValue: false, // not needed for react as it escapes by default
|
||||
},
|
||||
|
||||
react: {
|
||||
useSuspense: true
|
||||
},
|
||||
backend: {
|
||||
loadPath: `${config.homepage}/locales/DeleteProfileEverDialog/{{lng}}/{{ns}}.json`
|
||||
}
|
||||
});
|
||||
} else if (process.env.NODE_ENV === "development") {
|
||||
|
||||
const resources = {
|
||||
en: {
|
||||
translation: require("./locales/en/translation.json")
|
||||
},
|
||||
ru: {
|
||||
translation: require("./locales/ru/translation.json")
|
||||
},
|
||||
};
|
||||
|
||||
newInstance.init({
|
||||
resources: resources,
|
||||
lng: localStorage.getItem(LANGUAGE) || 'en',
|
||||
fallbackLng: "en",
|
||||
debug: true,
|
||||
|
||||
interpolation: {
|
||||
escapeValue: false, // not needed for react as it escapes by default
|
||||
},
|
||||
|
||||
react: {
|
||||
useSuspense: true
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export default newInstance;
|
@ -0,0 +1,188 @@
|
||||
import React, { memo } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { withRouter } from "react-router";
|
||||
import PropTypes from "prop-types";
|
||||
import {
|
||||
toastr,
|
||||
ModalDialog,
|
||||
Button,
|
||||
Text,
|
||||
ToggleContent,
|
||||
Checkbox,
|
||||
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 i18n from "./i18n";
|
||||
import { api, utils } from "asc-web-common";
|
||||
import { removeUser } from "../../../store/people/actions";
|
||||
import ModalDialogContainer from "../ModalDialogContainer";
|
||||
|
||||
const { Filter } = api;
|
||||
const { changeLanguage } = utils;
|
||||
|
||||
class DeleteGroupUsersDialogComponent extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
changeLanguage(i18n);
|
||||
|
||||
const { selectedUsers, userIds } = props;
|
||||
|
||||
const listUsers = selectedUsers.map((item, index) => {
|
||||
const disabled = userIds.find(x => x === item.id);
|
||||
return (selectedUsers[index] = {
|
||||
...selectedUsers[index],
|
||||
checked: disabled ? true : false,
|
||||
disabled: disabled ? false : true
|
||||
});
|
||||
});
|
||||
|
||||
this.state = { isRequestRunning: false, listUsers, userIds };
|
||||
}
|
||||
|
||||
onDeleteGroupUsers = () => {
|
||||
const { removeUser, t, setSelected, onClose, filter } = this.props;
|
||||
const { userIds } = this.state;
|
||||
|
||||
this.setState({ isRequestRunning: true }, () => {
|
||||
removeUser(userIds, filter)
|
||||
.then(() => {
|
||||
toastr.success(t("DeleteGroupUsersSuccessMessage"));
|
||||
})
|
||||
.catch(error => toastr.error(error))
|
||||
.finally(() => {
|
||||
this.setState({ isRequestRunning: false }, () => {
|
||||
setSelected("close");
|
||||
onClose();
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
onChange = e => {
|
||||
const userIndex = this.state.listUsers.findIndex(
|
||||
x => x.id === e.target.value
|
||||
);
|
||||
const newUsersList = this.state.listUsers;
|
||||
newUsersList[userIndex].checked = !newUsersList[userIndex].checked;
|
||||
|
||||
const newUserIds = [];
|
||||
|
||||
for (let item of newUsersList) {
|
||||
if (item.checked === true) {
|
||||
newUserIds.push(item.id);
|
||||
}
|
||||
}
|
||||
|
||||
this.setState({ listUsers: newUsersList, userIds: newUserIds });
|
||||
};
|
||||
|
||||
render() {
|
||||
const { t, onClose, visible } = this.props;
|
||||
const { isRequestRunning, userIds, listUsers } = this.state;
|
||||
const itemSize = 25;
|
||||
const containerStyles = { height: listUsers.length * 25, maxHeight: 220 };
|
||||
|
||||
const renderItems = memo(({ data, index, style }) => {
|
||||
return (
|
||||
<Checkbox
|
||||
truncate
|
||||
style={style}
|
||||
className="modal-dialog-checkbox"
|
||||
value={data[index].id}
|
||||
onChange={this.onChange}
|
||||
key={`checkbox_${index}`}
|
||||
isChecked={data[index].checked}
|
||||
label={data[index].displayName}
|
||||
isDisabled={data[index].disabled}
|
||||
/>
|
||||
);
|
||||
}, areEqual);
|
||||
|
||||
const renderList = ({ height, width }) => (
|
||||
<List
|
||||
className="List"
|
||||
height={height}
|
||||
width={width}
|
||||
itemSize={itemSize}
|
||||
itemCount={listUsers.length}
|
||||
itemData={listUsers}
|
||||
outerElementType={CustomScrollbarsVirtualList}
|
||||
>
|
||||
{renderItems}
|
||||
</List>
|
||||
);
|
||||
|
||||
//console.log("DeleteGroupUsersDialog render");
|
||||
return (
|
||||
<ModalDialogContainer>
|
||||
<ModalDialog
|
||||
visible={visible}
|
||||
onClose={onClose}
|
||||
headerContent={t("DeleteGroupUsersMessageHeader")}
|
||||
bodyContent={
|
||||
<>
|
||||
<Text>{t("DeleteGroupUsersMessage")}</Text>
|
||||
<Text>{t("NotBeUndone")}</Text>
|
||||
<br />
|
||||
<Text color="#c30" fontSize="18px">
|
||||
{t("Warning")}
|
||||
</Text>
|
||||
<br />
|
||||
<Text>{t("DeleteUserDataConfirmation")}</Text>
|
||||
<ToggleContent
|
||||
className="toggle-content-dialog"
|
||||
label={t("ShowUsersList")}
|
||||
>
|
||||
<div style={containerStyles} className="modal-dialog-content">
|
||||
<AutoSizer>{renderList}</AutoSizer>
|
||||
</div>
|
||||
</ToggleContent>
|
||||
</>
|
||||
}
|
||||
footerContent={
|
||||
<>
|
||||
<Button
|
||||
label={t("OKButton")}
|
||||
size="medium"
|
||||
primary
|
||||
onClick={this.onDeleteGroupUsers}
|
||||
isLoading={isRequestRunning}
|
||||
isDisabled={!userIds.length}
|
||||
/>
|
||||
<Button
|
||||
className="button-dialog"
|
||||
label={t("CancelButton")}
|
||||
size="medium"
|
||||
onClick={onClose}
|
||||
isDisabled={isRequestRunning}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
</ModalDialogContainer>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const DeleteGroupUsersDialogTranslated = withTranslation()(
|
||||
DeleteGroupUsersDialogComponent
|
||||
);
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
export default connect(null, { removeUser })(withRouter(DeleteUsersDialog));
|
@ -0,0 +1,12 @@
|
||||
{
|
||||
"NotBeUndone": "Note: this action cannot be undone.",
|
||||
"Warning": "Warning",
|
||||
"DeleteUserDataConfirmation": "User's personal documents that are available to others will be deleted. To avoid this, you must start the data reassign process before deleting.",
|
||||
"OKButton": "OK",
|
||||
"CancelButton": "Cancel",
|
||||
|
||||
"DeleteGroupUsersMessage": "The selected disabled users will be deleted from the portal.",
|
||||
"DeleteGroupUsersMessageHeader": "Delete the users from portal",
|
||||
"DeleteGroupUsersSuccessMessage": "Users have been successfully deleted.",
|
||||
"ShowUsersList": "View users list"
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
{
|
||||
"NotBeUndone": "Внимание: это действие необратимо.",
|
||||
"Warning": "Внимание!",
|
||||
"DeleteUserDataConfirmation": "Будут удалены личные документы пользователя, доступные для других. Чтобы избежать этого, нужно перед удалением запустить процесс передачи данных.",
|
||||
"OKButton": "ОК",
|
||||
"CancelButton": "Отмена",
|
||||
|
||||
"DeleteGroupUsersMessage": "Выбранные заблокированные пользователи будут удалены с портала.",
|
||||
"DeleteGroupUsersMessageHeader": "Удаление пользователей с портала",
|
||||
"DeleteGroupUsersSuccessMessage": "Пользователи были успешно удалены",
|
||||
"ShowUsersList": "Показать список пользователей"
|
||||
|
||||
}
|
@ -1,10 +1,9 @@
|
||||
import styled from 'styled-components';
|
||||
import styled from "styled-components";
|
||||
|
||||
const ModalDialogContainer = styled.div`
|
||||
|
||||
.flex {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
.flex {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.text-dialog {
|
||||
@ -20,7 +19,7 @@ const ModalDialogContainer = styled.div`
|
||||
}
|
||||
|
||||
.warning-text {
|
||||
margin: 20px 0;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.textarea-dialog {
|
||||
@ -38,7 +37,22 @@ const ModalDialogContainer = styled.div`
|
||||
|
||||
.field-body {
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
||||
.toggle-content-dialog {
|
||||
.heading-toggle-content {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.modal-dialog-content {
|
||||
padding: 8px 16px;
|
||||
border: 1px solid lightgray;
|
||||
|
||||
.modal-dialog-checkbox:not(:last-child) {
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default ModalDialogContainer;
|
||||
export default ModalDialogContainer;
|
||||
|
@ -0,0 +1,54 @@
|
||||
import i18n from "i18next";
|
||||
import Backend from "i18next-xhr-backend";
|
||||
import config from "../../../../package.json";
|
||||
import { constants } from 'asc-web-common';
|
||||
const { LANGUAGE } = constants;
|
||||
|
||||
const newInstance = i18n.createInstance();
|
||||
|
||||
if (process.env.NODE_ENV === "production") {
|
||||
newInstance
|
||||
.use(Backend)
|
||||
.init({
|
||||
lng: localStorage.getItem(LANGUAGE) || 'en',
|
||||
fallbackLng: "en",
|
||||
|
||||
interpolation: {
|
||||
escapeValue: false, // not needed for react as it escapes by default
|
||||
},
|
||||
|
||||
react: {
|
||||
useSuspense: true
|
||||
},
|
||||
backend: {
|
||||
loadPath: `${config.homepage}/locales/DeleteProfileEverDialog/{{lng}}/{{ns}}.json`
|
||||
}
|
||||
});
|
||||
} else if (process.env.NODE_ENV === "development") {
|
||||
|
||||
const resources = {
|
||||
en: {
|
||||
translation: require("./locales/en/translation.json")
|
||||
},
|
||||
ru: {
|
||||
translation: require("./locales/ru/translation.json")
|
||||
},
|
||||
};
|
||||
|
||||
newInstance.init({
|
||||
resources: resources,
|
||||
lng: localStorage.getItem(LANGUAGE) || 'en',
|
||||
fallbackLng: "en",
|
||||
debug: true,
|
||||
|
||||
interpolation: {
|
||||
escapeValue: false, // not needed for react as it escapes by default
|
||||
},
|
||||
|
||||
react: {
|
||||
useSuspense: true
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export default newInstance;
|
@ -0,0 +1,178 @@
|
||||
import React, { memo } from "react";
|
||||
import { withRouter } from "react-router";
|
||||
import PropTypes from "prop-types";
|
||||
import {
|
||||
toastr,
|
||||
ModalDialog,
|
||||
Button,
|
||||
Text,
|
||||
ToggleContent,
|
||||
Checkbox,
|
||||
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 i18n from "./i18n";
|
||||
import { api, utils } from "asc-web-common";
|
||||
import ModalDialogContainer from "../ModalDialogContainer";
|
||||
|
||||
const { resendUserInvites } = api.people;
|
||||
const { changeLanguage } = utils;
|
||||
|
||||
class SendInviteDialogComponent extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
changeLanguage(i18n);
|
||||
|
||||
const { userIds, selectedUsers } = props;
|
||||
|
||||
const listUsers = selectedUsers.map((item, index) => {
|
||||
const disabled = userIds.find(x => x === item.id);
|
||||
return (selectedUsers[index] = {
|
||||
...selectedUsers[index],
|
||||
checked: disabled ? true : false,
|
||||
disabled: disabled ? false : true
|
||||
});
|
||||
});
|
||||
|
||||
this.state = {
|
||||
listUsers,
|
||||
isRequestRunning: false,
|
||||
userIds
|
||||
};
|
||||
}
|
||||
|
||||
onSendInvite = () => {
|
||||
const { t, setSelected, onClose } = this.props;
|
||||
const { userIds } = this.state;
|
||||
|
||||
this.setState({ isRequestRunning: true }, () => {
|
||||
resendUserInvites(userIds)
|
||||
.then(() => toastr.success(t("SuccessSendInvitation")))
|
||||
.catch(error => toastr.error(error))
|
||||
.finally(() => {
|
||||
this.setState({ isRequestRunning: false }, () => {
|
||||
setSelected("close");
|
||||
onClose();
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
onChange = e => {
|
||||
const userIndex = this.state.listUsers.findIndex(
|
||||
x => x.id === e.target.value
|
||||
);
|
||||
const newUsersList = this.state.listUsers;
|
||||
newUsersList[userIndex].checked = !newUsersList[userIndex].checked;
|
||||
|
||||
const newUserIds = [];
|
||||
|
||||
for (let item of newUsersList) {
|
||||
if (item.checked === true) {
|
||||
newUserIds.push(item.id);
|
||||
}
|
||||
}
|
||||
|
||||
this.setState({ listUsers: newUsersList, userIds: newUserIds });
|
||||
};
|
||||
|
||||
render() {
|
||||
const { t, onClose, visible } = this.props;
|
||||
const { listUsers, isRequestRunning, userIds } = this.state;
|
||||
const itemSize = 25;
|
||||
const containerStyles = { height: listUsers.length * 25, maxHeight: 220 };
|
||||
|
||||
const renderItems = memo(({ data, index, style }) => {
|
||||
return (
|
||||
<Checkbox
|
||||
truncate
|
||||
style={style}
|
||||
className="modal-dialog-checkbox"
|
||||
value={data[index].id}
|
||||
onChange={this.onChange}
|
||||
key={`checkbox_${index}`}
|
||||
isChecked={data[index].checked}
|
||||
label={data[index].displayName}
|
||||
isDisabled={data[index].disabled}
|
||||
/>
|
||||
);
|
||||
}, areEqual);
|
||||
|
||||
const renderList = ({ height, width }) => (
|
||||
<List
|
||||
className="List"
|
||||
height={height}
|
||||
width={width}
|
||||
itemSize={itemSize}
|
||||
itemCount={listUsers.length}
|
||||
itemData={listUsers}
|
||||
outerElementType={CustomScrollbarsVirtualList}
|
||||
>
|
||||
{renderItems}
|
||||
</List>
|
||||
);
|
||||
|
||||
//console.log("SendInviteDialog render");
|
||||
return (
|
||||
<ModalDialogContainer>
|
||||
<ModalDialog
|
||||
visible={visible}
|
||||
onClose={onClose}
|
||||
headerContent={t("SendInviteAgain")}
|
||||
bodyContent={
|
||||
<>
|
||||
<Text>{t("SendInviteAgainDialog")}</Text>
|
||||
<Text>{t("SendInviteAgainDialogMessage")}</Text>
|
||||
<ToggleContent
|
||||
className="toggle-content-dialog"
|
||||
label={t("ShowUsersList")}
|
||||
>
|
||||
<div style={containerStyles} className="modal-dialog-content">
|
||||
<AutoSizer>{renderList}</AutoSizer>
|
||||
</div>
|
||||
</ToggleContent>
|
||||
</>
|
||||
}
|
||||
footerContent={
|
||||
<>
|
||||
<Button
|
||||
label={t("OKButton")}
|
||||
size="medium"
|
||||
primary
|
||||
onClick={this.onSendInvite}
|
||||
isLoading={isRequestRunning}
|
||||
isDisabled={!userIds.length}
|
||||
/>
|
||||
<Button
|
||||
className="button-dialog"
|
||||
label={t("CancelButton")}
|
||||
size="medium"
|
||||
onClick={onClose}
|
||||
isDisabled={isRequestRunning}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
</ModalDialogContainer>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const SendInviteDialogTranslated = withTranslation()(SendInviteDialogComponent);
|
||||
|
||||
const SendInviteDialog = props => (
|
||||
<SendInviteDialogTranslated i18n={i18n} {...props} />
|
||||
);
|
||||
|
||||
SendInviteDialog.propTypes = {
|
||||
visible: PropTypes.bool.isRequired,
|
||||
onClose: PropTypes.func.isRequired,
|
||||
userIds: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||
selectedUsers: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
setSelected: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default withRouter(SendInviteDialog);
|
@ -0,0 +1,10 @@
|
||||
{
|
||||
"OKButton": "OK",
|
||||
"CancelButton": "Cancel",
|
||||
"SendInviteAgain": "Send invitation once again",
|
||||
"SuccessSendInvitation": "The invitation was successfully sent",
|
||||
|
||||
"ShowUsersList": "View users list",
|
||||
"SendInviteAgainDialog": "The invitation to the portal will be sent once again to the selected users with the 'Pending' status who are not disabled.",
|
||||
"SendInviteAgainDialogMessage": "After the users confirm the invitation to the portal their status will change to 'Active'"
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
{
|
||||
"OKButton": "ОК",
|
||||
"CancelButton": "Отмена",
|
||||
"SendInviteAgain": "Отправить приглашение еще раз",
|
||||
"SuccessSendInvitation": "Приглашение успешно отправлено",
|
||||
|
||||
"ShowUsersList": "Показать список пользователей",
|
||||
"SendInviteAgainDialog": "Приглашение на портал будет отправлено еще раз выбранным пользователям со статусом 'Ожидание', которые не заблокированы.",
|
||||
"SendInviteAgainDialogMessage": "После того, как пользователи подтвердят приглашение на портал, их статус изменится на 'Активный'"
|
||||
}
|
@ -3,7 +3,11 @@ import ChangePasswordDialog from "./ChangePasswordDialog";
|
||||
import ChangePhoneDialog from "./ChangePhoneDialog";
|
||||
import DeleteProfileEverDialog from "./DeleteProfileEverDialog";
|
||||
import DeleteSelfProfileDialog from "./DeleteSelfProfileDialog";
|
||||
import InviteDialog from './InviteDialog';
|
||||
import DeleteUsersDialog from "./DeleteUsersDialog";
|
||||
import InviteDialog from "./InviteDialog";
|
||||
import SendInviteDialog from "./SendInviteDialog";
|
||||
import ChangeUserStatusDialog from "./ChangeUserStatusDialog";
|
||||
import ChangeUserTypeDialog from "./ChangeUserTypeDialog";
|
||||
|
||||
export {
|
||||
ChangeEmailDialog,
|
||||
@ -11,5 +15,9 @@ export {
|
||||
ChangePhoneDialog,
|
||||
DeleteProfileEverDialog,
|
||||
DeleteSelfProfileDialog,
|
||||
DeleteUsersDialog,
|
||||
InviteDialog,
|
||||
};
|
||||
SendInviteDialog,
|
||||
ChangeUserStatusDialog,
|
||||
ChangeUserTypeDialog
|
||||
};
|
||||
|
@ -7,43 +7,57 @@ import {
|
||||
toastr,
|
||||
ContextMenuButton
|
||||
} from "asc-web-components";
|
||||
import { Headline } from 'asc-web-common';
|
||||
import { Headline } from "asc-web-common";
|
||||
import { connect } from "react-redux";
|
||||
import {
|
||||
getSelectedGroup,
|
||||
getSelectionIds
|
||||
getUserType,
|
||||
getUsersStatus,
|
||||
getInactiveUsers,
|
||||
getDeleteUsers,
|
||||
getUsersIds
|
||||
} from "../../../../../store/people/selectors";
|
||||
import { withTranslation } from "react-i18next";
|
||||
import {
|
||||
updateUserStatus,
|
||||
updateUserType,
|
||||
fetchPeople,
|
||||
removeUser
|
||||
removeUser,
|
||||
setSelected
|
||||
} from "../../../../../store/people/actions";
|
||||
import { deleteGroup } from "../../../../../store/group/actions";
|
||||
import { store, api, constants } from 'asc-web-common';
|
||||
import { InviteDialog } from '../../../../dialogs';
|
||||
import { store, constants } from "asc-web-common";
|
||||
import {
|
||||
InviteDialog,
|
||||
DeleteUsersDialog,
|
||||
SendInviteDialog,
|
||||
ChangeUserStatusDialog,
|
||||
ChangeUserTypeDialog
|
||||
} from "../../../../dialogs";
|
||||
|
||||
const { isAdmin } = store.auth.selectors;
|
||||
const { resendUserInvites } = api.people;
|
||||
const { EmployeeStatus, EmployeeType } = constants;
|
||||
|
||||
const isRefetchPeople = true;
|
||||
const { EmployeeType, EmployeeStatus } = constants;
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
${props => props.isHeaderVisible && css`width: calc(100% + 76px);`}
|
||||
${props =>
|
||||
props.isHeaderVisible &&
|
||||
css`
|
||||
width: calc(100% + 76px);
|
||||
`}
|
||||
}
|
||||
|
||||
.group-button-menu-container {
|
||||
margin: 0 -16px;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
padding-bottom: 56px;
|
||||
|
||||
|
||||
@media (max-width: 1024px) {
|
||||
& > div:first-child {
|
||||
${props => props.isArticlePinned && css`width: calc(100% - 240px);`}
|
||||
${props =>
|
||||
props.isArticlePinned &&
|
||||
css`
|
||||
width: calc(100% - 240px);
|
||||
`}
|
||||
position: absolute;
|
||||
top: 56px;
|
||||
z-index: 180;
|
||||
@ -79,6 +93,12 @@ 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 {
|
||||
isHeaderVisible,
|
||||
@ -90,62 +110,57 @@ const SectionHeaderContent = props => {
|
||||
group,
|
||||
isAdmin,
|
||||
t,
|
||||
selection,
|
||||
updateUserStatus,
|
||||
updateUserType,
|
||||
onLoading,
|
||||
filter,
|
||||
history,
|
||||
settings,
|
||||
deleteGroup,
|
||||
removeUser
|
||||
usersWithEmployeeType,
|
||||
usersWithGuestType,
|
||||
usersWithActiveStatus,
|
||||
usersWithDisableStatus,
|
||||
usersToInvite,
|
||||
usersToRemove,
|
||||
setSelected,
|
||||
selection
|
||||
} = props;
|
||||
|
||||
const selectedUserIds = getSelectionIds(selection);
|
||||
//console.log("SectionHeaderContent render", selection, selectedUserIds);
|
||||
//console.log("SectionHeaderContent render");
|
||||
|
||||
const onSetActive = useCallback(() => {
|
||||
onLoading(true);
|
||||
updateUserStatus(EmployeeStatus.Active, selectedUserIds, isRefetchPeople)
|
||||
.then(() => toastr.success(t("SuccessChangeUserStatus")))
|
||||
.catch(error => toastr.error(error))
|
||||
.finally(() => onLoading(false));
|
||||
}, [selectedUserIds, updateUserStatus, t, onLoading]);
|
||||
const onSetEmployee = useCallback(
|
||||
() => setShowEmployeeDialog(!showEmployeeDialog),
|
||||
[showEmployeeDialog]
|
||||
);
|
||||
|
||||
const onSetDisabled = useCallback(() => {
|
||||
onLoading(true);
|
||||
updateUserStatus(EmployeeStatus.Disabled, selectedUserIds, isRefetchPeople)
|
||||
.then(() => toastr.success(t("SuccessChangeUserStatus")))
|
||||
.catch(error => toastr.error(error))
|
||||
.finally(() => onLoading(false));
|
||||
}, [selectedUserIds, updateUserStatus, t, onLoading]);
|
||||
const onSetGuest = useCallback(() => setShowGuestDialog(!showGuestDialog), [
|
||||
showGuestDialog
|
||||
]);
|
||||
|
||||
const onSetEmployee = useCallback(() => {
|
||||
updateUserType(EmployeeType.User, selectedUserIds);
|
||||
toastr.success(t("SuccessChangeUserType"));
|
||||
}, [selectedUserIds, updateUserType, t]);
|
||||
const onSetActive = useCallback(
|
||||
() => setShowActiveDialog(!showActiveDialog),
|
||||
[showActiveDialog]
|
||||
);
|
||||
|
||||
const onSetGuest = useCallback(() => {
|
||||
updateUserType(EmployeeType.Guest, selectedUserIds);
|
||||
toastr.success(t("SuccessChangeUserType"));
|
||||
}, [selectedUserIds, updateUserType, t]);
|
||||
const onSetDisabled = useCallback(
|
||||
() => setShowDisableDialog(!showDisableDialog),
|
||||
[showDisableDialog]
|
||||
);
|
||||
|
||||
const onSentInviteAgain = useCallback(() => {
|
||||
resendUserInvites(selectedUserIds)
|
||||
.then(() => toastr.success(t('SuccessSendInvitation')))
|
||||
.catch(error => toastr.error(error));
|
||||
}, [selectedUserIds, t]);
|
||||
const onSendInviteAgain = useCallback(
|
||||
() => setSendInviteDialog(!showSendInviteDialog),
|
||||
[showSendInviteDialog]
|
||||
);
|
||||
|
||||
const onDelete = useCallback(() => {
|
||||
onLoading(true);
|
||||
removeUser(selectedUserIds, filter)
|
||||
.then(() => {
|
||||
toastr.success(t('SuccessfullyRemovedUsers'));
|
||||
return fetchPeople(filter);
|
||||
})
|
||||
.catch(error => toastr.error(error))
|
||||
.finally(() => onLoading(false));
|
||||
}, [selectedUserIds, removeUser, onLoading, filter, t]);
|
||||
const onDelete = useCallback(() => setDeleteDialog(!showDeleteDialog), [
|
||||
showDeleteDialog
|
||||
]);
|
||||
|
||||
const onSendEmail = useCallback(() => {
|
||||
let str = "";
|
||||
for (let item of selection) {
|
||||
str += `${item.email},`;
|
||||
}
|
||||
window.open(`mailto: ${str}`, "_self");
|
||||
}, [selection]);
|
||||
|
||||
const menuItems = [
|
||||
{
|
||||
@ -162,38 +177,42 @@ const SectionHeaderContent = props => {
|
||||
onSelect: item => onSelect(item.key)
|
||||
},
|
||||
{
|
||||
label: t('ChangeToUser', { userCaption: settings.customNames.userCaption }),
|
||||
disabled: !selection.length,
|
||||
label: t("ChangeToUser", {
|
||||
userCaption: settings.customNames.userCaption
|
||||
}),
|
||||
disabled: !usersWithEmployeeType.length,
|
||||
onClick: onSetEmployee
|
||||
},
|
||||
{
|
||||
label: t('ChangeToGuest', { guestCaption: settings.customNames.guestCaption }),
|
||||
disabled: !selection.length,
|
||||
label: t("ChangeToGuest", {
|
||||
guestCaption: settings.customNames.guestCaption
|
||||
}),
|
||||
disabled: !usersWithGuestType.length,
|
||||
onClick: onSetGuest
|
||||
},
|
||||
{
|
||||
label: t("LblSetActive"),
|
||||
disabled: !selection.length,
|
||||
disabled: !usersWithActiveStatus.length,
|
||||
onClick: onSetActive
|
||||
},
|
||||
{
|
||||
label: t("LblSetDisabled"),
|
||||
disabled: !selection.length,
|
||||
disabled: !usersWithDisableStatus.length,
|
||||
onClick: onSetDisabled
|
||||
},
|
||||
{
|
||||
label: t("LblInviteAgain"),
|
||||
disabled: !selection.length,
|
||||
onClick: onSentInviteAgain
|
||||
disabled: !usersToInvite.length,
|
||||
onClick: onSendInviteAgain
|
||||
},
|
||||
{
|
||||
label: t("LblSendEmail"),
|
||||
disabled: !selection.length,
|
||||
onClick: toastr.success.bind(this, t("SendEmailAction"))
|
||||
onClick: onSendEmail
|
||||
},
|
||||
{
|
||||
label: t("DeleteButton"),
|
||||
disabled: !selection.length,
|
||||
disabled: !usersToRemove.length,
|
||||
onClick: onDelete
|
||||
}
|
||||
];
|
||||
@ -236,8 +255,9 @@ const SectionHeaderContent = props => {
|
||||
history.push(`${settings.homepage}/group/create`);
|
||||
}, [history, settings]);
|
||||
|
||||
const onInvitationDialogClick = useCallback(() =>
|
||||
setDialogVisible(!dialogVisible), [dialogVisible]
|
||||
const onInvitationDialogClick = useCallback(
|
||||
() => setDialogVisible(!dialogVisible),
|
||||
[dialogVisible]
|
||||
);
|
||||
|
||||
const getContextOptionsPlus = useCallback(() => {
|
||||
@ -258,24 +278,97 @@ const SectionHeaderContent = props => {
|
||||
label: groupCaption,
|
||||
onClick: goToGroupCreate
|
||||
},
|
||||
{ key: 'separator', isSeparator: true },
|
||||
{ key: "separator", isSeparator: true },
|
||||
{
|
||||
key: "make-invitation-link",
|
||||
label: t("MakeInvitationLink"),
|
||||
onClick: onInvitationDialogClick
|
||||
}/* ,
|
||||
} /* ,
|
||||
{
|
||||
key: "send-invitation",
|
||||
label: t("SendInviteAgain"),
|
||||
onClick: onSentInviteAgain
|
||||
} */
|
||||
];
|
||||
}, [settings, t, goToEmployeeCreate, goToGuestCreate, goToGroupCreate, onInvitationDialogClick/* , onSentInviteAgain */]);
|
||||
}, [
|
||||
settings,
|
||||
t,
|
||||
goToEmployeeCreate,
|
||||
goToGuestCreate,
|
||||
goToGroupCreate,
|
||||
onInvitationDialogClick /* , onSentInviteAgain */
|
||||
]);
|
||||
|
||||
const isArticlePinned = window.localStorage.getItem('asc_article_pinned_key');
|
||||
const isArticlePinned = window.localStorage.getItem("asc_article_pinned_key");
|
||||
|
||||
return (
|
||||
<StyledContainer isHeaderVisible={isHeaderVisible} isArticlePinned={isArticlePinned}>
|
||||
<StyledContainer
|
||||
isHeaderVisible={isHeaderVisible}
|
||||
isArticlePinned={isArticlePinned}
|
||||
>
|
||||
{showEmployeeDialog && (
|
||||
<ChangeUserTypeDialog
|
||||
visible={showEmployeeDialog}
|
||||
userIds={getUsersIds(usersWithEmployeeType)}
|
||||
selectedUsers={selection}
|
||||
onClose={onSetEmployee}
|
||||
userType={EmployeeType.User}
|
||||
setSelected={setSelected}
|
||||
/>
|
||||
)}
|
||||
|
||||
{showGuestDialog && (
|
||||
<ChangeUserTypeDialog
|
||||
visible={showGuestDialog}
|
||||
userIds={getUsersIds(usersWithGuestType)}
|
||||
selectedUsers={selection}
|
||||
onClose={onSetGuest}
|
||||
userType={EmployeeType.Guest}
|
||||
setSelected={setSelected}
|
||||
/>
|
||||
)}
|
||||
{showActiveDialog && (
|
||||
<ChangeUserStatusDialog
|
||||
visible={showActiveDialog}
|
||||
userIds={getUsersIds(usersWithActiveStatus)}
|
||||
selectedUsers={selection}
|
||||
onClose={onSetActive}
|
||||
userStatus={EmployeeStatus.Active}
|
||||
setSelected={setSelected}
|
||||
/>
|
||||
)}
|
||||
{showDisableDialog && (
|
||||
<ChangeUserStatusDialog
|
||||
visible={showDisableDialog}
|
||||
userIds={getUsersIds(usersWithDisableStatus)}
|
||||
selectedUsers={selection}
|
||||
onClose={onSetDisabled}
|
||||
userStatus={EmployeeStatus.Disabled}
|
||||
setSelected={setSelected}
|
||||
/>
|
||||
)}
|
||||
|
||||
{showSendInviteDialog && (
|
||||
<SendInviteDialog
|
||||
visible={showSendInviteDialog}
|
||||
onClose={onSendInviteAgain}
|
||||
userIds={getUsersIds(usersToInvite)}
|
||||
selectedUsers={selection}
|
||||
setSelected={setSelected}
|
||||
/>
|
||||
)}
|
||||
|
||||
{showDeleteDialog && (
|
||||
<DeleteUsersDialog
|
||||
visible={showDeleteDialog}
|
||||
onClose={onDelete}
|
||||
userIds={getUsersIds(usersToRemove)}
|
||||
selectedUsers={selection}
|
||||
filter={filter}
|
||||
setSelected={setSelected}
|
||||
/>
|
||||
)}
|
||||
|
||||
{isHeaderVisible ? (
|
||||
<div className="group-button-menu-container">
|
||||
<GroupButtonsMenu
|
||||
@ -291,66 +384,107 @@ const SectionHeaderContent = props => {
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div className="header-container">
|
||||
{group ? (
|
||||
<>
|
||||
<Headline className='headline-header' type="content" truncate={true}>{group.name}</Headline>
|
||||
{isAdmin && (
|
||||
<div className="header-container">
|
||||
{group ? (
|
||||
<>
|
||||
<Headline
|
||||
className="headline-header"
|
||||
type="content"
|
||||
truncate={true}
|
||||
>
|
||||
{group.name}
|
||||
</Headline>
|
||||
{isAdmin && (
|
||||
<ContextMenuButton
|
||||
className="action-button"
|
||||
directionX="right"
|
||||
title={t("Actions")}
|
||||
iconName="VerticalDotsIcon"
|
||||
size={16}
|
||||
color="#A3A9AE"
|
||||
getData={getContextOptionsGroup}
|
||||
isDisabled={false}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Headline
|
||||
className="headline-header"
|
||||
truncate={true}
|
||||
type="content"
|
||||
>
|
||||
{settings.customNames.groupsCaption}
|
||||
</Headline>
|
||||
{isAdmin && (
|
||||
<>
|
||||
<ContextMenuButton
|
||||
className="action-button"
|
||||
directionX="right"
|
||||
title={t("Actions")}
|
||||
iconName="VerticalDotsIcon"
|
||||
iconName="PlusIcon"
|
||||
size={16}
|
||||
color="#A3A9AE"
|
||||
getData={getContextOptionsGroup}
|
||||
color="#657077"
|
||||
getData={getContextOptionsPlus}
|
||||
isDisabled={false}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Headline className='headline-header' truncate={true} type="content">{settings.customNames.groupsCaption}</Headline>
|
||||
{isAdmin && (
|
||||
<>
|
||||
<ContextMenuButton
|
||||
className="action-button"
|
||||
directionX="right"
|
||||
title={t("Actions")}
|
||||
iconName="PlusIcon"
|
||||
size={16}
|
||||
color="#657077"
|
||||
getData={getContextOptionsPlus}
|
||||
isDisabled={false}
|
||||
/>
|
||||
{dialogVisible &&
|
||||
<InviteDialog
|
||||
visible={dialogVisible}
|
||||
onClose={onInvitationDialogClick}
|
||||
onCloseButton={onInvitationDialogClick}
|
||||
/>
|
||||
}
|
||||
</>
|
||||
{dialogVisible && (
|
||||
<InviteDialog
|
||||
visible={dialogVisible}
|
||||
onClose={onInvitationDialogClick}
|
||||
onCloseButton={onInvitationDialogClick}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</StyledContainer>
|
||||
);
|
||||
};
|
||||
|
||||
const mapStateToProps = state => {
|
||||
const selection = state.people.selection;
|
||||
const activeUsers = 1;
|
||||
const disabledUsers = 2;
|
||||
const currentUserId = state.auth.user.id;
|
||||
const employeeStatus = true;
|
||||
const guestStatus = false;
|
||||
|
||||
return {
|
||||
group: getSelectedGroup(state.people.groups, state.people.selectedGroup),
|
||||
selection: state.people.selection,
|
||||
selection,
|
||||
isAdmin: isAdmin(state.auth.user),
|
||||
filter: state.people.filter,
|
||||
settings: state.auth.settings
|
||||
settings: state.auth.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)
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
{ updateUserStatus, updateUserType, fetchPeople, deleteGroup, removeUser }
|
||||
)(withTranslation()(withRouter(SectionHeaderContent)));
|
||||
export default connect(mapStateToProps, {
|
||||
updateUserStatus,
|
||||
fetchPeople,
|
||||
deleteGroup,
|
||||
removeUser,
|
||||
setSelected
|
||||
})(withTranslation()(withRouter(SectionHeaderContent)));
|
||||
|
@ -85,14 +85,9 @@ class PureHome extends React.Component {
|
||||
};
|
||||
|
||||
onClose = () => {
|
||||
const { selection, setSelected } = this.props;
|
||||
|
||||
if (!selection.length) {
|
||||
setSelected("none");
|
||||
this.setState({ isHeaderVisible: false });
|
||||
} else {
|
||||
setSelected("close");
|
||||
}
|
||||
const { setSelected } = this.props;
|
||||
setSelected("none");
|
||||
this.setState({ isHeaderVisible: false });
|
||||
};
|
||||
|
||||
onLoading = status => {
|
||||
|
@ -23,8 +23,6 @@
|
||||
"Administrator": "Administrator",
|
||||
"LblOther": "Other",
|
||||
"DeleteButton": "Delete",
|
||||
"SuccessChangeUserStatus": "The user status was successfully changed",
|
||||
"SuccessChangeUserType": "The user type was successfully changed",
|
||||
"LblSelect": "Select",
|
||||
"More": "More",
|
||||
"CloseButton": "Close",
|
||||
@ -35,7 +33,6 @@
|
||||
"MessageEmailActivationInstuctionsSentOnEmail": "The email activation instructions have been sent to the <1>{{email}}</1> email address",
|
||||
"Search": "Search",
|
||||
"SendInviteAgain": "Send invitation once again",
|
||||
"SuccessSendInvitation": "The invitation was successfully sent",
|
||||
|
||||
"CountPerPage": "{{count}} per page",
|
||||
"PageOfTotalPage": "{{page}} of {{totalPage}}",
|
||||
|
@ -23,8 +23,6 @@
|
||||
"Administrator": "Администратор",
|
||||
"LblOther": "Другое",
|
||||
"DeleteButton": "Удалить",
|
||||
"SuccessChangeUserStatus": "Статус пользователя успешно изменен",
|
||||
"SuccessChangeUserType": "Тип пользователя успешно изменен",
|
||||
"LblSelect": "Выберите",
|
||||
"More": "Больше",
|
||||
"CloseButton": "Закрыть",
|
||||
@ -35,7 +33,6 @@
|
||||
"MessageEmailActivationInstuctionsSentOnEmail": "Инструкции по активации электронной почты были отправлены на адрес <1>{{email}}</1>",
|
||||
"Search": "Поиск",
|
||||
"SendInviteAgain": "Отправить приглашение ещё раз",
|
||||
"SuccessSendInvitation": "Приглашение успешно отправлено",
|
||||
|
||||
"PageOfTotalPage": "{{page}} из {{totalPage}}",
|
||||
"CountPerPage": "{{count}} на странице",
|
||||
|
@ -67,6 +67,48 @@
|
||||
"MessageSendPasswordChangeInstructionsOnEmail",
|
||||
"SendButton"
|
||||
]
|
||||
},
|
||||
"DeleteUsersDialog":{
|
||||
"Resource": [
|
||||
"OKButton",
|
||||
"CancelButton",
|
||||
"Warning",
|
||||
"DeleteUserDataConfirmation"
|
||||
],
|
||||
"UserControlsCommonResource":[
|
||||
"NotBeUndone"
|
||||
]
|
||||
},
|
||||
"SendInviteDialog":{
|
||||
"Resource": [
|
||||
"OKButton",
|
||||
"CancelButton",
|
||||
"SendInviteAgain",
|
||||
"DisabledEmployeeTitle"
|
||||
],
|
||||
"PeopleJSResource": [
|
||||
"SuccessSendInvitation"
|
||||
]
|
||||
},
|
||||
"ChangeUserStatusDialog":{
|
||||
"PeopleJSResource": [
|
||||
"SuccessChangeUserStatus"
|
||||
],
|
||||
"Resource": [
|
||||
"CancelButton"
|
||||
]
|
||||
},
|
||||
"ChangeUserTypeDialog":{
|
||||
"PeopleJSResource": [
|
||||
"SuccessChangeUserType"
|
||||
],
|
||||
"Resource": [
|
||||
"CancelButton",
|
||||
"GuestCaption"
|
||||
],
|
||||
"AuditResource": [
|
||||
"UserCol"
|
||||
]
|
||||
}
|
||||
},
|
||||
"pages": {
|
||||
@ -193,11 +235,6 @@
|
||||
"LblOther",
|
||||
"LblChangeEmail"
|
||||
],
|
||||
"PeopleJSResource": [
|
||||
"SuccessChangeUserStatus",
|
||||
"SuccessChangeUserType",
|
||||
"SuccessSendInvitation"
|
||||
],
|
||||
"UserControlsCommonResource": [
|
||||
"NextPage",
|
||||
"PreviousPage",
|
||||
|
@ -122,10 +122,6 @@ export function getSelectedGroup(groups, selectedGroupId) {
|
||||
return find(groups, (group) => group.id === selectedGroupId);
|
||||
}
|
||||
|
||||
export function getSelectionIds(selections) {
|
||||
return selections.map((user) => { return user.id });
|
||||
}
|
||||
|
||||
export function toEmployeeWrapper(profile) {
|
||||
const emptyData = {
|
||||
id: "",
|
||||
@ -171,4 +167,33 @@ export function filterGroupSelectorOptions(options, template) {
|
||||
return options.filter(option => {
|
||||
return template ? option.label.indexOf(template) > -1 : true;
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export function getUserType(users, status, currentUserId) {
|
||||
return users.filter(
|
||||
x =>
|
||||
!x.isAdmin &&
|
||||
!x.isOwner &&
|
||||
x.isVisitor === status &&
|
||||
x.status !== 2 &&
|
||||
x.id !== currentUserId
|
||||
);
|
||||
}
|
||||
|
||||
export function getUsersStatus(users, status, currentUserId) {
|
||||
return users.filter(
|
||||
x => !x.isOwner && x.status !== status && x.id !== currentUserId
|
||||
);
|
||||
}
|
||||
|
||||
export function getInactiveUsers(users) {
|
||||
return users.filter(x => x.activationStatus === 2 && x.status === 1);
|
||||
}
|
||||
|
||||
export function getDeleteUsers(users) {
|
||||
return users.filter(x => x.status === 2);
|
||||
}
|
||||
|
||||
export function getUsersIds(selections) {
|
||||
return selections.map((user) => { return user.id });
|
||||
}
|
||||
|
@ -99,7 +99,7 @@ describe('<GroupButtonsMenu />', () => {
|
||||
|
||||
instance.groupButtonClick(item);
|
||||
|
||||
expect(wrapper.state('visible')).toBe(false);
|
||||
//expect(wrapper.state('visible')).toBe(false);
|
||||
expect(onClick).toBeCalled();
|
||||
});
|
||||
|
||||
|
@ -85,7 +85,7 @@ class GroupButtonsMenu extends React.PureComponent {
|
||||
groupButtonClick = (item) => {
|
||||
if (item.disabled) return;
|
||||
item.onClick();
|
||||
this.closeMenu();
|
||||
//this.closeMenu();
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
|
Loading…
Reference in New Issue
Block a user