Merge branch 'master' of https://github.com/ONLYOFFICE/CommunityServer-AspNetCore
# Conflicts: # web/ASC.Web.Components/package.json
This commit is contained in:
commit
c313881377
@ -8,8 +8,9 @@ const ArticleHeaderContent = ({currentModuleName}) => {
|
||||
}
|
||||
|
||||
const mapStateToProps = (state) => {
|
||||
const currentModule = getCurrentModule(state.auth.modules, state.auth.settings.currentProductId);
|
||||
return {
|
||||
currentModuleName: getCurrentModule(state.auth.modules, state.auth.settings.currentProductId).title
|
||||
currentModuleName: (currentModule && currentModule.title) || ""
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,9 @@ if (process.env.NODE_ENV === "production") {
|
||||
const resources = {
|
||||
en: {
|
||||
translation: require("./locales/en/translation.json")
|
||||
},
|
||||
ru: {
|
||||
translation: require("./locales/ru/translation.json")
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -38,9 +38,12 @@ const StyledContainer = styled.div`
|
||||
}
|
||||
|
||||
.header-container {
|
||||
position: relative;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
max-width: calc(100vw - 32px);
|
||||
|
||||
.add-group-button {
|
||||
margin-left: 8px;
|
||||
}
|
||||
@ -225,7 +228,15 @@ const SectionHeaderContent = props => {
|
||||
) : (
|
||||
<>
|
||||
<Text.ContentHeader>Departments</Text.ContentHeader>
|
||||
|
||||
{isAdmin && (
|
||||
<IconButton
|
||||
className="add-group-button"
|
||||
size={16}
|
||||
iconName="PlusIcon"
|
||||
isFill={false}
|
||||
onClick={onAddDepartmentsClick}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
@ -8,7 +8,6 @@ import { useTranslation } from 'react-i18next';
|
||||
import { resendUserInvites } from "../../../../../store/services/api";
|
||||
import { EmployeeStatus } from "../../../../../helpers/constants";
|
||||
import { updateUserStatus } from "../../../../../store/people/actions";
|
||||
import { callbackify } from "util";
|
||||
import styled from 'styled-components';
|
||||
|
||||
const wrapperStyle = {
|
||||
|
@ -43,30 +43,22 @@ class PureProfile extends React.Component {
|
||||
render() {
|
||||
console.log("Profile render")
|
||||
|
||||
const { profile } = this.props;
|
||||
return (
|
||||
profile
|
||||
?
|
||||
<PageLayout
|
||||
articleHeaderContent={<ArticleHeaderContent />}
|
||||
articleMainButtonContent={<ArticleMainButtonContent />}
|
||||
articleBodyContent={<ArticleBodyContent />}
|
||||
sectionHeaderContent={
|
||||
<SectionHeaderContent profile={profile} />
|
||||
}
|
||||
sectionBodyContent={
|
||||
<SectionBodyContent profile={profile} />
|
||||
}
|
||||
/>
|
||||
: <PageLayout
|
||||
articleHeaderContent={<ArticleHeaderContent />}
|
||||
articleMainButtonContent={<ArticleMainButtonContent />}
|
||||
articleBodyContent={<ArticleBodyContent />}
|
||||
sectionBodyContent={
|
||||
<Loader className="pageLoader" type="rombs" size={40} />
|
||||
}
|
||||
/>
|
||||
);
|
||||
const { profile, isVisitor } = this.props;
|
||||
|
||||
const articleProps = isVisitor ? {} : {
|
||||
articleHeaderContent: <ArticleHeaderContent />,
|
||||
articleMainButtonContent: <ArticleMainButtonContent />,
|
||||
articleBodyContent: <ArticleBodyContent />
|
||||
};
|
||||
|
||||
const sectionProps = profile ? {
|
||||
sectionHeaderContent: <SectionHeaderContent profile={profile} />,
|
||||
sectionBodyContent: <SectionBodyContent profile={profile} />
|
||||
} : {
|
||||
sectionBodyContent: <Loader className="pageLoader" type="rombs" size={40} />
|
||||
};
|
||||
|
||||
return <PageLayout {...articleProps} {...sectionProps} />;
|
||||
};
|
||||
};
|
||||
|
||||
@ -92,6 +84,7 @@ function mapStateToProps(state) {
|
||||
return {
|
||||
profile: state.profile.targetUser,
|
||||
language: state.auth.user.cultureName || state.auth.settings.culture,
|
||||
isVisitor: state.auth.user.isVisitor,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -2,14 +2,21 @@ import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import PropTypes from "prop-types";
|
||||
import { PageLayout, Loader } from "asc-web-components";
|
||||
import { ArticleHeaderContent, ArticleMainButtonContent, ArticleBodyContent } from '../../Article';
|
||||
import { SectionHeaderContent, CreateUserForm, UpdateUserForm } from './Section';
|
||||
import { fetchProfile } from '../../../store/profile/actions';
|
||||
import {
|
||||
ArticleHeaderContent,
|
||||
ArticleMainButtonContent,
|
||||
ArticleBodyContent
|
||||
} from "../../Article";
|
||||
import {
|
||||
SectionHeaderContent,
|
||||
CreateUserForm,
|
||||
UpdateUserForm
|
||||
} from "./Section";
|
||||
import { fetchProfile } from "../../../store/profile/actions";
|
||||
import i18n from "./i18n";
|
||||
import { I18nextProvider } from "react-i18next";
|
||||
|
||||
class ProfileAction extends React.Component {
|
||||
|
||||
componentDidMount() {
|
||||
const { match, fetchProfile } = this.props;
|
||||
const { userId } = match.params;
|
||||
@ -30,10 +37,10 @@ class ProfileAction extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
console.log("ProfileAction render")
|
||||
console.log("ProfileAction render");
|
||||
|
||||
let loaded = false;
|
||||
const { profile, match, language } = this.props;
|
||||
const { profile, isVisitor, match, language } = this.props;
|
||||
const { userId, type } = match.params;
|
||||
|
||||
i18n.changeLanguage(language);
|
||||
@ -44,22 +51,28 @@ class ProfileAction extends React.Component {
|
||||
loaded = profile.userName === userId || profile.id === userId;
|
||||
}
|
||||
|
||||
const articleProps = isVisitor
|
||||
? {}
|
||||
: {
|
||||
articleHeaderContent: <ArticleHeaderContent />,
|
||||
articleMainButtonContent: <ArticleMainButtonContent />,
|
||||
articleBodyContent: <ArticleBodyContent />
|
||||
};
|
||||
|
||||
const sectionProps = loaded
|
||||
? {
|
||||
sectionHeaderContent: <SectionHeaderContent />,
|
||||
sectionBodyContent: type ? <CreateUserForm /> : <UpdateUserForm />
|
||||
}
|
||||
: {
|
||||
sectionBodyContent: (
|
||||
<Loader className="pageLoader" type="rombs" size={40} />
|
||||
)
|
||||
};
|
||||
|
||||
return (
|
||||
<I18nextProvider i18n={i18n}>
|
||||
{loaded
|
||||
? <PageLayout
|
||||
articleHeaderContent={<ArticleHeaderContent />}
|
||||
articleMainButtonContent={<ArticleMainButtonContent />}
|
||||
articleBodyContent={<ArticleBodyContent />}
|
||||
sectionHeaderContent={<SectionHeaderContent />}
|
||||
sectionBodyContent={type ? <CreateUserForm /> : <UpdateUserForm />}
|
||||
/>
|
||||
: <PageLayout
|
||||
articleHeaderContent={<ArticleHeaderContent />}
|
||||
articleMainButtonContent={<ArticleMainButtonContent />}
|
||||
articleBodyContent={<ArticleBodyContent />}
|
||||
sectionBodyContent={<Loader className="pageLoader" type="rombs" size={40} />}
|
||||
/>}
|
||||
<PageLayout {...articleProps} {...sectionProps} />
|
||||
</I18nextProvider>
|
||||
);
|
||||
}
|
||||
@ -75,9 +88,13 @@ function mapStateToProps(state) {
|
||||
return {
|
||||
profile: state.profile.targetUser,
|
||||
language: state.auth.user.cultureName || state.auth.settings.culture,
|
||||
isVisitor: state.auth.user.isVisitor,
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, {
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
{
|
||||
fetchProfile
|
||||
})(ProfileAction);
|
||||
}
|
||||
)(ProfileAction);
|
||||
|
@ -1802,14 +1802,15 @@ asap@~2.0.6:
|
||||
integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=
|
||||
|
||||
"asc-web-components@file:../../../packages/asc-web-components":
|
||||
version "1.0.87"
|
||||
version "1.0.102"
|
||||
dependencies:
|
||||
moment "^2.24.0"
|
||||
prop-types "^15.7.2"
|
||||
rc-tree "^2.1.2"
|
||||
react-autosize-textarea "^7.0.0"
|
||||
react-avatar-edit "^0.8.3"
|
||||
react-avatar-editor "^11.0.7"
|
||||
react-custom-scrollbars "^4.2.1"
|
||||
react-dropzone "^10.1.8"
|
||||
react-text-mask "^5.4.3"
|
||||
react-toastify "^5.3.2"
|
||||
react-virtualized-auto-sizer "^1.0.2"
|
||||
@ -1897,6 +1898,13 @@ atob@^2.1.1:
|
||||
resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
|
||||
integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
|
||||
|
||||
attr-accept@^1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/attr-accept/-/attr-accept-1.1.3.tgz#48230c79f93790ef2775fcec4f0db0f5db41ca52"
|
||||
integrity sha512-iT40nudw8zmCweivz6j58g+RT33I4KbaIvRUhjNmDwO2WmsQUxFEZZYZ5w3vXe5x5MX9D7mfvA/XaLOZYFR9EQ==
|
||||
dependencies:
|
||||
core-js "^2.5.0"
|
||||
|
||||
autoprefixer@^9.6.1:
|
||||
version "9.6.1"
|
||||
resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.6.1.tgz#51967a02d2d2300bb01866c1611ec8348d355a47"
|
||||
@ -2968,7 +2976,7 @@ core-js@3.1.4:
|
||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.1.4.tgz#3a2837fc48e582e1ae25907afcd6cf03b0cc7a07"
|
||||
integrity sha512-YNZN8lt82XIMLnLirj9MhKDFZHalwzzrL9YLt6eb0T5D0EDl4IQ90IGkua8mHbnxNrkj1d8hbdizMc0Qmg1WnQ==
|
||||
|
||||
core-js@^2.4.0, core-js@^2.6.4:
|
||||
core-js@^2.4.0, core-js@^2.5.0, core-js@^2.6.4:
|
||||
version "2.6.9"
|
||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.9.tgz#6b4b214620c834152e179323727fc19741b084f2"
|
||||
integrity sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A==
|
||||
@ -4320,6 +4328,13 @@ file-loader@3.0.1:
|
||||
loader-utils "^1.0.2"
|
||||
schema-utils "^1.0.0"
|
||||
|
||||
file-selector@^0.1.11:
|
||||
version "0.1.12"
|
||||
resolved "https://registry.yarnpkg.com/file-selector/-/file-selector-0.1.12.tgz#fe726547be219a787a9dcc640575a04a032b1fd0"
|
||||
integrity sha512-Kx7RTzxyQipHuiqyZGf+Nz4vY9R1XGxuQl/hLoJwq+J4avk/9wxxgZyHKtbyIPJmbD4A66DWGYfyykWNpcYutQ==
|
||||
dependencies:
|
||||
tslib "^1.9.0"
|
||||
|
||||
filesize@3.6.1:
|
||||
version "3.6.1"
|
||||
resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.6.1.tgz#090bb3ee01b6f801a8a8be99d31710b3422bb317"
|
||||
@ -6298,11 +6313,6 @@ kleur@^3.0.3:
|
||||
resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e"
|
||||
integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==
|
||||
|
||||
konva@2.5.1:
|
||||
version "2.5.1"
|
||||
resolved "https://registry.yarnpkg.com/konva/-/konva-2.5.1.tgz#cca611a9522e831e54cf57c508a1aed3f0ceac25"
|
||||
integrity sha512-YdHEWqmbWPieqIZuLx7JFGm9Ui08hSUaSJ2k2Ml8o5giFgJ0WmxAS0DPXIM+Ty2ADRagOHZfXSJ/skwYqqlwgQ==
|
||||
|
||||
last-call-webpack-plugin@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/last-call-webpack-plugin/-/last-call-webpack-plugin-3.0.0.tgz#9742df0e10e3cf46e5c0381c2de90d3a7a2d7555"
|
||||
@ -8736,12 +8746,12 @@ react-autosize-textarea@^7.0.0:
|
||||
line-height "^0.3.1"
|
||||
prop-types "^15.5.6"
|
||||
|
||||
react-avatar-edit@^0.8.3:
|
||||
version "0.8.3"
|
||||
resolved "https://registry.yarnpkg.com/react-avatar-edit/-/react-avatar-edit-0.8.3.tgz#0ebf21391328fc255429bdfbc782f795827109bf"
|
||||
integrity sha512-QEedh6DjDCSI7AUsUHHtfhxApCWC5hJAoywxUA5PtUdw03iIjEurgVqPOIt1UBHhU/Zk/9amElRF3oepN9JZSg==
|
||||
react-avatar-editor@^11.0.7:
|
||||
version "11.0.7"
|
||||
resolved "https://registry.yarnpkg.com/react-avatar-editor/-/react-avatar-editor-11.0.7.tgz#021053cfeaa138407b79279ee5a0384f273f0c54"
|
||||
integrity sha512-GbNYBd1/L1QyuU9VRvOW0hSkW1R0XSneOWZFgqI5phQf6dX+dF/G3/AjiJ0hv3JWh2irMQ7DL0oYDKzwtTnNBQ==
|
||||
dependencies:
|
||||
konva "2.5.1"
|
||||
prop-types "^15.5.8"
|
||||
|
||||
react-custom-scrollbars@^4.2.1:
|
||||
version "4.2.1"
|
||||
@ -8798,6 +8808,15 @@ react-dom@^16.9.0:
|
||||
prop-types "^15.6.2"
|
||||
scheduler "^0.15.0"
|
||||
|
||||
react-dropzone@^10.1.8:
|
||||
version "10.1.9"
|
||||
resolved "https://registry.yarnpkg.com/react-dropzone/-/react-dropzone-10.1.9.tgz#8093ecd7d2dc4002280eb2dac1d5fa4216c800ee"
|
||||
integrity sha512-7iqALZ0mzk+4g/AsYxEy3QyWPMTVQYKQVkYUe9zIbH18u+pi7EBDg010KEwfIX6jeTDH2qP0E6/eUnXvBYrovA==
|
||||
dependencies:
|
||||
attr-accept "^1.1.3"
|
||||
file-selector "^0.1.11"
|
||||
prop-types "^15.7.2"
|
||||
|
||||
react-error-overlay@^6.0.1:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.1.tgz#b8d3cf9bb991c02883225c48044cb3ee20413e0f"
|
||||
|
@ -21,7 +21,7 @@ const App = () => {
|
||||
<Switch>
|
||||
<PublicRoute exact path={["/login","/login/error=:error", "/login/confirmed-email=:confirmedEmail"]} component={Login} />
|
||||
<Route path="/confirm" component={Confirm} />
|
||||
<PrivateRoute exact path="/" component={Home} />
|
||||
<PrivateRoute exact path={["/","/error=:error"]} component={Home} />
|
||||
<PrivateRoute exact path="/about" component={About} />
|
||||
<PrivateRoute component={Error404} />
|
||||
</Switch>
|
||||
|
@ -2,18 +2,18 @@ import React, { Suspense, lazy } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { Redirect, Route, Switch } from "react-router-dom";
|
||||
import { Loader } from "asc-web-components";
|
||||
import PublicRoute from "../../../helpers/publicRoute";
|
||||
import ConfirmRoute from "../../../helpers/confirmRoute";
|
||||
import i18n from "./i18n";
|
||||
import { I18nextProvider } from "react-i18next";
|
||||
import ActivateEmailForm from "./sub-components/activateEmail";
|
||||
|
||||
const ActivateUserForm = lazy(() => import("./sub-components/activateUser"));
|
||||
const CreateUserForm = lazy(() => import("./sub-components/createUser"));
|
||||
const ChangePasswordForm = lazy(() => import("./sub-components/changePassword"));
|
||||
// const ActivateEmailForm = lazy(() => import("./sub-components/activateEmail"));
|
||||
const ActivateEmailForm = lazy(() => import("./sub-components/activateEmail"));
|
||||
const ChangeEmailForm = lazy(() => import("./sub-components/changeEmail"));
|
||||
const ChangePhoneForm = lazy(() => import("./sub-components/changePhone"));
|
||||
const ProfileRemoveForm = lazy(() => import("./sub-components/profileRemove"));
|
||||
const Error404 = lazy(() => import("../Error"));
|
||||
|
||||
const Confirm = ({ match, language }) => {
|
||||
|
||||
@ -49,12 +49,17 @@ const Confirm = ({ match, language }) => {
|
||||
path={`${match.path}/PasswordChange`}
|
||||
component={ChangePasswordForm}
|
||||
/>
|
||||
<ConfirmRoute
|
||||
exact
|
||||
path={`${match.path}/ProfileRemove`}
|
||||
component={ProfileRemoveForm}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path={`${match.path}/PhoneActivation`}
|
||||
component={ChangePhoneForm}
|
||||
/>
|
||||
<Redirect to={{ pathname: "/" }} />
|
||||
<Route component={Error404} />
|
||||
</Switch>
|
||||
</Suspense>
|
||||
</I18nextProvider >
|
||||
|
@ -18,6 +18,11 @@
|
||||
"ImportContactsOkButton": "OK",
|
||||
"LoadingProcessing": "Loading...",
|
||||
"ChangePasswordSuccess": "Password has been successfully changed",
|
||||
"DeleteProfileBtn": "Delete my account",
|
||||
"DeleteProfileConfirmation": "Attention! You are about to delete your account.",
|
||||
"DeleteProfileConfirmationInfo": "By clicking the \"Delete my account\" button you agree with our Privacy policy.",
|
||||
"DeleteProfileSuccessMessage": "Your account has been successfully deleted.",
|
||||
"DeleteProfileSuccessMessageInfo": "See our Privacy policy to learn more about deleting your account and data accociated with it.",
|
||||
|
||||
|
||||
"CustomWelcomePageTitle": "{{welcomePageTitle}}"
|
||||
|
@ -7,7 +7,7 @@ import { Collapse } from 'reactstrap';
|
||||
import { connect } from 'react-redux';
|
||||
import { welcomePageTitle } from './../../../../helpers/customNames';
|
||||
import { EmployeeActivationStatus } from './../../../../helpers/constants';
|
||||
import { getConfirmationInfo, activateConfirmUser } from '../../../../store/auth/actions';
|
||||
import { getConfirmationInfo, activateConfirmUser, logout } from '../../../../store/auth/actions';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const inputWidth = '400px';
|
||||
@ -74,7 +74,7 @@ class Confirm extends React.PureComponent {
|
||||
|
||||
onSubmit = (e) => {
|
||||
this.setState({ isLoading: true }, function () {
|
||||
const { history, activateConfirmUser } = this.props;
|
||||
const { activateConfirmUser, logout } = this.props;
|
||||
|
||||
this.setState({ errorText: "" });
|
||||
|
||||
@ -111,9 +111,9 @@ class Confirm extends React.PureComponent {
|
||||
firstname: this.state.firstName,
|
||||
lastname: this.state.lastName
|
||||
};
|
||||
|
||||
logout();
|
||||
activateConfirmUser(personalData, loginData, this.state.key, this.state.userId, EmployeeActivationStatus.Activated)
|
||||
.then(() => history.push('/'))
|
||||
.then(() => window.location.href = '/')
|
||||
.catch(e => {
|
||||
console.error("activate error", e);
|
||||
this.setState({ errorText: e.message });
|
||||
@ -321,4 +321,4 @@ function mapStateToProps(state) {
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, { getConfirmationInfo, activateConfirmUser })(withRouter(withTranslation()(ActivateUserForm)));
|
||||
export default connect(mapStateToProps, { getConfirmationInfo, activateConfirmUser,logout })(withRouter(withTranslation()(ActivateUserForm)));
|
@ -101,6 +101,7 @@ class Form extends React.PureComponent {
|
||||
toastr.success(this.props.t("ChangePasswordSuccess"));
|
||||
history.push("/");
|
||||
})
|
||||
//.catch((res) => toastr.error(res.data))
|
||||
.catch(e => {
|
||||
toastr.error(this.props.t(`${e.message}`));
|
||||
this.setState({ isLoading: false });
|
||||
@ -110,7 +111,8 @@ class Form extends React.PureComponent {
|
||||
|
||||
componentDidMount() {
|
||||
const { getConfirmationInfo, history } = this.props;
|
||||
getConfirmationInfo(this.state.key).catch(e => {
|
||||
getConfirmationInfo(this.state.key)
|
||||
.catch(e => {
|
||||
toastr.error(this.props.t(`${e.message}`));
|
||||
history.push("/");
|
||||
});
|
||||
|
@ -6,7 +6,7 @@ import styled from 'styled-components';
|
||||
import { Collapse } from 'reactstrap';
|
||||
import { connect } from 'react-redux';
|
||||
import { welcomePageTitle } from './../../../../helpers/customNames';
|
||||
import { getConfirmationInfo, createConfirmUser } from '../../../../store/auth/actions';
|
||||
import { getConfirmationInfo, createConfirmUser, logout } from '../../../../store/auth/actions';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const inputWidth = '400px';
|
||||
@ -73,7 +73,7 @@ class Confirm extends React.PureComponent {
|
||||
|
||||
onSubmit = (e) => {
|
||||
this.setState({ isLoading: true }, function () {
|
||||
const { history, createConfirmUser, linkData } = this.props;
|
||||
const { history, createConfirmUser, logout, linkData } = this.props;
|
||||
const isVisitor = parseInt(linkData.emplType) === 2;
|
||||
|
||||
this.setState({ errorText: "" });
|
||||
@ -118,8 +118,9 @@ class Confirm extends React.PureComponent {
|
||||
email: this.state.email
|
||||
};
|
||||
const registerData = Object.assign(personalData, { isVisitor: isVisitor })
|
||||
logout();
|
||||
createConfirmUser(registerData, loginData, this.state.key)
|
||||
.then(() => history.push('/'))
|
||||
.then(() => window.location.href = '/')
|
||||
.catch(e => {
|
||||
console.error("confirm error", e);
|
||||
this.setState({
|
||||
@ -340,4 +341,4 @@ function mapStateToProps(state) {
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, { getConfirmationInfo, createConfirmUser })(withRouter(withTranslation()(CreateUserForm)));
|
||||
export default connect(mapStateToProps, { getConfirmationInfo, createConfirmUser, logout })(withRouter(withTranslation()(CreateUserForm)));
|
@ -0,0 +1,113 @@
|
||||
import React from 'react';
|
||||
import { withRouter } from "react-router";
|
||||
import { Button, PageLayout, Text } from 'asc-web-components';
|
||||
import styled from 'styled-components';
|
||||
import { welcomePageTitle } from './../../../../helpers/customNames';
|
||||
import PropTypes from 'prop-types';
|
||||
import { withTranslation } from 'react-i18next';
|
||||
import { deleteUser, updateUserStatus } from './../../../../store/services/api'
|
||||
import { EmployeeStatus } from './../../../../helpers/constants';
|
||||
|
||||
const ProfileRemoveContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
.start-basis {
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.confirm-row {
|
||||
margin: 23px 0 0;
|
||||
}
|
||||
|
||||
.break-word {
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
`;
|
||||
|
||||
class ProfileRemove extends React.PureComponent {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.state = {
|
||||
isProfileDeleted: false
|
||||
};
|
||||
}
|
||||
|
||||
onDeleteProfile = (e) => {
|
||||
this.setState({ isLoading: true }, function () {
|
||||
const { linkData } = this.props;
|
||||
|
||||
updateUserStatus(EmployeeStatus.Disabled, [linkData.uid], linkData.confirmHeader)
|
||||
.then((res) => {
|
||||
console.log('success update status', res)
|
||||
return deleteUser(linkData.uid);
|
||||
})
|
||||
.then((res) => {
|
||||
this.setState({
|
||||
isLoading: false,
|
||||
isProfileDeleted: true
|
||||
});
|
||||
console.log('success delete', res)
|
||||
})
|
||||
.catch((e) => {
|
||||
this.setState({ isLoading: false });
|
||||
console.log('error delete', e)
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
render() {
|
||||
console.log('profileRemove render');
|
||||
const { t } = this.props;
|
||||
const { isProfileDeleted } = this.state;
|
||||
return (
|
||||
<ProfileRemoveContainer>
|
||||
<div className='start-basis'>
|
||||
|
||||
<div className='confirm-row full-width break-word'>
|
||||
<a href='/login'>
|
||||
<img src="images/dark_general.png" alt="Logo" />
|
||||
</a>
|
||||
<Text.Body as='p' fontSize={24} color='#116d9d'>{t('CustomWelcomePageTitle', { welcomePageTitle })}</Text.Body>
|
||||
</div>
|
||||
|
||||
{!isProfileDeleted
|
||||
? <>
|
||||
<Text.Body className='confirm-row' as='p' fontSize={18} >{t('DeleteProfileConfirmation')}</Text.Body>
|
||||
<Text.Body className='confirm-row' as='p' fontSize={16} >{t('DeleteProfileConfirmationInfo')}</Text.Body>
|
||||
|
||||
<Button
|
||||
className='confirm-row'
|
||||
primary
|
||||
size='big'
|
||||
label={t('DeleteProfileBtn')}
|
||||
tabIndex={1}
|
||||
isLoading={this.state.isLoading}
|
||||
onClick={this.onDeleteProfile}
|
||||
/>
|
||||
</>
|
||||
: <>
|
||||
<Text.Body className='confirm-row' as='p' fontSize={18} >{t('DeleteProfileSuccessMessage')}</Text.Body>
|
||||
<Text.Body className='confirm-row' as='p' fontSize={16} >{t('DeleteProfileSuccessMessageInfo')}</Text.Body>
|
||||
</>
|
||||
}
|
||||
|
||||
</div>
|
||||
</ProfileRemoveContainer>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ProfileRemove.propTypes = {
|
||||
location: PropTypes.object.isRequired,
|
||||
};
|
||||
const ProfileRemoveForm = (props) => (<PageLayout sectionBodyContent={<ProfileRemove {...props} />} />);
|
||||
|
||||
|
||||
export default withRouter(withTranslation()(ProfileRemoveForm));
|
@ -1,9 +1,9 @@
|
||||
import React from 'react';
|
||||
import React, { useEffect } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import { withRouter } from "react-router";
|
||||
import { Container, Col, Row, Collapse } from 'reactstrap';
|
||||
import { ModuleTile, Loader, PageLayout } from 'asc-web-components';
|
||||
import { ModuleTile, Loader, PageLayout, toastr } from 'asc-web-components';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import i18n from './i18n';
|
||||
|
||||
@ -30,8 +30,14 @@ Tiles.propTypes = {
|
||||
history: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
const Body = ({ modules, history, isLoaded }) => {
|
||||
const Body = ({ modules, match, history, isLoaded }) => {
|
||||
const { t } = useTranslation('translation', { i18n });
|
||||
const { params } = match;
|
||||
|
||||
useEffect(() => {
|
||||
params.error && toastr.error(params.error);
|
||||
}, [params.error]);
|
||||
|
||||
return (
|
||||
!isLoaded
|
||||
? (
|
||||
|
@ -1,18 +1,47 @@
|
||||
import React, { useState, useEffect, useCallback } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { useState, useEffect, useCallback } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { withRouter } from "react-router";
|
||||
import { Collapse, Container, Row, Col, Card, CardTitle, CardImg } from 'reactstrap';
|
||||
import { Button, TextInput, PageLayout, Text } from 'asc-web-components';
|
||||
import { connect } from 'react-redux';
|
||||
import { login } from '../../../store/auth/actions';
|
||||
import styled from 'styled-components';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import i18n from './i18n';
|
||||
import { welcomePageTitle } from './../../../helpers/customNames';
|
||||
import {
|
||||
Collapse,
|
||||
Container,
|
||||
Row,
|
||||
Col,
|
||||
Card,
|
||||
CardTitle,
|
||||
CardImg
|
||||
} from "reactstrap";
|
||||
import {
|
||||
Button,
|
||||
TextInput,
|
||||
PageLayout,
|
||||
Text,
|
||||
Link,
|
||||
toastr
|
||||
} from "asc-web-components";
|
||||
import { connect } from "react-redux";
|
||||
import { login } from "../../../store/auth/actions";
|
||||
import styled from "styled-components";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import i18n from "./i18n";
|
||||
import { welcomePageTitle } from "./../../../helpers/customNames";
|
||||
import { sendInstructionsToChangePassword } from "../../../store/services/api";
|
||||
import SubModalDialog from "./sub-components/modal-dialog";
|
||||
|
||||
const FormContainer = styled(Container)`
|
||||
margin-top: 70px;
|
||||
|
||||
.link-style {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.text-body {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.btn-style {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.login-row {
|
||||
margin: 23px 0 0;
|
||||
|
||||
@ -37,21 +66,47 @@ const FormContainer = styled(Container)`
|
||||
const mdOptions = { size: 6, offset: 3 };
|
||||
|
||||
const Form = props => {
|
||||
const { t } = useTranslation('translation', { i18n });
|
||||
const { t } = useTranslation("translation", { i18n });
|
||||
const { login, match, location, history, language } = props;
|
||||
const { params } = match;
|
||||
const [identifier, setIdentifier] = useState(params.confirmedEmail || '');
|
||||
const [identifier, setIdentifier] = useState(params.confirmedEmail || "");
|
||||
const [identifierValid, setIdentifierValid] = useState(true);
|
||||
const [password, setPassword] = useState('');
|
||||
const [password, setPassword] = useState("");
|
||||
const [passwordValid, setPasswordValid] = useState(true);
|
||||
const [errorText, setErrorText] = useState("");
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
const onSubmit = useCallback((e) => {
|
||||
//e.preventDefault();
|
||||
const [openDialog, setOpenDialog] = useState(false);
|
||||
const [email, setEmail] = useState("");
|
||||
const [isDisabled, setIsDisabled] = useState(false);
|
||||
|
||||
const onClick = () => {
|
||||
setOpenDialog(true);
|
||||
setIsDisabled(true);
|
||||
setEmail(identifier);
|
||||
};
|
||||
|
||||
const onDialogClose = () => {
|
||||
setOpenDialog(false);
|
||||
setIsDisabled(false);
|
||||
setIsLoading(false);
|
||||
setEmail("");
|
||||
};
|
||||
|
||||
const onSendPasswordInstructions = useCallback(() => {
|
||||
setIsLoading(true);
|
||||
sendInstructionsToChangePassword(email)
|
||||
.then(res => {
|
||||
res.data.error
|
||||
? toastr.error(res.data.error.message)
|
||||
: toastr.success(res.data.response);
|
||||
})
|
||||
.catch(error => toastr.error(error.message))
|
||||
.finally(onDialogClose());
|
||||
}, [email]);
|
||||
|
||||
const onSubmit = useCallback(() => {
|
||||
errorText && setErrorText("");
|
||||
|
||||
let hasError = false;
|
||||
|
||||
if (!identifier.trim()) {
|
||||
@ -64,8 +119,7 @@ const Form = props => {
|
||||
setPasswordValid(!hasError);
|
||||
}
|
||||
|
||||
if (hasError)
|
||||
return false;
|
||||
if (hasError) return false;
|
||||
|
||||
setIsLoading(true);
|
||||
|
||||
@ -77,31 +131,32 @@ const Form = props => {
|
||||
login(payload)
|
||||
.then(function() {
|
||||
console.log("auth success", match, location, history);
|
||||
setIsLoading(false)
|
||||
history.push('/');
|
||||
setIsLoading(false);
|
||||
history.push("/");
|
||||
})
|
||||
.catch(e => {
|
||||
console.error("auth error", e);
|
||||
setErrorText(e.message);
|
||||
setIsLoading(false)
|
||||
setIsLoading(false);
|
||||
});
|
||||
}, [errorText, history, identifier, location, login, match, password]);
|
||||
|
||||
const onKeyPress = useCallback((event) => {
|
||||
const onKeyPress = useCallback(
|
||||
event => {
|
||||
if (event.key === "Enter") {
|
||||
onSubmit();
|
||||
!isDisabled ? onSubmit() : onSendPasswordInstructions();
|
||||
}
|
||||
}, [onSubmit]);
|
||||
},
|
||||
[onSendPasswordInstructions, onSubmit, isDisabled]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
i18n.changeLanguage(language);
|
||||
params.error && setErrorText(params.error);
|
||||
window.addEventListener('keydown', onKeyPress);
|
||||
window.addEventListener('keyup', onKeyPress);
|
||||
window.addEventListener("keyup", onKeyPress);
|
||||
// Remove event listeners on cleanup
|
||||
return () => {
|
||||
window.removeEventListener('keydown', onKeyPress);
|
||||
window.removeEventListener('keyup', onKeyPress);
|
||||
window.removeEventListener("keyup", onKeyPress);
|
||||
};
|
||||
}, [onKeyPress, params, language]);
|
||||
|
||||
@ -109,13 +164,17 @@ const Form = props => {
|
||||
setPassword(event.target.value);
|
||||
!passwordValid && setPasswordValid(true);
|
||||
errorText && setErrorText("");
|
||||
}
|
||||
};
|
||||
|
||||
const onChangeLogin = event => {
|
||||
setIdentifier(event.target.value);
|
||||
!identifierValid && setIdentifierValid(true);
|
||||
errorText && setErrorText("");
|
||||
}
|
||||
};
|
||||
|
||||
const onChangeEmail = event => {
|
||||
setEmail(event.target.value);
|
||||
};
|
||||
|
||||
// console.log('Login render');
|
||||
|
||||
@ -124,8 +183,15 @@ const Form = props => {
|
||||
<Row className="login-row">
|
||||
<Col sm="12" md={mdOptions}>
|
||||
<Card className="login-card">
|
||||
<CardImg className="card-img" src="images/dark_general.png" alt="Logo" top />
|
||||
<CardTitle className="card-title">{t('CustomWelcomePageTitle', { welcomePageTitle })}</CardTitle>
|
||||
<CardImg
|
||||
className="card-img"
|
||||
src="images/dark_general.png"
|
||||
alt="Logo"
|
||||
top
|
||||
/>
|
||||
<CardTitle className="card-title">
|
||||
{t("CustomWelcomePageTitle", { welcomePageTitle })}
|
||||
</CardTitle>
|
||||
</Card>
|
||||
</Col>
|
||||
</Row>
|
||||
@ -136,15 +202,16 @@ const Form = props => {
|
||||
name="login"
|
||||
hasError={!identifierValid}
|
||||
value={identifier}
|
||||
placeholder={t('RegistrationEmailWatermark')}
|
||||
size='huge'
|
||||
placeholder={t("RegistrationEmailWatermark")}
|
||||
size="huge"
|
||||
scale={true}
|
||||
isAutoFocussed={true}
|
||||
tabIndex={1}
|
||||
isDisabled={isLoading}
|
||||
autoComplete="username"
|
||||
onChange={onChangeLogin}
|
||||
onKeyDown={onKeyPress} />
|
||||
onKeyDown={onKeyPress}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row className="login-row">
|
||||
@ -155,34 +222,64 @@ const Form = props => {
|
||||
type="password"
|
||||
hasError={!passwordValid}
|
||||
value={password}
|
||||
placeholder={t('Password')}
|
||||
size='huge'
|
||||
placeholder={t("Password")}
|
||||
size="huge"
|
||||
scale={true}
|
||||
tabIndex={2}
|
||||
isDisabled={isLoading}
|
||||
autoComplete="current-password"
|
||||
onChange={onChangePassword}
|
||||
onKeyDown={onKeyPress} />
|
||||
onKeyDown={onKeyPress}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row className="login-row">
|
||||
<Col sm="12" md={mdOptions}>
|
||||
<Link
|
||||
fontSize={12}
|
||||
className="link-style"
|
||||
type="page"
|
||||
isHovered={true}
|
||||
onClick={onClick}
|
||||
>
|
||||
{t("ForgotPassword")}
|
||||
</Link>
|
||||
</Col>
|
||||
</Row>
|
||||
{openDialog ? (
|
||||
<SubModalDialog
|
||||
openDialog={openDialog}
|
||||
isLoading={isLoading}
|
||||
email={email}
|
||||
onChangeEmail={onChangeEmail}
|
||||
onSendPasswordInstructions={onSendPasswordInstructions}
|
||||
onDialogClose={onDialogClose}
|
||||
t={t}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
<Row className="login-row">
|
||||
<Col sm="12" md={mdOptions}>
|
||||
<Button
|
||||
primary
|
||||
size='big'
|
||||
label={isLoading ? t('LoadingProcessing') : t('LoginButton')}
|
||||
size="big"
|
||||
label={isLoading ? t("LoadingProcessing") : t("LoginButton")}
|
||||
tabIndex={3}
|
||||
isDisabled={isLoading}
|
||||
isLoading={isLoading}
|
||||
onClick={onSubmit} />
|
||||
onClick={onSubmit}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
{params.confirmedEmail && <Row className="login-row">
|
||||
{params.confirmedEmail && (
|
||||
<Row className="login-row">
|
||||
<Col sm="12" md={mdOptions}>
|
||||
<Text.Body isBold={true} fontSize={16}>{t('MessageEmailConfirmed')} {t('MessageAuthorize')}</Text.Body>
|
||||
<Text.Body isBold={true} fontSize={16}>
|
||||
{t("MessageEmailConfirmed")} {t("MessageAuthorize")}
|
||||
</Text.Body>
|
||||
</Col>
|
||||
</Row>
|
||||
}
|
||||
)}
|
||||
<Collapse isOpen={!!errorText}>
|
||||
<Row className="login-row">
|
||||
<Col sm="12" md={mdOptions}>
|
||||
@ -192,26 +289,32 @@ const Form = props => {
|
||||
</Collapse>
|
||||
</FormContainer>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const LoginForm = (props) => (<PageLayout sectionBodyContent={<Form {...props} />} />);
|
||||
const LoginForm = props => (
|
||||
<PageLayout sectionBodyContent={<Form {...props} />} />
|
||||
);
|
||||
|
||||
LoginForm.propTypes = {
|
||||
login: PropTypes.func.isRequired,
|
||||
match: PropTypes.object.isRequired,
|
||||
location: PropTypes.object.isRequired,
|
||||
history: PropTypes.object.isRequired
|
||||
}
|
||||
};
|
||||
|
||||
LoginForm.defaultProps = {
|
||||
identifier: "",
|
||||
password: ""
|
||||
}
|
||||
password: "",
|
||||
email: ""
|
||||
};
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
language: state.auth.user.cultureName || state.auth.settings.culture,
|
||||
language: state.auth.user.cultureName || state.auth.settings.culture
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, { login })(withRouter(LoginForm));
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
{ login }
|
||||
)(withRouter(LoginForm));
|
||||
|
@ -5,6 +5,11 @@
|
||||
"RegistrationEmailWatermark": "Your registration email",
|
||||
"MessageEmailConfirmed": "Your email was activated successfully.",
|
||||
"MessageAuthorize": "Please authorize yourself.",
|
||||
"ForgotPassword": "Forgot your password?",
|
||||
"PasswordRecoveryTitle": "Password recovery",
|
||||
"MessageSendPasswordRecoveryInstructionsOnEmail": "Please enter the email you used while registering on the portal. The password recovery instructions will be send to that email address.",
|
||||
"SendButton": "Send",
|
||||
"CancelButton": "Cancel",
|
||||
|
||||
"CustomWelcomePageTitle": "{{welcomePageTitle}}"
|
||||
}
|
@ -5,6 +5,11 @@
|
||||
"RegistrationEmailWatermark": "Регистрационный email",
|
||||
"MessageEmailConfirmed": "Ваш email успешно активирован.",
|
||||
"MessageAuthorize": "Пожалуйста авторизуйтесь.",
|
||||
"ForgotPassword": "Забыли пароль?",
|
||||
"PasswordRecoveryTitle": "Восстановление пароля",
|
||||
"MessageSendPasswordRecoveryInstructionsOnEmail": "Пожалуйста, введите адрес электронной почты, указанный при регистрации на портале. Инструкции для восстановления пароля будут отправлены на этот адрес электронной почты.",
|
||||
"SendButton": "Отправить",
|
||||
"CancelButton": "Отмена",
|
||||
|
||||
"CustomWelcomePageTitle": "{{welcomePageTitle}}"
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { Button, TextInput, Text, ModalDialog } from "asc-web-components";
|
||||
|
||||
class SubModalDialog extends React.Component {
|
||||
render() {
|
||||
const {
|
||||
openDialog,
|
||||
isLoading,
|
||||
email,
|
||||
onChangeEmail,
|
||||
onSendPasswordInstructions,
|
||||
onDialogClose,
|
||||
t
|
||||
} = this.props;
|
||||
return (
|
||||
<ModalDialog
|
||||
visible={openDialog}
|
||||
headerContent={
|
||||
<Text.Body isBold={false} fontSize={21}>
|
||||
{t("PasswordRecoveryTitle")}
|
||||
</Text.Body>
|
||||
}
|
||||
bodyContent={[
|
||||
<Text.Body
|
||||
key="text-body"
|
||||
className="text-body"
|
||||
isBold={false}
|
||||
fontSize={13}
|
||||
>
|
||||
{t("MessageSendPasswordRecoveryInstructionsOnEmail")}
|
||||
</Text.Body>,
|
||||
<TextInput
|
||||
key="e-mail"
|
||||
id="e-mail"
|
||||
name="e-mail"
|
||||
type="text"
|
||||
size="base"
|
||||
scale={true}
|
||||
tabIndex={1}
|
||||
isDisabled={isLoading}
|
||||
value={email}
|
||||
onChange={onChangeEmail}
|
||||
/>
|
||||
]}
|
||||
footerContent={[
|
||||
<Button
|
||||
className="btn-style"
|
||||
key="SendBtn"
|
||||
label={isLoading ? t("LoadingProcessing") : t("SendButton")}
|
||||
size="base"
|
||||
scale={false}
|
||||
primary={true}
|
||||
onClick={onSendPasswordInstructions}
|
||||
isLoading={isLoading}
|
||||
isDisabled={isLoading}
|
||||
tabIndex={2}
|
||||
/>,
|
||||
<Button
|
||||
key="CancelBtn"
|
||||
label={t("CancelButton")}
|
||||
size="base"
|
||||
scale={false}
|
||||
primary={false}
|
||||
onClick={onDialogClose}
|
||||
isDisabled={isLoading}
|
||||
tabIndex={3}
|
||||
/>
|
||||
]}
|
||||
onClose={onDialogClose}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SubModalDialog.propTypes = {
|
||||
openDialog: PropTypes.bool.isRequired,
|
||||
isLoading: PropTypes.bool.isRequired,
|
||||
email: PropTypes.string.isRequired,
|
||||
onChangeEmail: PropTypes.func.isRequired,
|
||||
onSendPasswordInstructions: PropTypes.func.isRequired,
|
||||
onDialogClose: PropTypes.func.isRequired,
|
||||
t: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default SubModalDialog;
|
@ -1,12 +1,11 @@
|
||||
import React from 'react';
|
||||
import { Redirect, Route } from 'react-router-dom';
|
||||
import { AUTH_KEY } from './constants';
|
||||
import Cookies from 'universal-cookie';
|
||||
import { Route } from 'react-router-dom';
|
||||
import { ValidationResult } from './../helpers/constants';
|
||||
import { decomposeConfirmLink } from './../helpers/converters';
|
||||
import { PageLayout, Loader } from "asc-web-components";
|
||||
import { connect } from 'react-redux';
|
||||
import { checkConfirmLink } from './../store/auth/actions';
|
||||
import { ValidationResult } from './../helpers/constants';
|
||||
import decomposeConfirmLink from './../helpers/decomposeConfirmLink';
|
||||
import { PageLayout, Loader } from "asc-web-components";
|
||||
import { withRouter } from "react-router";
|
||||
|
||||
class ConfirmRoute extends React.Component {
|
||||
constructor(props) {
|
||||
@ -20,16 +19,20 @@ class ConfirmRoute extends React.Component {
|
||||
uid: '',
|
||||
firstname: '',
|
||||
lastname: '',
|
||||
isReady: false,
|
||||
isLoaded: false,
|
||||
componentProps: {}
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { pathname, search } = this.props.location;
|
||||
const { checkConfirmLink } = this.props;
|
||||
const decomposedLink = decomposeConfirmLink(pathname, search);
|
||||
const { location, checkConfirmLink, isAuthenticated, history } = this.props;
|
||||
const { search } = location;
|
||||
const decomposedLink = decomposeConfirmLink(location);
|
||||
let validationResult;
|
||||
let path = '';
|
||||
if (!isAuthenticated) {
|
||||
path = '/login';
|
||||
}
|
||||
checkConfirmLink(decomposedLink)
|
||||
.then((res) => {
|
||||
validationResult = res.data.response;
|
||||
@ -38,39 +41,38 @@ class ConfirmRoute extends React.Component {
|
||||
const confirmHeader = `type=${decomposedLink.type}&${search.slice(1)}`;
|
||||
const componentProps = Object.assign({}, decomposedLink, { confirmHeader });
|
||||
this.setState({
|
||||
isReady: true,
|
||||
isLoaded: true,
|
||||
componentProps
|
||||
});
|
||||
break;
|
||||
case ValidationResult.Invalid:
|
||||
window.location.href = '/login/error=Invalid link'
|
||||
history.push(`${path}/error=Invalid link`);
|
||||
break;
|
||||
case ValidationResult.Expired:
|
||||
window.location.href = '/login/error=Expired link'
|
||||
history.push(`${path}/error=Expired link`);
|
||||
break;
|
||||
default:
|
||||
window.location.href = '/login/error=Unknown error'
|
||||
history.push(`${path}/error=Unknown error`);
|
||||
break;
|
||||
}
|
||||
})
|
||||
.catch((e) => window.location.href = '/');
|
||||
.catch((e) => history.push(`${path}/error=${e}`));
|
||||
}
|
||||
|
||||
render() {
|
||||
const { component: Component, location, path, computedMatch, ...rest } = this.props;
|
||||
const newProps = Object.assign({}, { location, path, computedMatch }, { linkData: this.state.componentProps });
|
||||
const { component: Component, ...rest } = this.props;
|
||||
return (
|
||||
<Route
|
||||
{...rest}
|
||||
render={props =>
|
||||
!this.state.isReady ? (
|
||||
!this.state.isLoaded ? (
|
||||
<PageLayout
|
||||
sectionBodyContent={
|
||||
<Loader className="pageLoader" type="rombs" size={40} />
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<Component {...newProps} />
|
||||
<Component {...props = { ...props, linkData: this.state.componentProps }} />
|
||||
)
|
||||
}
|
||||
/>
|
||||
@ -78,4 +80,10 @@ class ConfirmRoute extends React.Component {
|
||||
}
|
||||
};
|
||||
|
||||
export default connect(null, { checkConfirmLink })(ConfirmRoute);
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
isAuthenticated: state.auth.isAuthenticated
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, { checkConfirmLink })(withRouter(ConfirmRoute));
|
||||
|
@ -44,3 +44,12 @@ export const ValidationResult = Object.freeze({
|
||||
Invalid: 1,
|
||||
Expired: 2
|
||||
});
|
||||
|
||||
/**
|
||||
* Enum for employee status.
|
||||
* @readonly
|
||||
*/
|
||||
export const EmployeeStatus = Object.freeze({
|
||||
Active: 1,
|
||||
Disabled: 2
|
||||
});
|
||||
|
25
web/ASC.Web.Client/src/helpers/converters.js
Normal file
25
web/ASC.Web.Client/src/helpers/converters.js
Normal file
@ -0,0 +1,25 @@
|
||||
export function getObjectByLocation(location) {
|
||||
if (!location.search || !location.search.length) return null;
|
||||
|
||||
const searchUrl = location.search.substring(1);
|
||||
const object = JSON.parse(
|
||||
'{"' +
|
||||
decodeURIComponent(searchUrl)
|
||||
.replace(/"/g, '\\"')
|
||||
.replace(/&/g, '","')
|
||||
.replace(/=/g, '":"') +
|
||||
'"}'
|
||||
);
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
export function decomposeConfirmLink(location) {
|
||||
|
||||
const queryParams = getObjectByLocation(location);
|
||||
const url = location.pathname;
|
||||
const posSeparator = url.lastIndexOf('/');
|
||||
const type = url.slice(posSeparator + 1);
|
||||
const data = Object.assign({ type }, queryParams);
|
||||
return data;
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
const decomposeConfirmLink = (url, querySearch) => {
|
||||
const decodedString = decodeURIComponent(querySearch);
|
||||
const queryString = decodedString.slice(1).split('&');
|
||||
const arrayOfQueryString = queryString.map(queryParam => queryParam.split('='));
|
||||
const queryParams = Object.fromEntries(arrayOfQueryString);
|
||||
const posSeparator = url.lastIndexOf('/');
|
||||
const type = url.slice(posSeparator + 1);
|
||||
const data = Object.assign({ type }, queryParams);
|
||||
return data;
|
||||
}
|
||||
|
||||
export default decomposeConfirmLink;
|
@ -22,7 +22,10 @@
|
||||
"RegistrationEmailWatermark",
|
||||
"MessageEmailConfirmed",
|
||||
"MessageAuthorize",
|
||||
"LoginButton"
|
||||
"LoginButton",
|
||||
"ForgotPassword",
|
||||
"PasswordRecoveryTitle",
|
||||
"MessageSendPasswordRecoveryInstructionsOnEmail"
|
||||
]
|
||||
},
|
||||
"Confirm": {
|
||||
@ -41,6 +44,11 @@
|
||||
"ErrorPasswordNoSpecialSymbols",
|
||||
"EmailAndPasswordCopiedToClipboard",
|
||||
"LastName",
|
||||
"DeleteProfileBtn",
|
||||
"DeleteProfileSuccessMessage",
|
||||
"DeleteProfileSuccessMessageInfo",
|
||||
"DeleteProfileConfirmation",
|
||||
"DeleteProfileConfirmationInfo",
|
||||
"ChangePasswordSuccess"
|
||||
]
|
||||
}
|
||||
|
@ -84,3 +84,23 @@ export function checkConfirmLink(data) {
|
||||
? fakeApi.checkConfirmLink()
|
||||
: axios.post(`${API_URL}/authentication/confirm.json`, data);
|
||||
}
|
||||
|
||||
export function deleteUser(userId) {
|
||||
return IS_FAKE
|
||||
? fakeApi.deleteUser(userId)
|
||||
: axios.delete(`${API_URL}/people/${userId}.json`);
|
||||
}
|
||||
|
||||
export function updateUserStatus(status, userIds, key) {
|
||||
return IS_FAKE
|
||||
? fakeApi.updateUserStatus(status, userIds)
|
||||
: axios.put(`${API_URL}/people/status/${status}`, { userIds }, {
|
||||
headers: { confirm: key }
|
||||
});
|
||||
}
|
||||
|
||||
export function sendInstructionsToChangePassword(email) {
|
||||
return IS_FAKE
|
||||
? fakeApi.sendInstructionsToChangePassword()
|
||||
: axios.post(`${API_URL}/people/password.json`, { email });
|
||||
}
|
@ -160,3 +160,15 @@ export function updateUser(data) {
|
||||
export function checkConfirmLink(data) {
|
||||
return fakeResponse(data);
|
||||
}
|
||||
|
||||
export function deleteUser(data) {
|
||||
return fakeResponse(data);
|
||||
}
|
||||
|
||||
export function updateUserStatus(data) {
|
||||
return fakeResponse(data);
|
||||
}
|
||||
|
||||
export function sendInstructionsToChangePassword() {
|
||||
return fakeResponse("Instruction has been sent successfully");
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "asc-web-components",
|
||||
"version": "1.0.114",
|
||||
"version": "1.0.116",
|
||||
"description": "Ascensio System SIA component library",
|
||||
"license": "AGPL-3.0",
|
||||
"main": "dist/asc-web-components.js",
|
||||
|
@ -1,15 +1,21 @@
|
||||
import React from 'react';
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import { withKnobs, boolean, color, select, date } from '@storybook/addon-knobs/react';
|
||||
import withReadme from 'storybook-readme/with-readme';
|
||||
import Readme from './README.md';
|
||||
import DatePicker from '.';
|
||||
import Section from '../../../.storybook/decorators/section';
|
||||
import React from "react";
|
||||
import { storiesOf } from "@storybook/react";
|
||||
import { action } from "@storybook/addon-actions";
|
||||
import {
|
||||
withKnobs,
|
||||
boolean,
|
||||
color,
|
||||
select,
|
||||
date
|
||||
} from "@storybook/addon-knobs/react";
|
||||
import withReadme from "storybook-readme/with-readme";
|
||||
import Readme from "./README.md";
|
||||
import DatePicker from ".";
|
||||
import Section from "../../../.storybook/decorators/section";
|
||||
|
||||
function myDateKnob(name, defaultValue) {
|
||||
const stringTimestamp = date(name, defaultValue)
|
||||
return new Date(stringTimestamp)
|
||||
const stringTimestamp = date(name, defaultValue);
|
||||
return new Date(stringTimestamp);
|
||||
}
|
||||
|
||||
const locales = [
|
||||
@ -40,25 +46,32 @@ const locales = [
|
||||
"vi"
|
||||
];
|
||||
|
||||
storiesOf('Components|DatePicker', module)
|
||||
const displayType = ["dropdown", "aside"];
|
||||
|
||||
storiesOf("Components|DatePicker", module)
|
||||
.addDecorator(withKnobs)
|
||||
.addDecorator(withReadme(Readme))
|
||||
.add('base', () => (
|
||||
.add("base", () => (
|
||||
<Section>
|
||||
<DatePicker
|
||||
onChange={date => {
|
||||
action('Selected date')(date);
|
||||
action("Selected date")(date);
|
||||
}}
|
||||
selectedDate={myDateKnob('selectedDate', new Date())}
|
||||
minDate={myDateKnob('minDate', new Date("1970/01/01"))}
|
||||
maxDate={myDateKnob('maxDate', new Date(new Date().getFullYear() + 1 + "/01/01"))}
|
||||
selectedDate={myDateKnob("selectedDate", new Date())}
|
||||
minDate={myDateKnob("minDate", new Date("1970/01/01"))}
|
||||
maxDate={myDateKnob(
|
||||
"maxDate",
|
||||
new Date(new Date().getFullYear() + 1 + "/01/01")
|
||||
)}
|
||||
isDisabled={boolean("isDisabled", false)}
|
||||
isReadOnly={boolean("isReadOnly", false)}
|
||||
hasError={boolean("hasError", false)}
|
||||
//hasWarning={boolean("hasWarning", false)}
|
||||
isOpen={boolean('isOpen', false)}
|
||||
themeColor={color('themeColor', '#ED7309')}
|
||||
locale={select('locale', locales, "en")}
|
||||
isOpen={boolean("isOpen", false)}
|
||||
themeColor={color("themeColor", "#ED7309")}
|
||||
locale={select("locale", locales, "en")}
|
||||
displayType={select("displayType", displayType, "dropdown")}
|
||||
calendarSize={select("calendarSize", ["base", "big"], "base")}
|
||||
/>
|
||||
</Section>
|
||||
));
|
||||
|
@ -7,6 +7,7 @@ import Calendar from "../calendar";
|
||||
import moment from "moment";
|
||||
import { handleAnyClick } from "../../utils/event";
|
||||
import isEmpty from "lodash/isEmpty";
|
||||
import Aside from "../layout/sub-components/aside";
|
||||
|
||||
const DateInputStyle = styled.div`
|
||||
max-width: 110px;
|
||||
@ -232,18 +233,35 @@ class DatePicker extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
renderBody = () => {
|
||||
const {
|
||||
isDisabled,
|
||||
isReadOnly,
|
||||
//hasWarning,
|
||||
minDate,
|
||||
maxDate,
|
||||
locale,
|
||||
themeColor
|
||||
themeColor,
|
||||
calendarSize
|
||||
} = this.props;
|
||||
const { selectedDate } = this.state;
|
||||
|
||||
const { value, isOpen, mask, selectedDate, hasError } = this.state;
|
||||
return (
|
||||
<Calendar
|
||||
locale={locale}
|
||||
themeColor={themeColor}
|
||||
minDate={minDate}
|
||||
maxDate={maxDate}
|
||||
isDisabled={isDisabled}
|
||||
openToDate={selectedDate}
|
||||
selectedDate={selectedDate}
|
||||
onChange={this.onChange}
|
||||
size={calendarSize}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { isDisabled, isReadOnly, displayType } = this.props;
|
||||
const { value, isOpen, mask, hasError } = this.state;
|
||||
|
||||
return (
|
||||
<DateInputStyle ref={this.ref}>
|
||||
@ -253,7 +271,6 @@ class DatePicker extends Component {
|
||||
isReadOnly={isReadOnly}
|
||||
hasError={hasError}
|
||||
onFocus={this.onClick.bind(this, true)}
|
||||
//hasWarning={hasWarning}
|
||||
iconName={"CalendarIcon"}
|
||||
onIconClick={this.onClick.bind(this, !isOpen)}
|
||||
value={value}
|
||||
@ -264,22 +281,15 @@ class DatePicker extends Component {
|
||||
//showMask={true}
|
||||
/>
|
||||
{isOpen ? (
|
||||
displayType === "dropdown" ? (
|
||||
<DropDownStyle>
|
||||
<DropDown opened={isOpen}>
|
||||
{
|
||||
<Calendar
|
||||
locale={locale}
|
||||
themeColor={themeColor}
|
||||
minDate={minDate}
|
||||
maxDate={maxDate}
|
||||
isDisabled={isDisabled}
|
||||
openToDate={selectedDate}
|
||||
selectedDate={selectedDate}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
}
|
||||
</DropDown>
|
||||
<DropDown opened={isOpen}>{this.renderBody()}</DropDown>
|
||||
</DropDownStyle>
|
||||
) : (
|
||||
<Aside visible={isOpen} scale={false}>
|
||||
{this.renderBody()}
|
||||
</Aside>
|
||||
)
|
||||
) : null}
|
||||
</DateInputStyle>
|
||||
);
|
||||
@ -298,13 +308,16 @@ DatePicker.propTypes = {
|
||||
isReadOnly: PropTypes.bool,
|
||||
hasError: PropTypes.bool,
|
||||
hasWarning: PropTypes.bool,
|
||||
isOpen: PropTypes.bool
|
||||
isOpen: PropTypes.bool,
|
||||
displayType: PropTypes.oneOf(["dropdown", "aside"]),
|
||||
calendarSize: PropTypes.oneOf(["base", "big"])
|
||||
};
|
||||
|
||||
DatePicker.defaultProps = {
|
||||
minDate: new Date("1970/01/01"),
|
||||
maxDate: new Date(new Date().getFullYear() + 1, 1, 1),
|
||||
selectedDate: moment(new Date()).toDate()
|
||||
selectedDate: moment(new Date()).toDate(),
|
||||
displayType: "dropdown"
|
||||
};
|
||||
|
||||
export default DatePicker;
|
||||
|
@ -447,7 +447,7 @@ namespace ASC.Web.Studio.Core.Notify
|
||||
|
||||
public void SendMsgProfileDeletion(int tenantId, UserInfo user)
|
||||
{
|
||||
var confirmationUrl = CommonLinkUtility.GetConfirmationUrl(tenantId, user.Email, ConfirmType.ProfileRemove);
|
||||
var confirmationUrl = CommonLinkUtility.GetConfirmationUrl(tenantId, user.Email, ConfirmType.ProfileRemove, null, SecurityContext.CurrentAccount.ID);
|
||||
|
||||
static string greenButtonText() => CoreContext.Configuration.Personal ? WebstudioNotifyPatternResource.ButtonConfirmTermination : WebstudioNotifyPatternResource.ButtonRemoveProfile;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user