Web People Client: simplified configuration of i18n (+ removed useless requests + removed useless Import page)

This commit is contained in:
Alexey Safronov 2020-08-17 13:17:38 +03:00
parent 5542e211df
commit ac6dfbaebc
44 changed files with 869 additions and 1997 deletions

View File

@ -3,12 +3,19 @@ import { connect } from "react-redux";
import { Router, Switch, Redirect } from "react-router-dom";
import { Loader } from "asc-web-components";
import Home from "./components/pages/Home";
import Profile from './components/pages/Profile';
import ProfileAction from './components/pages/ProfileAction';
import GroupAction from './components/pages/GroupAction';
import Reassign from './components/pages/Reassign';
import Import from './components/pages/Import';
import { history, PrivateRoute, PublicRoute, Login, Error404, StudioLayout, Offline } from "asc-web-common";
import Profile from "./components/pages/Profile";
import ProfileAction from "./components/pages/ProfileAction";
import GroupAction from "./components/pages/GroupAction";
import Reassign from "./components/pages/Reassign";
import {
history,
PrivateRoute,
PublicRoute,
Login,
Error404,
StudioLayout,
Offline
} from "asc-web-common";
/*const Profile = lazy(() => import("./components/pages/Profile"));
const ProfileAction = lazy(() => import("./components/pages/ProfileAction"));
@ -16,16 +23,19 @@ const GroupAction = lazy(() => import("./components/pages/GroupAction"));*/
const App = ({ settings }) => {
const { homepage } = settings;
return (
navigator.onLine ?
return navigator.onLine ? (
<Router history={history}>
<StudioLayout>
<Suspense
fallback={<Loader className="pageLoader" type="rombs" size='40px' />}
fallback={<Loader className="pageLoader" type="rombs" size="40px" />}
>
<Switch>
<Redirect exact from="/" to={`${homepage}`} />
<PrivateRoute exact path={[homepage, `${homepage}/filter`]} component={Home} />
<PrivateRoute
exact
path={[homepage, `${homepage}/filter`]}
component={Home}
/>
<PrivateRoute
path={`${homepage}/view/:userId`}
component={Profile}
@ -56,18 +66,22 @@ const App = ({ settings }) => {
component={Reassign}
restricted
/>
<PrivateRoute
path={`${homepage}/import`}
component={Import}
restricted
<PublicRoute
exact
path={[
"/login",
"/login/error=:error",
"/login/confirmed-email=:confirmedEmail"
]}
component={Login}
/>
<PublicRoute exact path={["/login","/login/error=:error", "/login/confirmed-email=:confirmedEmail"]} component={Login} />
<PrivateRoute component={Error404} />
</Switch>
</Suspense>
</StudioLayout>
</Router>
: <Offline/>
) : (
<Offline />
);
};

View File

@ -1,18 +1,17 @@
import React from 'react';
import { connect } from 'react-redux';
import {
utils,
TreeMenu,
TreeNode,
Icons,
Link
} from "asc-web-components";
import React from "react";
import { connect } from "react-redux";
import { utils, TreeMenu, TreeNode, Icons, Link } from "asc-web-components";
import { history } from "asc-web-common";
import { selectGroup } from '../../../store/people/actions';
import { selectGroup } from "../../../store/people/actions";
import { getSelectedGroup } from "../../../store/people/selectors";
import { withTranslation, I18nextProvider } from 'react-i18next';
import i18n from '../i18n';
import { utils as commonUtils } from 'asc-web-common';
import { withTranslation, I18nextProvider } from "react-i18next";
import { utils as commonUtils } from "asc-web-common";
import { createI18N } from "../../../helpers/i18n";
const i18n = createI18N({
page: "Article",
localesPath: "Article"
});
const { changeLanguage } = commonUtils;
@ -31,28 +30,27 @@ const getItems = data => {
color="#657077"
/>
) : (
""
)
""
)
}
>
{getItems(item.children)}
</TreeNode>
);
}
return (
<TreeNode key={item.key} title={item.title} />
);
return <TreeNode key={item.key} title={item.title} />;
});
};
class ArticleBodyContent extends React.Component {
shouldComponentUpdate(nextProps) {
if(!utils.array.isArrayEqual(nextProps.selectedKeys, this.props.selectedKeys)) {
if (
!utils.array.isArrayEqual(nextProps.selectedKeys, this.props.selectedKeys)
) {
return true;
}
if(!utils.array.isArrayEqual(nextProps.data, this.props.data)) {
if (!utils.array.isArrayEqual(nextProps.data, this.props.data)) {
return true;
}
@ -66,7 +64,9 @@ class ArticleBodyContent extends React.Component {
document.title = currentGroup
? `${currentGroup.name} ${t("People")}`
: `${t("People")} ${t("OrganizationName")}`;
selectGroup(data && data.length === 1 && data[0] !== "root" ? data[0] : null);
selectGroup(
data && data.length === 1 && data[0] !== "root" ? data[0] : null
);
};
switcherIcon = obj => {
@ -104,8 +104,8 @@ class ArticleBodyContent extends React.Component {
{getItems(data)}
</TreeMenu>
);
};
};
}
}
const getTreeGroups = (groups, departments) => {
const linkProps = { fontSize: "14px", fontWeight: 600, noHover: true };
@ -113,32 +113,41 @@ const getTreeGroups = (groups, departments) => {
let newLink = link.split("&");
const index = newLink.findIndex(x => x.includes("group"));
index && newLink.splice(1, 1);
newLink = newLink.join('&');
newLink = newLink.join("&");
const onTitleClick = () => {
history.push("/products/people/");
}
};
const treeData = [
{
key: "root",
title: <Link {...linkProps} onClick={onTitleClick} href={`${history.location.pathname}`}>{departments}</Link>,
root: true,
children: groups.map(g => {
return {
key: g.id,
title: (
<Link
{...linkProps}
href={`${history.location.pathname}?group=${g.id}&${newLink}`}
>
{g.name}
</Link>
),
root: false
};
}) || []
}
{
key: "root",
title: (
<Link
{...linkProps}
onClick={onTitleClick}
href={`${history.location.pathname}`}
>
{departments}
</Link>
),
root: true,
children:
groups.map(g => {
return {
key: g.id,
title: (
<Link
{...linkProps}
href={`${history.location.pathname}?group=${g.id}&${newLink}`}
>
{g.name}
</Link>
),
root: false
};
}) || []
}
];
return treeData;
@ -146,9 +155,13 @@ const getTreeGroups = (groups, departments) => {
const ArticleBodyContentWrapper = withTranslation()(ArticleBodyContent);
const BodyContent = (props) => {
const BodyContent = props => {
changeLanguage(i18n);
return (<I18nextProvider i18n={i18n}><ArticleBodyContentWrapper {...props} /></I18nextProvider>);
return (
<I18nextProvider i18n={i18n}>
<ArticleBodyContentWrapper {...props} />
</I18nextProvider>
);
};
function mapStateToProps(state) {
@ -156,9 +169,14 @@ function mapStateToProps(state) {
return {
data: getTreeGroups(groups, state.auth.settings.customNames.groupsCaption),
selectedKeys: state.people.selectedGroup ? [state.people.selectedGroup] : ["root"],
selectedKeys: state.people.selectedGroup
? [state.people.selectedGroup]
: ["root"],
groups
};
}
export default connect(mapStateToProps, { selectGroup })(BodyContent);
export default connect(
mapStateToProps,
{ selectGroup }
)(BodyContent);

View File

@ -1,16 +1,18 @@
import React from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { withRouter } from 'react-router';
import {
MainButton,
DropDownItem,
toastr
} from "asc-web-components";
import { InviteDialog } from './../../dialogs';
import { withTranslation, I18nextProvider } from 'react-i18next';
import i18n from '../i18n';
import { store, utils } from 'asc-web-common';
import React from "react";
import { connect } from "react-redux";
import PropTypes from "prop-types";
import { withRouter } from "react-router";
import { MainButton, DropDownItem, toastr } from "asc-web-components";
import { InviteDialog } from "./../../dialogs";
import { withTranslation, I18nextProvider } from "react-i18next";
import { store, utils } from "asc-web-common";
import { createI18N } from "../../../helpers/i18n";
const i18n = createI18N({
page: "Article",
localesPath: "Article"
});
const { changeLanguage } = utils;
const { isAdmin } = store.auth.selectors;
@ -19,10 +21,10 @@ class PureArticleMainButtonContent extends React.Component {
super(props);
this.state = {
dialogVisible: false
}
};
}
onDropDownItemClick = (link) => {
onDropDownItemClick = link => {
this.props.history.push(link);
};
@ -34,85 +36,90 @@ class PureArticleMainButtonContent extends React.Component {
goToGuestCreate = () => {
const { history, settings } = this.props;
history.push(`${settings.homepage}/create/guest`);
}
};
goToGroupCreate = () => {
const { history, settings } = this.props;
history.push(`${settings.homepage}/group/create`);
}
};
onNotImplementedClick = (text) => {
onNotImplementedClick = text => {
toastr.success(text);
};
onInvitationDialogClick = () => this.setState({ dialogVisible: !this.state.dialogVisible });
onInvitationDialogClick = () =>
this.setState({ dialogVisible: !this.state.dialogVisible });
render() {
console.log("People ArticleMainButtonContent render");
const { isAdmin, settings, t } = this.props;
const { userCaption, guestCaption, groupCaption } = settings.customNames;
const { dialogVisible } = this.state;
return (
isAdmin ?
<>
<MainButton
isDisabled={false}
isDropdown={true}
text={t('Actions')}
>
<DropDownItem
icon="AddEmployeeIcon"
label={userCaption}
onClick={this.goToEmployeeCreate}
/>
<DropDownItem
icon="AddGuestIcon"
label={guestCaption}
onClick={this.goToGuestCreate}
/>
<DropDownItem
icon="AddDepartmentIcon"
label={groupCaption}
onClick={this.goToGroupCreate}
/>
<DropDownItem isSeparator />
<DropDownItem
icon="InvitationLinkIcon"
label={t('InviteLinkTitle')}
onClick={this.onInvitationDialogClick}
/>
{/* <DropDownItem
return isAdmin ? (
<>
<MainButton isDisabled={false} isDropdown={true} text={t("Actions")}>
<DropDownItem
icon="AddEmployeeIcon"
label={userCaption}
onClick={this.goToEmployeeCreate}
/>
<DropDownItem
icon="AddGuestIcon"
label={guestCaption}
onClick={this.goToGuestCreate}
/>
<DropDownItem
icon="AddDepartmentIcon"
label={groupCaption}
onClick={this.goToGroupCreate}
/>
<DropDownItem isSeparator />
<DropDownItem
icon="InvitationLinkIcon"
label={t("InviteLinkTitle")}
onClick={this.onInvitationDialogClick}
/>
{/* <DropDownItem
icon="PlaneIcon"
label={t('LblInviteAgain')}
onClick={this.onNotImplementedClick.bind(this, "Invite again action")}
/> */}
{false &&
<DropDownItem
icon="ImportIcon"
label={t('ImportPeople')}
onClick={this.onDropDownItemClick.bind(this, `${settings.homepage}/import`)}
/>
}
</MainButton>
{dialogVisible &&
<InviteDialog
visible={dialogVisible}
onClose={this.onInvitationDialogClick}
onCloseButton={this.onInvitationDialogClick}
{false && (
<DropDownItem
icon="ImportIcon"
label={t("ImportPeople")}
onClick={this.onDropDownItemClick.bind(
this,
`${settings.homepage}/import`
)}
/>
}
</>
:
<></>
)}
</MainButton>
{dialogVisible && (
<InviteDialog
visible={dialogVisible}
onClose={this.onInvitationDialogClick}
onCloseButton={this.onInvitationDialogClick}
/>
)}
</>
) : (
<></>
);
};
};
}
}
const ArticleMainButtonContentContainer = withTranslation()(PureArticleMainButtonContent);
const ArticleMainButtonContentContainer = withTranslation()(
PureArticleMainButtonContent
);
const ArticleMainButtonContent = (props) => {
const ArticleMainButtonContent = props => {
changeLanguage(i18n);
return (<I18nextProvider i18n={i18n}><ArticleMainButtonContentContainer {...props} /></I18nextProvider>);
return (
<I18nextProvider i18n={i18n}>
<ArticleMainButtonContentContainer {...props} />
</I18nextProvider>
);
};
ArticleMainButtonContent.propTypes = {
@ -120,11 +127,11 @@ ArticleMainButtonContent.propTypes = {
history: PropTypes.object.isRequired
};
const mapStateToProps = (state) => {
const mapStateToProps = state => {
return {
isAdmin: isAdmin(state.auth.user),
settings: state.auth.settings
}
}
};
};
export default connect(mapStateToProps)(withRouter(ArticleMainButtonContent));
export default connect(mapStateToProps)(withRouter(ArticleMainButtonContent));

View File

@ -1,54 +0,0 @@
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/Article/{{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: false
}
});
}
export default newInstance;

View File

@ -1,54 +0,0 @@
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/ChangeEmailDialog/{{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;

View File

@ -9,9 +9,15 @@ import {
FieldContainer
} from "asc-web-components";
import { withTranslation } from "react-i18next";
import i18n from "./i18n";
import ModalDialogContainer from '../ModalDialogContainer';
import ModalDialogContainer from "../ModalDialogContainer";
import { api, utils } from "asc-web-common";
import { createI18N } from "../../../helpers/i18n";
const i18n = createI18N({
page: "ChangeEmailDialog",
localesPath: "dialogs/ChangeEmailDialog"
});
const { sendInstructionsToChangeEmail } = api.people;
const { changeLanguage } = utils;
@ -27,7 +33,7 @@ class ChangeEmailDialogComponent extends React.Component {
isRequestRunning: false,
email,
hasError: false,
errorMessage: '',
errorMessage: "",
emailErrors: []
};
@ -50,7 +56,8 @@ class ChangeEmailDialogComponent extends React.Component {
window.removeEventListener("keyup", this.onKeyPress);
}
onValidateEmailInput = result => this.setState({ isEmailValid: result.isValid, emailErrors: result.errors });
onValidateEmailInput = result =>
this.setState({ isEmailValid: result.isValid, emailErrors: result.errors });
onChangeEmailInput = e => {
const { hasError } = this.state;
@ -65,14 +72,16 @@ class ChangeEmailDialogComponent extends React.Component {
const { id } = user;
this.setState({ isRequestRunning: true }, () => {
sendInstructionsToChangeEmail(id, email)
.then((res) => {
.then(res => {
toastr.success(res);
})
.catch((error) => toastr.error(error))
.catch(error => toastr.error(error))
.finally(() => {
this.setState({ isRequestRunning: false }, () => this.props.onClose());
this.setState({ isRequestRunning: false }, () =>
this.props.onClose()
);
});
})
});
};
onValidateEmail = () => {
@ -81,15 +90,13 @@ class ChangeEmailDialogComponent extends React.Component {
if (isEmailValid) {
const sameEmailError = email.toLowerCase() === user.email.toLowerCase();
if (sameEmailError) {
this.setState({ errorMessage: t('SameEmail'), hasError: true });
}
else {
this.setState({ errorMessage: '', hasError: false });
this.setState({ errorMessage: t("SameEmail"), hasError: true });
} else {
this.setState({ errorMessage: "", hasError: false });
this.onSendEmailChangeInstructions();
}
}
else {
const translatedErrors = emailErrors.map((errorKey => t(errorKey)));
} else {
const translatedErrors = emailErrors.map(errorKey => t(errorKey));
const errorMessage = translatedErrors[0];
this.setState({ errorMessage, hasError: true });
}
@ -102,7 +109,6 @@ class ChangeEmailDialogComponent extends React.Component {
}
};
render() {
console.log("ChangeEmailDialog render");
const { t, visible, onClose } = this.props;
@ -113,12 +119,12 @@ class ChangeEmailDialogComponent extends React.Component {
<ModalDialog
visible={visible}
onClose={onClose}
headerContent={t('EmailChangeTitle')}
headerContent={t("EmailChangeTitle")}
bodyContent={
<>
<FieldContainer
isVertical
labelText={t('EnterEmail')}
labelText={t("EnterEmail")}
errorMessage={errorMessage}
hasError={hasError}
>
@ -133,17 +139,15 @@ class ChangeEmailDialogComponent extends React.Component {
hasError={hasError}
/>
</FieldContainer>
<Text
className='text-dialog'
>
{t('EmailActivationDescription')}
<Text className="text-dialog">
{t("EmailActivationDescription")}
</Text>
</>
}
footerContent={
<Button
key="SendBtn"
label={t('SendButton')}
label={t("SendButton")}
size="medium"
primary={true}
onClick={this.onValidateEmail}
@ -156,7 +160,9 @@ class ChangeEmailDialogComponent extends React.Component {
}
}
const ChangeEmailDialogTranslated = withTranslation()(ChangeEmailDialogComponent);
const ChangeEmailDialogTranslated = withTranslation()(
ChangeEmailDialogComponent
);
const ChangeEmailDialog = props => (
<ChangeEmailDialogTranslated i18n={i18n} {...props} />
@ -168,5 +174,4 @@ ChangeEmailDialog.propTypes = {
user: PropTypes.object.isRequired
};
export default ChangeEmailDialog;

View File

@ -1,54 +0,0 @@
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/ChangePasswordDialog/{{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;

View File

@ -1,15 +1,15 @@
import React from "react";
import PropTypes from "prop-types";
import {
toastr,
ModalDialog,
Button,
Link,
Text
} from "asc-web-components";
import { toastr, ModalDialog, Button, Link, Text } from "asc-web-components";
import { withTranslation, Trans } from "react-i18next";
import i18n from "./i18n";
import { api, utils } from "asc-web-common";
import { createI18N } from "../../../helpers/i18n";
const i18n = createI18N({
page: "ChangePasswordDialog",
localesPath: "dialogs/ChangePasswordDialog"
});
const { sendInstructionsToChangePassword } = api.people;
const { changeLanguage } = utils;
@ -27,17 +27,15 @@ class ChangePasswordDialogComponent extends React.Component {
const { email, onClose } = this.props;
this.setState({ isRequestRunning: true }, () => {
sendInstructionsToChangePassword(email)
.then((res) => {
.then(res => {
toastr.success(res);
})
.catch((error) => toastr.error(error))
.catch(error => toastr.error(error))
.finally(() => {
this.setState({ isRequestRunning: false }, () => onClose());
});
})
}
});
};
render() {
console.log("ChangePasswordDialog render");
@ -48,23 +46,31 @@ class ChangePasswordDialogComponent extends React.Component {
<ModalDialog
visible={visible}
onClose={onClose}
headerContent={t('PasswordChangeTitle')}
headerContent={t("PasswordChangeTitle")}
bodyContent={
<Text fontSize='13px'>
<Trans i18nKey="MessageSendPasswordChangeInstructionsOnEmail" i18n={i18n}>
<Text fontSize="13px">
<Trans
i18nKey="MessageSendPasswordChangeInstructionsOnEmail"
i18n={i18n}
>
Send the password change instructions to the
<Link type="page" href={`mailto:${email}`} noHover color='#316DAA' title={email}>
<Link
type="page"
href={`mailto:${email}`}
noHover
color="#316DAA"
title={email}
>
{{ email }}
</Link>
email address
</Trans>
</Trans>
</Text>
}
footerContent={
<Button
key="SendBtn"
label={t('SendButton')}
label={t("SendButton")}
size="medium"
primary={true}
onClick={this.onSendPasswordChangeInstructions}
@ -76,7 +82,9 @@ class ChangePasswordDialogComponent extends React.Component {
}
}
const ChangePasswordDialogTranslated = withTranslation()(ChangePasswordDialogComponent);
const ChangePasswordDialogTranslated = withTranslation()(
ChangePasswordDialogComponent
);
const ChangePasswordDialog = props => (
<ChangePasswordDialogTranslated i18n={i18n} {...props} />
@ -85,7 +93,7 @@ const ChangePasswordDialog = props => (
ChangePasswordDialog.propTypes = {
visible: PropTypes.bool.isRequired,
onClose: PropTypes.func.isRequired,
email: PropTypes.string.isRequired,
email: PropTypes.string.isRequired
};
export default ChangePasswordDialog;

View File

@ -1,54 +0,0 @@
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/ChangePhoneDialog/{{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;

View File

@ -1,14 +1,15 @@
import React from "react";
import PropTypes from "prop-types";
import {
toastr,
ModalDialog,
Button,
Text
} from "asc-web-components";
import { toastr, ModalDialog, Button, Text } from "asc-web-components";
import { withTranslation } from "react-i18next";
import i18n from "./i18n";
import { api, utils } from "asc-web-common";
import { utils } from "asc-web-common";
import { createI18N } from "../../../helpers/i18n";
const i18n = createI18N({
page: "ChangePhoneDialog",
localesPath: "dialogs/ChangePhoneDialog"
});
const { changeLanguage } = utils;
class ChangePhoneDialogComponent extends React.Component {
@ -31,8 +32,6 @@ class ChangePhoneDialogComponent extends React.Component {
});
};
render() {
console.log("ChangePhoneDialog render");
const { t, visible, onClose } = this.props;
@ -42,16 +41,12 @@ class ChangePhoneDialogComponent extends React.Component {
<ModalDialog
visible={visible}
onClose={onClose}
headerContent={t('MobilePhoneChangeTitle')}
bodyContent={
<Text>
{t('MobilePhoneEraseDescription')}
</Text>
}
headerContent={t("MobilePhoneChangeTitle")}
bodyContent={<Text>{t("MobilePhoneEraseDescription")}</Text>}
footerContent={
<Button
key="SendBtn"
label={t('SendButton')}
label={t("SendButton")}
size="medium"
primary={true}
onClick={this.onChangePhone}
@ -63,7 +58,9 @@ class ChangePhoneDialogComponent extends React.Component {
}
}
const ChangePhoneDialogTranslated = withTranslation()(ChangePhoneDialogComponent);
const ChangePhoneDialogTranslated = withTranslation()(
ChangePhoneDialogComponent
);
const ChangePhoneDialog = props => (
<ChangePhoneDialogTranslated i18n={i18n} {...props} />
@ -72,7 +69,7 @@ const ChangePhoneDialog = props => (
ChangePhoneDialog.propTypes = {
visible: PropTypes.bool.isRequired,
onClose: PropTypes.func.isRequired,
user: PropTypes.object.isRequired,
user: PropTypes.object.isRequired
};
export default ChangePhoneDialog;

View File

@ -1,54 +0,0 @@
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/ChangeUserStatusDialog/{{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;

View File

@ -14,11 +14,16 @@ import {
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";
import { createI18N } from "../../../helpers/i18n";
const i18n = createI18N({
page: "ChangeUserStatusDialog",
localesPath: "dialogs/ChangeUserStatusDialog"
});
const { changeLanguage } = utils;
class ChangeUserStatusDialogComponent extends React.Component {
@ -189,6 +194,7 @@ ChangeUserStatusDialog.propTypes = {
selectedUsers: PropTypes.arrayOf(PropTypes.object).isRequired
};
export default connect(null, { updateUserStatus })(
withRouter(ChangeUserStatusDialog)
);
export default connect(
null,
{ updateUserStatus }
)(withRouter(ChangeUserStatusDialog));

View File

@ -1,54 +0,0 @@
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/ChangeUserTypeDialog/{{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;

View File

@ -14,11 +14,16 @@ import {
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";
import { createI18N } from "../../../helpers/i18n";
const i18n = createI18N({
page: "ChangeUserTypeDialog",
localesPath: "dialogs/ChangeUserTypeDialog"
});
const { changeLanguage } = utils;
class ChangeUserTypeDialogComponent extends React.Component {
@ -178,6 +183,7 @@ ChangeUserTypeDialog.propTypes = {
selectedUsers: PropTypes.arrayOf(PropTypes.object).isRequired
};
export default connect(null, { updateUserType })(
withRouter(ChangeUserTypeDialog)
);
export default connect(
null,
{ updateUserType }
)(withRouter(ChangeUserTypeDialog));

View File

@ -1,54 +0,0 @@
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;

View File

@ -2,17 +2,17 @@ import React from "react";
import { connect } from "react-redux";
import { withRouter } from "react-router";
import PropTypes from "prop-types";
import {
toastr,
ModalDialog,
Button,
Text
} from "asc-web-components";
import { toastr, ModalDialog, Button, Text } from "asc-web-components";
import { withTranslation, Trans } from "react-i18next";
import i18n from "./i18n";
import { api, utils } from "asc-web-common";
import { fetchPeople } from '../../../store/people/actions';
import ModalDialogContainer from '../ModalDialogContainer';
import { fetchPeople } from "../../../store/people/actions";
import ModalDialogContainer from "../ModalDialogContainer";
import { createI18N } from "../../../helpers/i18n";
const i18n = createI18N({
page: "DeleteProfileEverDialog",
localesPath: "dialogs/DeleteProfileEverDialog"
});
const { deleteUser } = api.people;
const { Filter } = api;
const { changeLanguage } = utils;
@ -31,20 +31,20 @@ class DeleteProfileEverDialogComponent extends React.Component {
const { onClose, filter, fetchPeople, user, t } = this.props;
this.setState({ isRequestRunning: true }, () => {
deleteUser(user.id)
.then((res) => {
toastr.success(t('SuccessfullyDeleteUserInfoMessage'));
.then(res => {
toastr.success(t("SuccessfullyDeleteUserInfoMessage"));
return fetchPeople(filter);
})
.catch((error) => toastr.error(error))
.catch(error => toastr.error(error))
.finally(() => {
this.setState({ isRequestRunning: false }, () => onClose());
});
})
});
};
onReassignDataClick = () => {
const { history, settings, user } = this.props;
history.push(`${settings.homepage}/reassign/${user.userName}`)
history.push(`${settings.homepage}/reassign/${user.userName}`);
};
render() {
@ -57,37 +57,36 @@ class DeleteProfileEverDialogComponent extends React.Component {
<ModalDialog
visible={visible}
onClose={onClose}
headerContent={t('Confirmation')}
headerContent={t("Confirmation")}
bodyContent={
<>
<Text>
<Trans i18nKey='DeleteUserConfirmation' i18n={i18n}>
{{ userCaption }} <strong>{{ user: user.displayName }}</strong> will be deleted.
</Trans>
<Trans i18nKey="DeleteUserConfirmation" i18n={i18n}>
{{ userCaption }}{" "}
<strong>{{ user: user.displayName }}</strong> will be deleted.
</Trans>
</Text>
<Text>{t('NotBeUndone')}</Text>
<Text color="#c30" fontSize="18px" className='warning-text'>
{t('Warning')}
</Text>
<Text>
{t('DeleteUserDataConfirmation')}
<Text>{t("NotBeUndone")}</Text>
<Text color="#c30" fontSize="18px" className="warning-text">
{t("Warning")}
</Text>
<Text>{t("DeleteUserDataConfirmation")}</Text>
</>
}
footerContent={
<>
<Button
key="OKBtn"
label={t('OKButton')}
label={t("OKButton")}
size="medium"
primary={true}
onClick={this.onDeleteProfileEver}
isLoading={isRequestRunning}
/>
<Button
className='button-dialog'
className="button-dialog"
key="ReassignBtn"
label={t('ReassignData')}
label={t("ReassignData")}
size="medium"
onClick={this.onReassignDataClick}
isDisabled={isRequestRunning}
@ -100,7 +99,9 @@ class DeleteProfileEverDialogComponent extends React.Component {
}
}
const DeleteProfileEverDialogTranslated = withTranslation()(DeleteProfileEverDialogComponent);
const DeleteProfileEverDialogTranslated = withTranslation()(
DeleteProfileEverDialogComponent
);
const DeleteProfileEverDialog = props => (
<DeleteProfileEverDialogTranslated i18n={i18n} {...props} />
@ -122,4 +123,7 @@ function mapStateToProps(state) {
};
}
export default connect(mapStateToProps, { fetchPeople })(withRouter(DeleteProfileEverDialog));
export default connect(
mapStateToProps,
{ fetchPeople }
)(withRouter(DeleteProfileEverDialog));

View File

@ -1,54 +0,0 @@
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/DeleteSelfProfileDialog/{{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;

View File

@ -1,16 +1,14 @@
import React from "react";
import PropTypes from "prop-types";
import {
toastr,
ModalDialog,
Button,
Link,
Text
} from "asc-web-components";
import { toastr, ModalDialog, Button, Link, Text } from "asc-web-components";
import { withTranslation } from "react-i18next";
import i18n from "./i18n";
import ModalDialogContainer from '../ModalDialogContainer';
import ModalDialogContainer from "../ModalDialogContainer";
import { api, utils } from "asc-web-common";
import { createI18N } from "../../../helpers/i18n";
const i18n = createI18N({
page: "DeleteSelfProfileDialog",
localesPath: "dialogs/DeleteSelfProfileDialog"
});
const { sendInstructionsToDelete } = api.people;
const { changeLanguage } = utils;
@ -28,15 +26,15 @@ class DeleteSelfProfileDialogComponent extends React.Component {
const { onClose } = this.props;
this.setState({ isRequestRunning: true }, () => {
sendInstructionsToDelete()
.then((res) => {
.then(res => {
toastr.success(res);
})
.catch((error) => toastr.error(error))
.catch(error => toastr.error(error))
.finally(() => {
this.setState({ isRequestRunning: false }, () => onClose());
});
})
}
});
};
render() {
console.log("DeleteSelfProfileDialog render");
@ -48,10 +46,17 @@ class DeleteSelfProfileDialogComponent extends React.Component {
<ModalDialog
visible={visible}
onClose={onClose}
headerContent={t('DeleteProfileTitle')}
headerContent={t("DeleteProfileTitle")}
bodyContent={
<Text fontSize='13px'>
{t('DeleteProfileInfo')} <Link type="page" href={`mailto:${email}`} noHover color='#316DAA' title={email}>
<Text fontSize="13px">
{t("DeleteProfileInfo")}{" "}
<Link
type="page"
href={`mailto:${email}`}
noHover
color="#316DAA"
title={email}
>
{email}
</Link>
</Text>
@ -60,16 +65,16 @@ class DeleteSelfProfileDialogComponent extends React.Component {
<>
<Button
key="SendBtn"
label={t('SendButton')}
label={t("SendButton")}
size="medium"
primary={true}
onClick={this.onDeleteSelfProfileInstructions}
isLoading={isRequestRunning}
/>
<Button
className='button-dialog'
className="button-dialog"
key="CloseBtn"
label={t('CloseButton')}
label={t("CloseButton")}
size="medium"
onClick={onClose}
isDisabled={isRequestRunning}
@ -82,8 +87,9 @@ class DeleteSelfProfileDialogComponent extends React.Component {
}
}
const DeleteSelfProfileDialogTranslated = withTranslation()(DeleteSelfProfileDialogComponent);
const DeleteSelfProfileDialogTranslated = withTranslation()(
DeleteSelfProfileDialogComponent
);
const DeleteSelfProfileDialog = props => (
<DeleteSelfProfileDialogTranslated i18n={i18n} {...props} />
@ -92,7 +98,7 @@ const DeleteSelfProfileDialog = props => (
DeleteSelfProfileDialog.propTypes = {
visible: PropTypes.bool.isRequired,
onClose: PropTypes.func.isRequired,
email: PropTypes.string.isRequired,
email: PropTypes.string.isRequired
};
export default DeleteSelfProfileDialog;

View File

@ -1,54 +0,0 @@
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/DeleteUsersDialog/{{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;

View File

@ -14,10 +14,14 @@ import {
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";
import { createI18N } from "../../../helpers/i18n";
const i18n = createI18N({
page: "DeleteUsersDialog",
localesPath: "dialogs/DeleteUsersDialog"
});
const { Filter } = api;
const { changeLanguage } = utils;
@ -185,4 +189,7 @@ DeleteUsersDialog.propTypes = {
removeUser: PropTypes.func.isRequired
};
export default connect(null, { removeUser })(withRouter(DeleteUsersDialog));
export default connect(
null,
{ removeUser }
)(withRouter(DeleteUsersDialog));

View File

@ -1,62 +0,0 @@
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
format: function (value, format) {
if (format === 'lowercase') return value.toLowerCase();
return value;
}
},
react: {
useSuspense: true
},
backend: {
loadPath: `${config.homepage}/locales/InviteDialog/{{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
format: function (value, format) {
if (format === 'lowercase') return value.toLowerCase();
return value;
}
},
react: {
useSuspense: true
}
});
}
export default newInstance;

View File

@ -11,12 +11,17 @@ import {
Text
} from "asc-web-components";
import { withTranslation } from "react-i18next";
import i18n from "./i18n";
import ModalDialogContainer from '../ModalDialogContainer';
import ModalDialogContainer from "../ModalDialogContainer";
import copy from "copy-to-clipboard";
import { api, utils } from "asc-web-common";
import { createI18N } from "../../../helpers/i18n";
const i18n = createI18N({
page: "InviteDialog",
localesPath: "dialogs/InviteDialog"
});
const { getShortenedLink } = api.portal;
const { changeLanguage } = utils;
const textAreaName = "link-textarea";
class InviteDialogComponent extends React.Component {
@ -30,7 +35,7 @@ class InviteDialogComponent extends React.Component {
guestInvitationLink,
isLoading: false,
isLinkShort: false,
visible: false,
visible: false
};
}
@ -50,10 +55,7 @@ class InviteDialogComponent extends React.Component {
onGetShortenedLink = () => {
this.setState({ isLoading: true });
const {
userInvitationLink,
guestInvitationLink
} = this.props;
const { userInvitationLink, guestInvitationLink } = this.props;
getShortenedLink(userInvitationLink)
.then(link => this.setState({ userInvitationLink: link }))
@ -80,8 +82,8 @@ class InviteDialogComponent extends React.Component {
copy(this.state.userInvitationLink);
changeLanguage(i18n)
.then(()=> this.setState({visible: true}))
.then(()=> toastr.success(t("LinkCopySuccess")));
.then(() => this.setState({ visible: true }))
.then(() => toastr.success(t("LinkCopySuccess")));
}
onClickToCloseButton = () =>
@ -93,78 +95,77 @@ class InviteDialogComponent extends React.Component {
const { t, visible, settings, guestsCaption } = this.props;
return (
this.state.visible &&
<ModalDialogContainer>
<ModalDialog
visible={visible}
onClose={this.onClose}
headerContent={t("InviteLinkTitle")}
bodyContent={
<>
<Text as="p">
{t("HelpAnswerLinkInviteSettings")}
</Text>
<Text className="text-dialog" as="p">
{t("InviteLinkValidInterval", { count: 7 })}
</Text>
<div className="flex">
<div>
<Link
className="link-dialog"
type="action"
isHovered={true}
onClick={this.onCopyLinkToClipboard}
>
{t("CopyToClipboard")}
</Link>
{settings && !this.state.isLinkShort && (
this.state.visible && (
<ModalDialogContainer>
<ModalDialog
visible={visible}
onClose={this.onClose}
headerContent={t("InviteLinkTitle")}
bodyContent={
<>
<Text as="p">{t("HelpAnswerLinkInviteSettings")}</Text>
<Text className="text-dialog" as="p">
{t("InviteLinkValidInterval", { count: 7 })}
</Text>
<div className="flex">
<div>
<Link
className="link-dialog"
type="action"
isHovered={true}
onClick={this.onGetShortenedLink}
onClick={this.onCopyLinkToClipboard}
>
{t("GetShortenLink")}
{t("CopyToClipboard")}
</Link>
)}
{settings && !this.state.isLinkShort && (
<Link
type="action"
isHovered={true}
onClick={this.onGetShortenedLink}
>
{t("GetShortenLink")}
</Link>
)}
</div>
<Checkbox
label={t("InviteUsersAsCollaborators", { guestsCaption })}
isChecked={this.state.isGuest}
onChange={this.onCheckedGuest}
isDisabled={this.state.isLoading}
/>
</div>
<Checkbox
label={t("InviteUsersAsCollaborators", { guestsCaption })}
isChecked={this.state.isGuest}
onChange={this.onCheckedGuest}
<Textarea
className="textarea-dialog"
isReadOnly={true}
isDisabled={this.state.isLoading}
name={textAreaName}
value={
this.state.isGuest
? this.state.guestInvitationLink
: this.state.userInvitationLink
}
/>
</div>
<Textarea
className="textarea-dialog"
isReadOnly={true}
isDisabled={this.state.isLoading}
name={textAreaName}
value={
this.state.isGuest
? this.state.guestInvitationLink
: this.state.userInvitationLink
}
/>
</>
}
footerContent={
<>
<Button
key="CloseBtn"
label={
this.state.isLoading
? t("LoadingProcessing")
: t("CloseButton")
}
size="medium"
primary={true}
onClick={this.onClickToCloseButton}
isLoading={this.state.isLoading}
/>
</>
}
/>
</ModalDialogContainer>
</>
}
footerContent={
<>
<Button
key="CloseBtn"
label={
this.state.isLoading
? t("LoadingProcessing")
: t("CloseButton")
}
size="medium"
primary={true}
onClick={this.onClickToCloseButton}
isLoading={this.state.isLoading}
/>
</>
}
/>
</ModalDialogContainer>
)
);
}
}
@ -180,9 +181,7 @@ const mapStateToProps = state => {
const InviteDialogTranslated = withTranslation()(InviteDialogComponent);
const InviteDialog = props => (
<InviteDialogTranslated i18n={i18n} {...props} />
);
const InviteDialog = props => <InviteDialogTranslated i18n={i18n} {...props} />;
InviteDialog.propTypes = {
visible: PropTypes.bool.isRequired,

View File

@ -1,54 +0,0 @@
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/SendInviteDialog/{{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;

View File

@ -13,10 +13,13 @@ import {
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";
import { createI18N } from "../../../helpers/i18n";
const i18n = createI18N({
page: "SendInviteDialog",
localesPath: "dialogs/SendInviteDialog"
});
const { resendUserInvites } = api.people;
const { changeLanguage } = utils;

View File

@ -1,62 +0,0 @@
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
format: function (value, format) {
if (format === 'lowercase') return value.toLowerCase();
return value;
}
},
react: {
useSuspense: true
},
backend: {
loadPath: `${config.homepage}/locales/GroupAction/{{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
format: function (value, format) {
if (format === 'lowercase') return value.toLowerCase();
return value;
}
},
react: {
useSuspense: false
}
});
}
export default newInstance;

View File

@ -6,15 +6,18 @@ import {
ArticleHeaderContent,
ArticleMainButtonContent,
ArticleBodyContent
} from '../../Article';
import { SectionHeaderContent, SectionBodyContent } from './Section';
import i18n from "./i18n";
} from "../../Article";
import { SectionHeaderContent, SectionBodyContent } from "./Section";
import { I18nextProvider, withTranslation } from "react-i18next";
import { fetchGroup, resetGroup } from "../../../store/group/actions";
import { createI18N } from "../../../helpers/i18n";
const i18n = createI18N({
page: "GroupAction",
localesPath: "pages/GroupAction"
});
const { changeLanguage } = utils;
class GroupAction extends React.Component {
componentDidMount() {
const { match, fetchGroup, t } = this.props;
const { groupId } = match.params;
@ -37,7 +40,7 @@ class GroupAction extends React.Component {
}
render() {
console.log("GroupAction render")
console.log("GroupAction render");
const { group, match } = this.props;
@ -68,24 +71,24 @@ class GroupAction extends React.Component {
</PageLayout.SectionBody>
</PageLayout>
) : (
<PageLayout>
<PageLayout.ArticleHeader>
<ArticleHeaderContent />
</PageLayout.ArticleHeader>
<PageLayout>
<PageLayout.ArticleHeader>
<ArticleHeaderContent />
</PageLayout.ArticleHeader>
<PageLayout.ArticleMainButton>
<ArticleMainButtonContent />
</PageLayout.ArticleMainButton>
<PageLayout.ArticleMainButton>
<ArticleMainButtonContent />
</PageLayout.ArticleMainButton>
<PageLayout.ArticleBody>
<ArticleBodyContent />
</PageLayout.ArticleBody>
<PageLayout.ArticleBody>
<ArticleBodyContent />
</PageLayout.ArticleBody>
<PageLayout.SectionBody>
<Loader className="pageLoader" type="rombs" size="40px" />
</PageLayout.SectionBody>
</PageLayout>
)}
<PageLayout.SectionBody>
<Loader className="pageLoader" type="rombs" size="40px" />
</PageLayout.SectionBody>
</PageLayout>
)}
</I18nextProvider>
);
}
@ -109,8 +112,10 @@ function mapStateToProps(state) {
};
}
export default connect(mapStateToProps,
export default connect(
mapStateToProps,
{
fetchGroup,
resetGroup
})(GroupActionContainer);
}
)(GroupActionContainer);

View File

@ -31,9 +31,18 @@ import {
import { isMobileOnly } from "react-device-detect";
import isEqual from "lodash/isEqual";
import { Loader } from "asc-web-components";
import { store, api, constants } from 'asc-web-common';
import i18n from '../../i18n';
import { ChangeEmailDialog, ChangePasswordDialog, DeleteSelfProfileDialog, DeleteProfileEverDialog } from '../../../../dialogs';
import { store, api, constants } from "asc-web-common";
import {
ChangeEmailDialog,
ChangePasswordDialog,
DeleteSelfProfileDialog,
DeleteProfileEverDialog
} from "../../../../dialogs";
import { createI18N } from "../../../../../helpers/i18n";
const i18n = createI18N({
page: "Home",
localesPath: "pages/Home"
});
const { isArrayEqual } = utils.array;
const { isAdmin, isMe } = store.auth.selectors;
const { resendUserInvites } = api.people;
@ -50,7 +59,7 @@ class SectionBodyContent extends React.PureComponent {
changeEmail: false,
changePassword: false,
deleteSelfProfile: false,
deleteProfileEver: false,
deleteProfileEver: false
},
isEmailValid: false
};
@ -80,18 +89,24 @@ class SectionBodyContent extends React.PureComponent {
history.push(`${settings.homepage}/edit/${user.userName}`);
};
toggleChangePasswordDialog = (email) => {
const checkedEmail = typeof (email) === 'string' ? email : undefined;
toggleChangePasswordDialog = email => {
const checkedEmail = typeof email === "string" ? email : undefined;
this.setState({
dialogsVisible: { ...this.state.dialogsVisible, changePassword: !this.state.dialogsVisible.changePassword },
dialogsVisible: {
...this.state.dialogsVisible,
changePassword: !this.state.dialogsVisible.changePassword
},
user: { email: checkedEmail }
});
};
toggleChangeEmailDialog = (user) => {
toggleChangeEmailDialog = user => {
const checkedUser = user ? user : {};
this.setState({
dialogsVisible: { ...this.state.dialogsVisible, changeEmail: !this.state.dialogsVisible.changeEmail },
dialogsVisible: {
...this.state.dialogsVisible,
changeEmail: !this.state.dialogsVisible.changeEmail
},
user: {
email: checkedUser.email,
id: checkedUser.id
@ -104,7 +119,7 @@ class SectionBodyContent extends React.PureComponent {
onLoading(true);
updateUserStatus(EmployeeStatus.Disabled, [user.id], isRefetchPeople)
.then(() => toastr.success(t('SuccessChangeUserStatus')))
.then(() => toastr.success(t("SuccessChangeUserStatus")))
.catch(error => toastr.error(error))
.finally(() => onLoading(false));
};
@ -114,7 +129,7 @@ class SectionBodyContent extends React.PureComponent {
onLoading(true);
updateUserStatus(EmployeeStatus.Active, [user.id], isRefetchPeople)
.then(() => toastr.success(t('SuccessChangeUserStatus')))
.then(() => toastr.success(t("SuccessChangeUserStatus")))
.catch(error => toastr.error(error))
.finally(() => onLoading(false));
};
@ -131,19 +146,25 @@ class SectionBodyContent extends React.PureComponent {
toggleDeleteProfileEverDialog = user => {
const checkedUser = user ? user : {};
this.setState({
dialogsVisible: { ...this.state.dialogsVisible, deleteProfileEver: !this.state.dialogsVisible.deleteProfileEver },
dialogsVisible: {
...this.state.dialogsVisible,
deleteProfileEver: !this.state.dialogsVisible.deleteProfileEver
},
user: {
id: checkedUser.id,
displayName: checkedUser.displayName,
userName: checkedUser.userName,
userName: checkedUser.userName
}
});
};
toggleDeleteSelfProfileDialog = email => {
const checkedEmail = typeof (email) === 'string' ? email : undefined;
const checkedEmail = typeof email === "string" ? email : undefined;
this.setState({
dialogsVisible: { ...this.state.dialogsVisible, deleteSelfProfile: !this.state.dialogsVisible.deleteSelfProfile },
dialogsVisible: {
...this.state.dialogsVisible,
deleteSelfProfile: !this.state.dialogsVisible.deleteSelfProfile
},
user: { email: checkedEmail }
});
};
@ -154,10 +175,13 @@ class SectionBodyContent extends React.PureComponent {
resendUserInvites([user.id])
.then(() =>
toastr.success(
<Trans i18nKey='MessageEmailActivationInstuctionsSentOnEmail' i18n={i18n}>
<Trans
i18nKey="MessageEmailActivationInstuctionsSentOnEmail"
i18n={i18n}
>
The email activation instructions have been sent to the
<strong>{{ email: user.email }}</strong> email address
</Trans>
<strong>{{ email: user.email }}</strong> email address
</Trans>
)
)
.catch(error => toastr.error(error))
@ -186,11 +210,11 @@ class SectionBodyContent extends React.PureComponent {
onClick: this.onEmailSentClick.bind(this, user.email)
},
user.mobilePhone &&
isMobileOnly && {
key: "send-message",
label: t("LblSendMessage"),
onClick: this.onSendMessageClick.bind(this, user.mobilePhone)
},
isMobileOnly && {
key: "send-message",
label: t("LblSendMessage"),
onClick: this.onSendMessageClick.bind(this, user.mobilePhone)
},
{ key: "separator", isSeparator: true },
{
key: "edit",
@ -211,15 +235,18 @@ class SectionBodyContent extends React.PureComponent {
? viewer.isOwner
? null
: {
key: "delete-profile",
label: t("DeleteSelfProfile"),
onClick: this.toggleDeleteSelfProfileDialog.bind(this, user.email)
}
key: "delete-profile",
label: t("DeleteSelfProfile"),
onClick: this.toggleDeleteSelfProfileDialog.bind(
this,
user.email
)
}
: {
key: "disable",
label: t("DisableUserButton"),
onClick: this.onDisableClick.bind(this, user)
}
key: "disable",
label: t("DisableUserButton"),
onClick: this.onDisableClick.bind(this, user)
}
];
case "disabled":
return [
@ -257,17 +284,17 @@ class SectionBodyContent extends React.PureComponent {
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)
}),
(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"),
@ -312,102 +339,113 @@ class SectionBodyContent extends React.PureComponent {
render() {
//console.log("Home SectionBodyContent render()");
const { users, viewer, selection, history, settings, t, filter } = this.props;
const {
users,
viewer,
selection,
history,
settings,
t,
filter
} = this.props;
const { dialogsVisible, user } = this.state;
return users == null
? (<Loader className="pageLoader" type="rombs" size='40px' />)
: users.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 } : {};
const element = (
<Avatar
size="small"
role={getUserRole(user)}
userName={user.displayName}
source={user.avatar}
return users == null ? (
<Loader className="pageLoader" type="rombs" size="40px" />
) : users.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 } : {};
const element = (
<Avatar
size="small"
role={getUserRole(user)}
userName={user.displayName}
source={user.avatar}
/>
);
return (
<Row
key={user.id}
status={getUserStatus(user)}
data={user}
element={element}
onSelect={this.onContentRowSelect}
{...checkedProps}
{...contextOptionsProps}
needForUpdate={this.needForUpdate}
>
<UserContent
user={user}
history={history}
settings={settings}
selectGroup={this.props.selectGroup}
/>
);
</Row>
);
})}
</RowContainer>
return (
<Row
key={user.id}
status={getUserStatus(user)}
data={user}
element={element}
onSelect={this.onContentRowSelect}
{...checkedProps}
{...contextOptionsProps}
needForUpdate={this.needForUpdate}
>
<UserContent
user={user}
history={history}
settings={settings}
selectGroup={this.props.selectGroup}
/>
</Row>
);
})}
</RowContainer>
{dialogsVisible.changeEmail &&
<ChangeEmailDialog
visible={dialogsVisible.changeEmail}
onClose={this.toggleChangeEmailDialog}
user={user}
/>
}
{dialogsVisible.changePassword &&
<ChangePasswordDialog
visible={dialogsVisible.changePassword}
onClose={this.toggleChangePasswordDialog}
email={user.email}
/>
}
{dialogsVisible.deleteSelfProfile &&
<DeleteSelfProfileDialog
visible={dialogsVisible.deleteSelfProfile}
onClose={this.toggleDeleteSelfProfileDialog}
email={user.email}
/>
}
{dialogsVisible.deleteProfileEver &&
<DeleteProfileEverDialog
visible={dialogsVisible.deleteProfileEver}
onClose={this.toggleDeleteProfileEverDialog}
user={user}
filter={filter}
settings={settings}
history={history}
/>
}
</>
) : (
<EmptyScreenContainer
imageSrc="images/empty_screen_filter.png"
imageAlt="Empty Screen Filter image"
headerText={t("NotFoundTitle")}
descriptionText={t("NotFoundDescription")}
buttons={
<>
<Icons.CrossIcon size="small" style={{ marginRight: "4px" }} />
<Link type="action" isHovered={true} onClick={this.onResetFilter}>
{t("ClearButton")}
</Link>
</>
}
{dialogsVisible.changeEmail && (
<ChangeEmailDialog
visible={dialogsVisible.changeEmail}
onClose={this.toggleChangeEmailDialog}
user={user}
/>
);
)}
{dialogsVisible.changePassword && (
<ChangePasswordDialog
visible={dialogsVisible.changePassword}
onClose={this.toggleChangePasswordDialog}
email={user.email}
/>
)}
{dialogsVisible.deleteSelfProfile && (
<DeleteSelfProfileDialog
visible={dialogsVisible.deleteSelfProfile}
onClose={this.toggleDeleteSelfProfileDialog}
email={user.email}
/>
)}
{dialogsVisible.deleteProfileEver && (
<DeleteProfileEverDialog
visible={dialogsVisible.deleteProfileEver}
onClose={this.toggleDeleteProfileEverDialog}
user={user}
filter={filter}
settings={settings}
history={history}
/>
)}
</>
) : (
<EmptyScreenContainer
imageSrc="images/empty_screen_filter.png"
imageAlt="Empty Screen Filter image"
headerText={t("NotFoundTitle")}
descriptionText={t("NotFoundDescription")}
buttons={
<>
<Icons.CrossIcon size="small" style={{ marginRight: "4px" }} />
<Link type="action" isHovered={true} onClick={this.onResetFilter}>
{t("ClearButton")}
</Link>
</>
}
/>
);
}
}
@ -428,5 +466,13 @@ const mapStateToProps = state => {
export default connect(
mapStateToProps,
{ selectUser, deselectUser, setSelection, updateUserStatus, resetFilter, fetchPeople, selectGroup }
{
selectUser,
deselectUser,
setSelection,
updateUserStatus,
resetFilter,
fetchPeople,
selectGroup
}
)(withRouter(withTranslation()(SectionBodyContent)));

View File

@ -1,54 +0,0 @@
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/Home/{{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: false
}
});
}
export default newInstance;

View File

@ -4,8 +4,7 @@ import PropTypes from "prop-types";
import { withRouter } from "react-router";
import { RequestLoader } from "asc-web-components";
import { PageLayout, utils } from "asc-web-common";
import { withTranslation, I18nextProvider } from 'react-i18next';
import i18n from "./i18n";
import { withTranslation, I18nextProvider } from "react-i18next";
import {
ArticleHeaderContent,
ArticleBodyContent,
@ -19,6 +18,11 @@ import {
} from "./Section";
import { setSelected } from "../../../store/people/actions";
import { getSelectedGroup } from "../../../store/people/selectors";
import { createI18N } from "../../../helpers/i18n";
const i18n = createI18N({
page: "Home",
localesPath: "pages/Home"
});
const { changeLanguage } = utils;
class PureHome extends React.Component {
@ -98,16 +102,13 @@ class PureHome extends React.Component {
<RequestLoader
visible={this.state.isLoading}
zIndex={256}
loaderSize='16px'
loaderSize="16px"
loaderColor={"#999"}
label={`${t('LoadingProcessing')} ${t('LoadingDescription')}`}
fontSize='12px'
label={`${t("LoadingProcessing")} ${t("LoadingDescription")}`}
fontSize="12px"
fontColor={"#999"}
/>
<PageLayout
withBodyScroll={true}
withBodyAutoFocus={true}
>
<PageLayout withBodyScroll={true} withBodyAutoFocus={true}>
<PageLayout.ArticleHeader>
<ArticleHeaderContent />
</PageLayout.ArticleHeader>
@ -143,7 +144,7 @@ class PureHome extends React.Component {
onChange={this.onRowChange}
/>
</PageLayout.SectionBody>
<PageLayout.SectionPaging>
<SectionPagingContent onLoading={this.onLoading} />
</PageLayout.SectionPaging>
@ -157,8 +158,12 @@ const HomeContainer = withTranslation()(PureHome);
const Home = props => {
changeLanguage(i18n);
return (<I18nextProvider i18n={i18n}><HomeContainer {...props} /></I18nextProvider>);
}
return (
<I18nextProvider i18n={i18n}>
<HomeContainer {...props} />
</I18nextProvider>
);
};
Home.propTypes = {
users: PropTypes.array,

View File

@ -1,277 +0,0 @@
import React, { memo } from "react";
import { withRouter } from "react-router";
// import { useTranslation } from 'react-i18next';
import { connect } from "react-redux";
import styled from 'styled-components';
import { Text, Button, Avatar, toastr } from 'asc-web-components';
import { api } from 'asc-web-common';
import { toEmployeeWrapper } from "../../../../../store/people/selectors";
import { importUsers } from "../../../../../store/people/actions";
import { FixedSizeList as List, areEqual } from 'react-window';
import AutoSizer from 'react-virtualized-auto-sizer';
const LoadCsvWrapper = styled.div`
margin-top: 24px;
margin-bottom: 24px;
width: 100%;
height: 400px;
max-width: 1024px;
`;
const SelectSourceWrapper = styled.div`
margin-top: 24px;
`;
const StyledFileInput = styled.div`
position: relative;
width: 100%;
max-width: 400px;
height: 36px;
input[type="file"] {
height: 100%;
font-size: 200px;
position: absolute;
top: 0;
right: 0;
opacity: 0;
}
`;
const StyledFieldContainer = styled.div`
position: relative;
@media (min-width:768px) {
margin-top: 14px;
}
`;
const StyledAvatar = styled.div`
float: left;
@media (max-width:768px) {
margin-top: 8px;
}
`;
const StyledField = styled.div`
line-height: 14px;
min-width: 100px;
padding: 4px 16px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
@media (min-width:768px) {
margin-top: 4px;
display: inline-block !important;
}
`;
const StyledProgress = styled.div`
position: absolute;
max-width: 100%;
width: ${props => props.completed && `${props.completed}%`};
height: 100%;
top: 0px;
background-color: #7ACE9B;
opacity: 0.3;
border-radius: 3px;
z-index: -1;
transition-property: width;
transition-duration: 1s;
`;
class ImportRow extends React.PureComponent {
render() {
const { items, completed } = this.props;
const fullName = items[0] + ' ' + items[1];
const firstName = items[0];
const lastName = items[1];
const email = items[2];
return (
<StyledFieldContainer key={email}>
<StyledAvatar>
<Avatar size='small' role='user' userName={fullName} />
</StyledAvatar>
<StyledField style={{ display: 'inline-block' }}>{firstName}</StyledField>
<StyledField style={{ display: 'inline-block' }}>{lastName}</StyledField>
<StyledField style={{ display: 'block' }}>{email}</StyledField>
<StyledProgress completed={completed} />
</StyledFieldContainer>
)
}
}
class SectionBodyContent extends React.Component {
constructor(props) {
super(props);
this.state = {
splittedLines: [],
importing: false
}
}
getAsText = (fileToRead) => {
if (!fileToRead) return;
let reader = new FileReader();
reader.readAsText(fileToRead);
reader.onload = this.loadHandler;
reader.onerror = this.errorHandler;
}
loadHandler = (event) => {
const csv = event.target.result;
this.processData(csv);
}
errorHandler = (event) => {
if (event.target.error.name === 'NotReadableError') {
alert(event.target.error.name);
}
}
processData = (csv) => {
const allTextLines = csv.split(/\r\n|\n/);
const splittedLines = allTextLines.map(line => line.split(','));
const filteredLines = splittedLines.filter(line => (line[0].length > 0) && line);
this.setState({
splittedLines: filteredLines
});
}
createRows = rows => rows.map(data => {
return (
<ImportRow items={data} />
);
});
renderRow = memo(({ data, index, style }) => {
return (
<div style={style}>
{data[index]}
</div>
)
}, areEqual);
prepareUsersData = data => {
const { splittedLines } = this.state;
const rawUsers = splittedLines || data;
const preparedUsers = rawUsers.map(user => {
const userObj = {};
userObj.firstName = user[0];
userObj.lastName = user[1];
userObj.email = user[2];
return toEmployeeWrapper(userObj);
});
return preparedUsers;
}
makeChunks = (data, size = 50) => {
let temp = [];
for (let i = 0; i < data.length; i += size) {
temp.push(data.slice(i, i + size));
}
return temp;
}
runImport = users => {
const chunks = this.makeChunks(users);
chunks.map(async chunk => { //TODO: do something better than an asynchronous carnival
for (const user of chunk) {
await api.people.createUser(user);
}
});
this.setState({
importing: false
});
}
onImportClick = () => {
const users = this.prepareUsersData();
this.setState({
importing: true
});
this.runImport(users);
}
render() {
const { splittedLines, importing } = this.state;
// const { t } = useTranslation();
const rows = this.createRows(splittedLines);
const isImportEnabled = true;
const renderList = ({ height, width }) => {
const itemHeight = (width < 768) ? 56 : 36;
return (
<List
className="List"
height={height}
width={width}
itemSize={itemHeight}
itemCount={rows.length}
itemData={rows}
>
{this.renderRow}
</List>
)
}
return (
<>
<Text fontSize='18px' >
Functionality at development stage.
</Text>
<br />
<Text fontSize='14px' >
Files are formatted according to <b>CSV RFC 4180</b> rules. <br />
<b>Column Order:</b> FirstName, LastName, Email. <br />
Comma delimiter, strings in unix format. <br />
</Text>
<SelectSourceWrapper>
<StyledFileInput>
<Button size='big' primary={true} scale={true} label="Upload CSV" isDisabled={!isImportEnabled} />
{isImportEnabled &&
<input type="file" name="file" onChange={(e) => this.getAsText(e.target.files[0])} accept='.csv' />
}
</StyledFileInput>
</SelectSourceWrapper>
<br />
<Text fontSize='14px' >
Ready for import: {splittedLines.length} of {splittedLines.length}
</Text>
<LoadCsvWrapper>
<AutoSizer>
{renderList}
</AutoSizer>
</LoadCsvWrapper>
<StyledFileInput>
<Button size='big' primary={true} scale={true} onClick={this.onImportClick} isDisabled={importing || !splittedLines.length} label="Start import" />
</StyledFileInput>
</>
);
}
}
function mapStateToProps(state) {
return {
};
}
export default connect(mapStateToProps, {})(withRouter(SectionBodyContent));

View File

@ -1,61 +0,0 @@
import React, { useCallback } from "react";
import { connect } from "react-redux";
import { IconButton } from "asc-web-components";
import { Headline } from 'asc-web-common';
import { withRouter } from "react-router";
// import { useTranslation } from 'react-i18next';
import styled from "styled-components";
const Wrapper = styled.div`
display: flex;
align-items: center;
.arrow-button {
@media (max-width: 1024px) {
padding: 8px 0 8px 8px;
margin-left: -8px;
}
}
`;
const textStyle = {
marginLeft: "16px",
marginRight: "16px"
};
const SectionHeaderContent = props => {
const { history, settings } = props;
//const { t } = useTranslation();
const onClickBack = useCallback(() => {
history.push(settings.homepage);
}, [history, settings]);
return (
<Wrapper>
<div style={{ width: "16px" }}>
<IconButton
iconName="ArrowPathIcon"
color="#A3A9AE"
size="17"
hoverColor="#657077"
isFill={true}
onClick={onClickBack}
className="arrow-button"
/>
</div>
<Headline type="content" truncate={true} style={textStyle}>
Add users to the portal (Development)
</Headline>
</Wrapper>
);
};
function mapStateToProps(state) {
return {
profile: state.profile.targetUser,
settings: state.auth.settings
};
}
export default connect(mapStateToProps)(withRouter(SectionHeaderContent));

View File

@ -1,2 +0,0 @@
export { default as SectionHeaderContent } from './Header';
export { default as SectionBodyContent } from './Body';

View File

@ -1,51 +0,0 @@
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/Reassign/{{lng}}/{{ns}}.json`
}
});
} else if (process.env.NODE_ENV === "development") {
const resources = {
en: {
translation: require("./locales/en/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;

View File

@ -1,93 +0,0 @@
import React from "react";
import { connect } from "react-redux";
// import PropTypes from "prop-types";
import { PageLayout } from "asc-web-common";
import {
ArticleHeaderContent,
ArticleMainButtonContent,
ArticleBodyContent
} from '../../Article';
// import { SectionHeaderContent } from './Section';
// import { fetchProfile } from '../../../store/profile/actions';
import i18n from "./i18n";
import { I18nextProvider } from "react-i18next";
import { SectionHeaderContent, SectionBodyContent } from './Section';
class Import extends React.Component {
componentDidMount() {
// const { match, fetchProfile } = this.props;
// const { userId } = match.params;
// if (userId) {
// fetchProfile(userId);
// }
}
componentDidUpdate(prevProps) {
// const { match, fetchProfile } = this.props;
// const { userId } = match.params;
// const prevUserId = prevProps.match.params.userId;
// if (userId !== undefined && userId !== prevUserId) {
// fetchProfile(userId);
// }
}
render() {
//console.log("Import render")
// let loaded = false;
// const { profile, match } = this.props;
// const { userId, type } = match.params;
// if (type) {
// loaded = true;
// } else if (profile) {
// loaded = profile.userName === userId || profile.id === userId;
// }
return (
<I18nextProvider i18n={i18n}>
<PageLayout>
<PageLayout.ArticleHeader>
<ArticleHeaderContent />
</PageLayout.ArticleHeader>
<PageLayout.ArticleMainButton>
<ArticleMainButtonContent />
</PageLayout.ArticleMainButton>
<PageLayout.ArticleBody>
<ArticleBodyContent />
</PageLayout.ArticleBody>
<PageLayout.SectionHeader>
<SectionHeaderContent />
</PageLayout.SectionHeader>
<PageLayout.SectionBody>
<SectionBodyContent />
</PageLayout.SectionBody>
</PageLayout>
</I18nextProvider>
);
}
}
Import.propTypes = {
// match: PropTypes.object.isRequired,
// profile: PropTypes.object,
// fetchProfile: PropTypes.func.isRequired
};
function mapStateToProps(state) {
return {
// profile: state.profile.targetUser
};
}
export default connect(mapStateToProps, {
})(Import);

View File

@ -1,16 +0,0 @@
{
"ReassignmentData": "Reassignment of data",
"ReassignsToUser": "Employee to whom the data will be transferred —",
"ChooseUser": "Choose user",
"ReassignsTransferedListHdr": "Will be transferred:",
"ReassignsTransferedListItem1": "General documents and personal documents that are available to other portal users;",
"ReassignsTransferedListItem2": "Open projects, milestones and tasks;",
"ReassignsTransferedListItem3": "Contacts, open tasks, unclosed opportunities and CRM cases;",
"NotBeUndone": "Note: this action cannot be undone.",
"ReassignsReadMore": "More about data transfer",
"DeleteProfileAfterReassignment": "Delete profile when reassignment will be finished",
"CancelButton": "Cancel",
"ReassignButton": "Reassign",
"LDAPLbl": "LDAP"
}

View File

@ -4,26 +4,34 @@ import {
IconButton,
ContextMenuButton,
toastr,
AvatarEditor,
AvatarEditor
} from "asc-web-components";
import { Headline } from 'asc-web-common';
import { Headline } from "asc-web-common";
import { withRouter } from "react-router";
import {
getUserStatus,
toEmployeeWrapper
} from "../../../../../store/people/selectors";
import { withTranslation, Trans } from "react-i18next";
import { updateUserStatus } from "../../../../../store/people/actions";
import { updateProfile } from "../../../../../store/profile/actions";
import {
updateUserStatus
} from "../../../../../store/people/actions";
import {
updateProfile
fetchProfile,
getUserPhoto
} from "../../../../../store/profile/actions";
import { fetchProfile, getUserPhoto } from "../../../../../store/profile/actions";
import styled from "styled-components";
import { store, api, constants } from "asc-web-common";
import { DeleteSelfProfileDialog, ChangePasswordDialog, ChangeEmailDialog, DeleteProfileEverDialog } from '../../../../dialogs';
import i18n from '../../i18n';
import {
DeleteSelfProfileDialog,
ChangePasswordDialog,
ChangeEmailDialog,
DeleteProfileEverDialog
} from "../../../../dialogs";
import { createI18N } from "../../../../../helpers/i18n";
const i18n = createI18N({
page: "Profile",
localesPath: "pages/Profile"
});
const { isAdmin, isMe } = store.auth.selectors;
const {
resendUserInvites,
@ -39,29 +47,29 @@ const StyledContainer = styled.div`
display: flex;
align-items: center;
.action-button {
margin-left: 16px;
.action-button {
margin-left: 16px;
@media (max-width: 1024px) {
margin-left: auto;
@media (max-width: 1024px) {
margin-left: auto;
& > div:first-child {
padding: 8px 16px 8px 0px;
margin-right: -16px;
}
}
}
.arrow-button {
@media (max-width: 1024px) {
padding: 8px 16px 8px 16px;
margin-left: -16px;
& > div:first-child {
padding: 8px 16px 8px 0px;
margin-right: -16px;
}
}
.header-headline {
margin-left: 16px;
}
.arrow-button {
@media (max-width: 1024px) {
padding: 8px 16px 8px 16px;
margin-left: -16px;
margin-right: -16px;
}
}
.header-headline {
margin-left: 16px;
}
`;
class SectionHeaderContent extends React.PureComponent {
@ -95,7 +103,7 @@ class SectionHeaderContent extends React.PureComponent {
changePassword: false,
changeEmail: false,
deleteProfileEver: false
},
}
};
return newState;
@ -111,7 +119,11 @@ class SectionHeaderContent extends React.PureComponent {
tmpFile: this.state.avatar.tmpFile,
defaultWidth: avatarDefaultSizes[1],
defaultHeight: avatarDefaultSizes[2],
image: userPhotoData.original ? userPhotoData.original.indexOf('default_user_photo') !== -1 ? null : userPhotoData.original : null
image: userPhotoData.original
? userPhotoData.original.indexOf("default_user_photo") !== -1
? null
: userPhotoData.original
: null
},
visibleAvatarEditor: true
});
@ -138,7 +150,7 @@ class SectionHeaderContent extends React.PureComponent {
loadAvatar(this.state.profile.id, data)
.then(response => {
var img = new Image();
img.onload = function () {
img.onload = function() {
var stateCopy = Object.assign({}, _this.state);
stateCopy.avatar = {
tmpFile: response.data,
@ -180,7 +192,7 @@ class SectionHeaderContent extends React.PureComponent {
.then(() => this.props.updateProfile(this.props.profile))
.then(() => this.props.fetchProfile(this.state.profile.id))
.then(() => toastr.success(this.props.t("ChangesApplied")))
.catch((error) => {
.catch(error => {
toastr.error(error);
});
} else {
@ -189,7 +201,7 @@ class SectionHeaderContent extends React.PureComponent {
let stateCopy = Object.assign({}, this.state);
stateCopy.visibleAvatarEditor = false;
stateCopy.profile.avatarMax = response.big;
toastr.success(this.props.t('ChangesApplied'));
toastr.success(this.props.t("ChangesApplied"));
this.setState(stateCopy);
})
.catch(error => toastr.error(error));
@ -202,9 +214,21 @@ class SectionHeaderContent extends React.PureComponent {
});
};
toggleChangePasswordDialog = () => this.setState({ dialogsVisible: { ...this.state.dialogsVisible, changePassword: !this.state.dialogsVisible.changePassword } });
toggleChangePasswordDialog = () =>
this.setState({
dialogsVisible: {
...this.state.dialogsVisible,
changePassword: !this.state.dialogsVisible.changePassword
}
});
toggleChangeEmailDialog = () => this.setState({ dialogsVisible: { ...this.state.dialogsVisible, changeEmail: !this.state.dialogsVisible.changeEmail } });
toggleChangeEmailDialog = () =>
this.setState({
dialogsVisible: {
...this.state.dialogsVisible,
changeEmail: !this.state.dialogsVisible.changeEmail
}
});
onEditClick = () => {
const { history, settings } = this.props;
@ -217,8 +241,8 @@ class SectionHeaderContent extends React.PureComponent {
updateUserStatus(status, new Array(userId))
.then(() => this.props.updateProfile(this.props.profile))
.then(() => fetchProfile(userId))
.then(() => toastr.success(t('SuccessChangeUserStatus')))
.catch(error => toastr.error(error))
.then(() => toastr.success(t("SuccessChangeUserStatus")))
.catch(error => toastr.error(error));
};
onDisableClick = () =>
@ -236,23 +260,33 @@ class SectionHeaderContent extends React.PureComponent {
toastr.success("Context action: Delete personal data");
};
toggleDeleteProfileEverDialog = () => this.setState({ dialogsVisible: { ...this.state.dialogsVisible, deleteProfileEver: !this.state.dialogsVisible.deleteProfileEver } });
toggleDeleteProfileEverDialog = () =>
this.setState({
dialogsVisible: {
...this.state.dialogsVisible,
deleteProfileEver: !this.state.dialogsVisible.deleteProfileEver
}
});
toggleDeleteSelfProfileDialog = () => {
this.setState(
{
dialogsVisible: { ...this.state.dialogsVisible, deleteSelfProfile: !this.state.dialogsVisible.deleteSelfProfile }
});
this.setState({
dialogsVisible: {
...this.state.dialogsVisible,
deleteSelfProfile: !this.state.dialogsVisible.deleteSelfProfile
}
});
};
onInviteAgainClick = () => {
resendUserInvites(new Array(this.state.profile.id))
.then(() =>
toastr.success(
<Trans i18nKey='MessageEmailActivationInstuctionsSentOnEmail' i18n={i18n}>
<Trans
i18nKey="MessageEmailActivationInstuctionsSentOnEmail"
i18n={i18n}
>
The email activation instructions have been sent to the
<strong>{{ email: this.state.profile.email }}</strong> email address
<strong>{{ email: this.state.profile.email }}</strong> email address
</Trans>
)
)
@ -295,15 +329,15 @@ class SectionHeaderContent extends React.PureComponent {
? viewer.isOwner
? {}
: {
key: "delete-profile",
label: t("DeleteSelfProfile"),
onClick: this.toggleDeleteSelfProfileDialog
}
key: "delete-profile",
label: t("DeleteSelfProfile"),
onClick: this.toggleDeleteSelfProfileDialog
}
: {
key: "disable",
label: t("DisableUserButton"),
onClick: this.onDisableClick
}
key: "disable",
label: t("DisableUserButton"),
onClick: this.onDisableClick
}
];
case "disabled":
return [
@ -351,17 +385,17 @@ class SectionHeaderContent extends React.PureComponent {
onClick: this.openAvatarEditor
},
!isMe(user, viewer.userName) &&
(user.status === EmployeeStatus.Active
? {
key: "disable",
label: t("DisableUserButton"),
onClick: this.onDisableClick
}
: {
key: "enable",
label: t("EnableUserButton"),
onClick: this.onEnableClick
}),
(user.status === EmployeeStatus.Active
? {
key: "disable",
label: t("DisableUserButton"),
onClick: this.onDisableClick
}
: {
key: "enable",
label: t("EnableUserButton"),
onClick: this.onEnableClick
}),
isMe(user, viewer.userName) && {
key: "delete-profile",
label: t("DeleteSelfProfile"),
@ -380,7 +414,15 @@ class SectionHeaderContent extends React.PureComponent {
};
render() {
const { profile, isAdmin, viewer, t, filter, settings, history } = this.props;
const {
profile,
isAdmin,
viewer,
t,
filter,
settings,
history
} = this.props;
const { avatar, visibleAvatarEditor, dialogsVisible } = this.state;
const contextOptions = () => this.getUserContextOptions(profile, viewer);
@ -395,7 +437,7 @@ class SectionHeaderContent extends React.PureComponent {
onClick={this.onClickBack}
className="arrow-button"
/>
<Headline className='header-headline' type='content' truncate={true}>
<Headline className="header-headline" type="content" truncate={true}>
{profile.displayName}
{profile.isLDAP && ` (${t("LDAPLbl")})`}
</Headline>
@ -424,34 +466,34 @@ class SectionHeaderContent extends React.PureComponent {
unknownTypeError={t("ErrorUnknownFileImageType")}
maxSizeFileError={t("maxSizeFileError")}
unknownError={t("Error")}
saveButtonLabel={t('SaveButton')}
saveButtonLabel={t("SaveButton")}
/>
{dialogsVisible.deleteSelfProfile &&
{dialogsVisible.deleteSelfProfile && (
<DeleteSelfProfileDialog
visible={dialogsVisible.deleteSelfProfile}
onClose={this.toggleDeleteSelfProfileDialog}
email={this.state.profile.email}
/>
}
)}
{dialogsVisible.changePassword &&
{dialogsVisible.changePassword && (
<ChangePasswordDialog
visible={dialogsVisible.changePassword}
onClose={this.toggleChangePasswordDialog}
email={this.state.profile.email}
/>
}
)}
{dialogsVisible.changeEmail &&
{dialogsVisible.changeEmail && (
<ChangeEmailDialog
visible={dialogsVisible.changeEmail}
onClose={this.toggleChangeEmailDialog}
user={this.state.profile}
/>
}
)}
{dialogsVisible.deleteProfileEver &&
{dialogsVisible.deleteProfileEver && (
<DeleteProfileEverDialog
visible={dialogsVisible.deleteProfileEver}
onClose={this.toggleDeleteProfileEverDialog}
@ -460,7 +502,7 @@ class SectionHeaderContent extends React.PureComponent {
settings={settings}
history={history}
/>
}
)}
</StyledContainer>
);
}

View File

@ -1,51 +0,0 @@
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/Profile/{{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: false
}
});
}
export default newInstance;

View File

@ -7,15 +7,18 @@ import {
ArticleHeaderContent,
ArticleMainButtonContent,
ArticleBodyContent
} from '../../Article';
import { SectionHeaderContent, SectionBodyContent } from './Section';
import { fetchProfile, resetProfile } from '../../../store/profile/actions';
import i18n from "./i18n";
} from "../../Article";
import { SectionHeaderContent, SectionBodyContent } from "./Section";
import { fetchProfile, resetProfile } from "../../../store/profile/actions";
import { I18nextProvider, withTranslation } from "react-i18next";
import { createI18N } from "../../../helpers/i18n";
const i18n = createI18N({
page: "Profile",
localesPath: "pages/Profile"
});
const { changeLanguage } = utils;
class PureProfile extends React.Component {
constructor(props) {
super(props);
@ -30,12 +33,14 @@ class PureProfile extends React.Component {
const { match, fetchProfile, t } = this.props;
const { userId } = match.params;
const queryParams = this.state.queryString.split('&');
const arrayOfQueryParams = queryParams.map(queryParam => queryParam.split('='));
const queryParams = this.state.queryString.split("&");
const arrayOfQueryParams = queryParams.map(queryParam =>
queryParam.split("=")
);
const linkParams = Object.fromEntries(arrayOfQueryParams);
if (linkParams.email_change && linkParams.email_change === "success") {
toastr.success(t('ChangeEmailSuccess'));
toastr.success(t("ChangeEmailSuccess"));
}
fetchProfile(userId);
@ -87,21 +92,24 @@ class PureProfile extends React.Component {
{profile ? (
<SectionBodyContent />
) : (
<Loader className="pageLoader" type="rombs" size="40px" />
)}
<Loader className="pageLoader" type="rombs" size="40px" />
)}
</PageLayout.SectionBody>
</PageLayout>
);
};
};
}
}
const ProfileContainer = withTranslation()(PureProfile);
const Profile = (props) => {
const Profile = props => {
changeLanguage(i18n);
return <I18nextProvider i18n={i18n}><ProfileContainer {...props} /></I18nextProvider>
return (
<I18nextProvider i18n={i18n}>
<ProfileContainer {...props} />
</I18nextProvider>
);
};
Profile.propTypes = {
@ -119,8 +127,10 @@ function mapStateToProps(state) {
};
}
export default connect(mapStateToProps,
export default connect(
mapStateToProps,
{
fetchProfile,
resetProfile
})(Profile);
}
)(Profile);

View File

@ -1,54 +0,0 @@
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/ProfileAction/{{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: false
}
});
}
export default newInstance;

View File

@ -14,8 +14,12 @@ import {
UpdateUserForm
} from "./Section";
import { fetchProfile } from "../../../store/profile/actions";
import i18n from "./i18n";
import { I18nextProvider, withTranslation } from "react-i18next";
import { createI18N } from "../../../helpers/i18n";
const i18n = createI18N({
page: "ProfileAction",
localesPath: "pages/ProfileAction"
});
const { changeLanguage } = utils;
class ProfileAction extends React.Component {
@ -55,7 +59,6 @@ class ProfileAction extends React.Component {
loaded = profile.userName === userId || profile.id === userId;
}
return (
<I18nextProvider i18n={i18n}>
<PageLayout>
@ -86,11 +89,11 @@ class ProfileAction extends React.Component {
type ? (
<CreateUserForm />
) : (
<UpdateUserForm />
)
<UpdateUserForm />
)
) : (
<Loader className="pageLoader" type="rombs" size="40px" />
)}
<Loader className="pageLoader" type="rombs" size="40px" />
)}
</PageLayout.SectionBody>
</PageLayout>
</I18nextProvider>
@ -123,4 +126,7 @@ function mapStateToProps(state) {
};
}
export default connect(mapStateToProps, { fetchProfile })(ProfileActionContainer);
export default connect(
mapStateToProps,
{ fetchProfile }
)(ProfileActionContainer);

View File

@ -1,51 +0,0 @@
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/Reassign/{{lng}}/{{ns}}.json`
}
});
} else if (process.env.NODE_ENV === "development") {
const resources = {
en: {
translation: require("./locales/en/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;

View File

@ -6,19 +6,21 @@ import {
ArticleHeaderContent,
ArticleMainButtonContent,
ArticleBodyContent
} from '../../Article';
} from "../../Article";
// import { SectionHeaderContent } from './Section';
// import { fetchProfile } from '../../../store/profile/actions';
import i18n from "./i18n";
import { I18nextProvider } from "react-i18next";
import { SectionHeaderContent, SectionBodyContent } from './Section';
import { SectionHeaderContent, SectionBodyContent } from "./Section";
import { createI18N } from "../../../helpers/i18n";
const i18n = createI18N({
page: "Reassign",
localesPath: "pages/Reassign"
});
class Reassign extends React.Component {
componentDidMount() {
// const { match, fetchProfile } = this.props;
// const { userId } = match.params;
// if (userId) {
// fetchProfile(userId);
// }
@ -28,14 +30,13 @@ class Reassign extends React.Component {
// const { match, fetchProfile } = this.props;
// const { userId } = match.params;
// const prevUserId = prevProps.match.params.userId;
// if (userId !== undefined && userId !== prevUserId) {
// fetchProfile(userId);
// }
}
render() {
console.log("Reassign render")
console.log("Reassign render");
// let loaded = false;
// const { profile, match } = this.props;
@ -65,7 +66,7 @@ class Reassign extends React.Component {
<PageLayout.SectionHeader>
<SectionHeaderContent />
</PageLayout.SectionHeader>
<PageLayout.SectionBody>
<SectionBodyContent />
</PageLayout.SectionBody>
@ -75,7 +76,6 @@ class Reassign extends React.Component {
}
}
Reassign.propTypes = {
// match: PropTypes.object.isRequired,
// profile: PropTypes.object,
@ -88,6 +88,7 @@ function mapStateToProps(state) {
};
}
export default connect(mapStateToProps, {
})(Reassign);
export default connect(
mapStateToProps,
{}
)(Reassign);

View File

@ -0,0 +1,16 @@
{
"ReassignmentData": "Переназначение данных",
"ReassignsToUser": "Сотрудник, которому будут переданы данные —",
"ChooseUser": "Выберите пользователя",
"ReassignsTransferedListHdr": "Будет передан:",
"ReassignsTransferedListItem1": "Общие документы и личные документы, доступные другим пользователям портала;",
"ReassignsTransferedListItem2": "Открытые проекты, вехи и задачи;",
"ReassignsTransferedListItem3": "Контакты, открытые задачи, незакрытые возможности и кейсы CRM;",
"NotBeUndone": "Примечание: это действие нельзя отменить.",
"ReassignsReadMore": "Подробнее о передаче данных",
"DeleteProfileAfterReassignment": "Удалить профиль, когда переназначение будет завершено",
"CancelButton": "Отмена",
"ReassignButton": "Переназначить",
"LDAPLbl": "LDAP"
}

View File

@ -0,0 +1,35 @@
import i18n from "i18next";
import Backend from "i18next-xhr-backend";
import { constants } from "asc-web-common";
const { i18nBaseSettings } = constants;
/**
* @description create i18n instance
* @param {object} object with method,url,data etc.
*/
export const createI18N = function(options) {
const { page, localesPath } = options;
const newInstance = i18n.createInstance();
if (process.env.NODE_ENV === "production") {
newInstance.use(Backend).init({
...i18nBaseSettings,
backend: {
loadPath: `/locales/${page}/{{lng}}/{{ns}}.json`
}
});
} else if (process.env.NODE_ENV === "development") {
const resources = {};
i18nBaseSettings.supportedLngs.forEach(name => {
resources[name] = {
translation: require(`../components/${localesPath}/locales/${name}/translation.json`)
};
});
newInstance.init({ ...i18nBaseSettings, resources });
}
return newInstance;
};