Merge branch 'master' into feature/advanced-selector-v2
# Conflicts: # web/ASC.Web.Components/src/components/help-button/index.js
This commit is contained in:
commit
d44f0ea5f0
@ -2,14 +2,13 @@ import React, { Suspense } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { Router, Switch, Redirect } from "react-router-dom";
|
||||
import { Loader } from "asc-web-components";
|
||||
import PeopleLayout from "./components/Layout/index";
|
||||
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 } from "asc-web-common";
|
||||
import { history, PrivateRoute, PublicRoute, Login, Error404, StudioLayout } from "asc-web-common";
|
||||
|
||||
/*const Profile = lazy(() => import("./components/pages/Profile"));
|
||||
const ProfileAction = lazy(() => import("./components/pages/ProfileAction"));
|
||||
@ -19,7 +18,7 @@ const App = ({ settings }) => {
|
||||
const { homepage } = settings;
|
||||
return (
|
||||
<Router history={history}>
|
||||
<PeopleLayout>
|
||||
<StudioLayout>
|
||||
<Suspense
|
||||
fallback={<Loader className="pageLoader" type="rombs" size={40} />}
|
||||
>
|
||||
@ -65,7 +64,7 @@ const App = ({ settings }) => {
|
||||
<PrivateRoute component={Error404} />
|
||||
</Switch>
|
||||
</Suspense>
|
||||
</PeopleLayout>
|
||||
</StudioLayout>
|
||||
</Router>
|
||||
);
|
||||
};
|
||||
|
@ -1,61 +0,0 @@
|
||||
import i18n from "i18next";
|
||||
import Backend from "i18next-xhr-backend";
|
||||
import config from "../../../package.json";
|
||||
|
||||
const newInstance = i18n.createInstance();
|
||||
|
||||
if (process.env.NODE_ENV === "production") {
|
||||
newInstance
|
||||
.use(Backend)
|
||||
.init({
|
||||
lng: '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
|
||||
},
|
||||
backend: {
|
||||
loadPath: `${config.homepage}/locales/Layout/{{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: '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;
|
@ -1,126 +0,0 @@
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import { withRouter } from "react-router";
|
||||
import { Layout, Toast } from 'asc-web-components';
|
||||
import { withTranslation, I18nextProvider } from 'react-i18next';
|
||||
import i18n from "./i18n";
|
||||
import { store } from 'asc-web-common';
|
||||
const { logout } = store.auth.actions;
|
||||
|
||||
class PurePeopleLayout extends React.Component {
|
||||
shouldComponentUpdate(nextProps) {
|
||||
if (this.props.hasChanges !== nextProps.hasChanges) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
onProfileClick = () => {
|
||||
console.log('ProfileBtn');
|
||||
const { history, settings } = this.props;
|
||||
history.push(`${settings.homepage}/view/@self`);
|
||||
}
|
||||
|
||||
onAboutClick = () => {
|
||||
window.location.href = "/about";
|
||||
}
|
||||
|
||||
onLogoutClick = () => {
|
||||
this.props.logout();
|
||||
}
|
||||
|
||||
onLogoClick = () => window.open("/", '_self');
|
||||
|
||||
render() {
|
||||
const { hasChanges, children, t } = this.props;
|
||||
|
||||
const currentUserActions = [
|
||||
{
|
||||
key: 'ProfileBtn', label: t('Profile'), onClick: this.onProfileClick
|
||||
},
|
||||
{
|
||||
key: 'AboutBtn', label: t('AboutCompanyTitle'), onClick: this.onAboutClick
|
||||
},
|
||||
{
|
||||
key: 'LogoutBtn', label: t('LogoutButton'), onClick: this.onLogoutClick
|
||||
},
|
||||
];
|
||||
|
||||
const newProps = hasChanges
|
||||
? {
|
||||
currentUserActions: currentUserActions,
|
||||
onLogoClick: this.onLogoClick,
|
||||
...this.props
|
||||
}
|
||||
: {};
|
||||
|
||||
console.log("PeopleLayout render", newProps);
|
||||
return (
|
||||
<>
|
||||
<Toast />
|
||||
<Layout key="1" {...newProps}>{children}</Layout>
|
||||
</>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const getAvailableModules = (modules, currentUser) => {
|
||||
const isUserAdmin = currentUser.isAdmin;
|
||||
const customModules = isUserAdmin ? [
|
||||
{
|
||||
separator: true,
|
||||
id: "nav-separator-2"
|
||||
},
|
||||
{
|
||||
id: 'settings',
|
||||
title: 'Settings',
|
||||
iconName: "SettingsIcon",
|
||||
notifications: 0,
|
||||
url: '/settings',
|
||||
onClick: () => window.open('/settings', "_self"),
|
||||
onBadgeClick: e => console.log("SettingsIconBadge Clicked", e)
|
||||
}] : [];
|
||||
|
||||
const separator = { separator: true, id: 'nav-separator-1' };
|
||||
const products = modules.map(product => {
|
||||
return {
|
||||
id: product.id,
|
||||
title: product.title,
|
||||
iconName: 'PeopleIcon',
|
||||
notifications: 0,
|
||||
url: product.link,
|
||||
onClick: () => window.open(product.link, '_self'),
|
||||
onBadgeClick: e => console.log('PeopleIconBadge Clicked', e)
|
||||
};
|
||||
}) || [];
|
||||
|
||||
return products.length ? [separator, ...products, ...customModules] : products;
|
||||
};
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
hasChanges: state.auth.isAuthenticated && state.auth.isLoaded,
|
||||
availableModules: getAvailableModules(state.auth.modules, state.auth.user),
|
||||
currentUser: state.auth.user,
|
||||
currentModuleId: state.auth.settings.currentProductId,
|
||||
settings: state.auth.settings,
|
||||
language: state.auth.user.cultureName || state.auth.settings.culture,
|
||||
};
|
||||
}
|
||||
|
||||
const PeopleLayoutContainer = withTranslation()(PurePeopleLayout);
|
||||
|
||||
const PeopleLayout = (props) => {
|
||||
const { language } = props;
|
||||
i18n.changeLanguage(language);
|
||||
return (<I18nextProvider i18n={i18n}><PeopleLayoutContainer {...props} /></I18nextProvider>);
|
||||
};
|
||||
|
||||
PeopleLayout.propTypes = {
|
||||
logout: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, { logout })(withRouter((PeopleLayout)));
|
@ -1,8 +1,7 @@
|
||||
import React, { Suspense, lazy } from "react";
|
||||
import { Router, Route, Switch } from "react-router-dom";
|
||||
import { Loader } from "asc-web-components";
|
||||
import StudioLayout from "./components/Layout/index";
|
||||
import { history, PrivateRoute, PublicRoute, Login, Error404 } from "asc-web-common";
|
||||
import { history, PrivateRoute, PublicRoute, Login, Error404, StudioLayout} from "asc-web-common";
|
||||
|
||||
const Home = lazy(() => import("./components/pages/Home"));
|
||||
const About = lazy(() => import("./components/pages/About"));
|
||||
|
@ -1,60 +0,0 @@
|
||||
import i18n from "i18next";
|
||||
import Backend from "i18next-xhr-backend";
|
||||
|
||||
const newInstance = i18n.createInstance();
|
||||
|
||||
if (process.env.NODE_ENV === "production") {
|
||||
newInstance
|
||||
.use(Backend)
|
||||
.init({
|
||||
lng: 'en',
|
||||
fallbackLng: "en",
|
||||
debug: false,
|
||||
|
||||
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
|
||||
},
|
||||
backend: {
|
||||
loadPath: `/locales/Layout/{{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: '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;
|
@ -1,124 +0,0 @@
|
||||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import PropTypes from "prop-types";
|
||||
import { withRouter } from "react-router";
|
||||
import { Layout, Toast } from "asc-web-components";
|
||||
import { withTranslation, I18nextProvider } from 'react-i18next';
|
||||
import i18n from "./i18n";
|
||||
import isEqual from "lodash/isEqual";
|
||||
import { store } from 'asc-web-common';
|
||||
const { logout } = store.auth.actions;
|
||||
|
||||
class PureStudioLayout extends React.Component {
|
||||
shouldComponentUpdate(nextProps, nextState) {
|
||||
return !isEqual(this.props, nextProps) || !isEqual(this.state, nextState);
|
||||
}
|
||||
|
||||
onProfileClick = () => {
|
||||
window.location.href = "/products/people/view/@self";
|
||||
}
|
||||
|
||||
onAboutClick = () => {
|
||||
this.props.history.push("/about");
|
||||
}
|
||||
|
||||
onLogoutClick = () => {
|
||||
this.props.logout();
|
||||
this.props.history.push("/");
|
||||
}
|
||||
|
||||
onLogoClick = () => this.props.history.push("/");
|
||||
|
||||
render() {
|
||||
const { hasChanges, children, t } = this.props;
|
||||
|
||||
const currentUserActions = [
|
||||
{
|
||||
key: 'ProfileBtn', label: t("Profile"), onClick: this.onProfileClick
|
||||
},
|
||||
{
|
||||
key: 'AboutBtn', label: t("AboutCompanyTitle"), onClick: this.onAboutClick
|
||||
},
|
||||
{
|
||||
key: 'LogoutBtn', label: t("LogoutButton"), onClick: this.onLogoutClick
|
||||
},
|
||||
];
|
||||
|
||||
const newProps = hasChanges
|
||||
? {
|
||||
currentUserActions: currentUserActions,
|
||||
onLogoClick: this.onLogoClick,
|
||||
...this.props
|
||||
}
|
||||
: {};
|
||||
|
||||
console.log("StudioLayout render", newProps);
|
||||
return (
|
||||
<>
|
||||
<Toast />
|
||||
<Layout key="1" {...newProps}>{children}</Layout>
|
||||
</>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const getAvailableModules = (modules, currentUser) => {
|
||||
const isUserAdmin = currentUser.isAdmin;
|
||||
const separator = { separator: true, id: "nav-separator-1" };
|
||||
const customModules = isUserAdmin ? [
|
||||
{
|
||||
separator: true,
|
||||
id: "nav-separator-2"
|
||||
},
|
||||
{
|
||||
id: 'settings',
|
||||
title: 'Settings',
|
||||
iconName: "SettingsIcon",
|
||||
notifications: 0,
|
||||
url: '/settings',
|
||||
onClick: () => window.open('/settings', "_self"),
|
||||
onBadgeClick: e => console.log("SettingsIconBadge Clicked", e)
|
||||
}] : [];
|
||||
const products =
|
||||
modules.map(product => {
|
||||
return {
|
||||
id: product.id,
|
||||
title: product.title,
|
||||
iconName: "PeopleIcon",
|
||||
notifications: 0,
|
||||
url: product.link,
|
||||
onClick: () => window.open(product.link, "_self"),
|
||||
onBadgeClick: e => console.log("PeopleIconBadge Clicked", e)
|
||||
};
|
||||
}) || [];
|
||||
|
||||
return products.length ? [separator, ...products, ...customModules] : products;
|
||||
};
|
||||
|
||||
function mapStateToProps(state) {
|
||||
let availableModules = getAvailableModules(state.auth.modules, state.auth.user);
|
||||
return {
|
||||
hasChanges: state.auth.isAuthenticated && state.auth.isLoaded,
|
||||
availableModules: availableModules,
|
||||
currentUser: state.auth.user,
|
||||
currentModuleId: state.auth.settings.currentProductId,
|
||||
language: state.auth.user.cultureName || state.auth.settings.culture,
|
||||
};
|
||||
};
|
||||
const StudioLayoutContainer = withTranslation()(PureStudioLayout);
|
||||
|
||||
const StudioLayout = (props) => {
|
||||
const { language } = props;
|
||||
i18n.changeLanguage(language);
|
||||
return (<I18nextProvider i18n={i18n}><StudioLayoutContainer {...props} /></I18nextProvider>);
|
||||
};
|
||||
|
||||
StudioLayout.propTypes = {
|
||||
logout: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
{ logout }
|
||||
)(withRouter(StudioLayout));
|
@ -1,5 +0,0 @@
|
||||
{
|
||||
"Profile": "Profile",
|
||||
"AboutCompanyTitle": "About this program",
|
||||
"LogoutButton": "Sign Out"
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
{
|
||||
"Profile": "Профиль",
|
||||
"AboutCompanyTitle": "О программе",
|
||||
"LogoutButton": "Выйти"
|
||||
}
|
@ -3,7 +3,6 @@ import { withRouter } from "react-router";
|
||||
import { withTranslation } from 'react-i18next';
|
||||
import { Button, TextInput, PageLayout, Text, PasswordInput, toastr, Loader } from 'asc-web-components';
|
||||
import styled from 'styled-components';
|
||||
import { Collapse } from 'reactstrap';
|
||||
import { connect } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import { store, constants } from 'asc-web-common';
|
||||
@ -298,10 +297,9 @@ class Confirm extends React.PureComponent {
|
||||
|
||||
</Row>
|
||||
*/}
|
||||
<Collapse className='confirm-row'
|
||||
isOpen={!!this.state.errorText}>
|
||||
<div className="alert alert-danger">{this.state.errorText}</div>
|
||||
</Collapse>
|
||||
<Text.Body className="confirm-row" fontSize={14} color="#c30">
|
||||
{this.state.errorText}
|
||||
</Text.Body>
|
||||
</div>
|
||||
</ConfirmContainer>
|
||||
)
|
||||
|
@ -4,44 +4,44 @@ import { withTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import PropTypes from "prop-types";
|
||||
import styled from "styled-components";
|
||||
import { Container, Row, Col, Card, CardTitle, CardImg } from "reactstrap";
|
||||
import { Button, PageLayout, Text, toastr } from "asc-web-components";
|
||||
//import { } from "../../../../../src/store/auth/actions";
|
||||
|
||||
const BodyStyle = styled(Container)`
|
||||
const BodyStyle = styled.div`
|
||||
margin-top: 70px;
|
||||
|
||||
.buttons-style {
|
||||
margin-top: 20px;
|
||||
min-width: 110px;
|
||||
}
|
||||
.button-style {
|
||||
margin-right: 8px;
|
||||
}
|
||||
.confirm_text {
|
||||
margin: 12px 0;
|
||||
}
|
||||
.owner-container {
|
||||
display: grid;
|
||||
|
||||
.password-card {
|
||||
border: none;
|
||||
.card-img {
|
||||
max-width: 216px;
|
||||
max-height: 35px;
|
||||
}
|
||||
.card-title {
|
||||
word-wrap: break-word;
|
||||
margin: 8px 0;
|
||||
text-align: left;
|
||||
font-size: 24px;
|
||||
color: #116d9d;
|
||||
}
|
||||
}
|
||||
.owner-wrapper {
|
||||
align-self: center;
|
||||
justify-self: center;
|
||||
.owner-img {
|
||||
max-width: 216px;
|
||||
max-height: 35px;
|
||||
}
|
||||
.owner-title {
|
||||
word-wrap: break-word;
|
||||
margin: 8px 0;
|
||||
text-align: left;
|
||||
font-size: 24px;
|
||||
color: #116d9d;
|
||||
}
|
||||
.owner-confirm_text {
|
||||
margin: 20px 0 12px 0;
|
||||
}
|
||||
.owner-buttons {
|
||||
margin-top: 20px;
|
||||
min-width: 110px;
|
||||
}
|
||||
.owner-button {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.row_display {
|
||||
display: flex;
|
||||
}
|
||||
.confirm-text {
|
||||
margin-top: 32px;
|
||||
.owner-confirm-message {
|
||||
margin-top: 32px;
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@ -68,61 +68,47 @@ class Form extends React.PureComponent {
|
||||
|
||||
render() {
|
||||
const { t, greetingTitle } = this.props;
|
||||
const mdOptions = { size: 6, offset: 2 };
|
||||
|
||||
return (
|
||||
<BodyStyle>
|
||||
<Row className="password-row">
|
||||
<Col sm="12" md={mdOptions}>
|
||||
<Card className="password-card">
|
||||
<CardImg
|
||||
className="card-img"
|
||||
src="images/dark_general.png"
|
||||
alt="Logo"
|
||||
top
|
||||
/>
|
||||
<CardTitle className="card-title">{greetingTitle}</CardTitle>
|
||||
</Card>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col sm="12" md={{ size: 12, offset: 2 }}>
|
||||
<Text.Body className="confirm_text" fontSize={18}>
|
||||
<div className="owner-container">
|
||||
<div className="owner-wrapper">
|
||||
<img
|
||||
className="owner-img"
|
||||
src="images/dark_general.png"
|
||||
alt="Logo"
|
||||
/>
|
||||
<Text.Body className="owner-title">{greetingTitle}</Text.Body>
|
||||
<Text.Body className="owner-confirm_text" fontSize={18}>
|
||||
{t("ConfirmOwnerPortalTitle", { newOwner: "NEW OWNER" })}
|
||||
</Text.Body>
|
||||
</Col>
|
||||
</Row>
|
||||
{this.state.showButtons ? (
|
||||
<Row>
|
||||
<Col className="row_display" sm="12" md={mdOptions}>
|
||||
<Button
|
||||
className="button-style buttons-style"
|
||||
primary
|
||||
size="big"
|
||||
label={t("SaveButton")}
|
||||
tabIndex={2}
|
||||
isDisabled={false}
|
||||
onClick={this.onAcceptClick}
|
||||
/>
|
||||
<Button
|
||||
className="buttons-style"
|
||||
size="big"
|
||||
label={t("CancelButton")}
|
||||
tabIndex={2}
|
||||
isDisabled={false}
|
||||
onClick={this.onCancelClick}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
) : (
|
||||
<Row>
|
||||
<Col sm="12" md={{ size: 12, offset: 2 }}>
|
||||
<Text.Body className="confirm-text" fontSize={12}>
|
||||
{this.state.showButtons ? (
|
||||
<>
|
||||
<Button
|
||||
className="owner-button owner-buttons"
|
||||
primary
|
||||
size="big"
|
||||
label={t("SaveButton")}
|
||||
tabIndex={2}
|
||||
isDisabled={false}
|
||||
onClick={this.onAcceptClick}
|
||||
/>
|
||||
<Button
|
||||
className="owner-buttons"
|
||||
size="big"
|
||||
label={t("CancelButton")}
|
||||
tabIndex={2}
|
||||
isDisabled={false}
|
||||
onClick={this.onCancelClick}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<Text.Body className="owner-confirm-message" fontSize={12}>
|
||||
{t("ConfirmOwnerPortalSuccessMessage")}
|
||||
</Text.Body>
|
||||
</Col>
|
||||
</Row>
|
||||
)}
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</BodyStyle>
|
||||
);
|
||||
}
|
||||
|
@ -4,7 +4,6 @@ import { withTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import PropTypes from "prop-types";
|
||||
import styled from "styled-components";
|
||||
import { Container, Row, Col, Card, CardTitle, CardImg } from "reactstrap";
|
||||
import {
|
||||
Button,
|
||||
PageLayout,
|
||||
@ -13,34 +12,32 @@ import {
|
||||
Loader,
|
||||
toastr
|
||||
} from "asc-web-components";
|
||||
import { store } from 'asc-web-common';
|
||||
const { changePassword, getConfirmationInfo, logout } = store.auth.actions;
|
||||
import { store } from "asc-web-common";
|
||||
const { changePassword, getConfirmationInfo, logout } = store.auth.actions;
|
||||
|
||||
const BodyStyle = styled(Container)`
|
||||
margin-top: 70px;
|
||||
p {
|
||||
const BodyStyle = styled.form`
|
||||
margin: 70px auto 0 auto;
|
||||
max-width: 500px;
|
||||
|
||||
.password-header {
|
||||
margin-bottom: 24px;
|
||||
|
||||
.password-logo {
|
||||
max-width: 216px;
|
||||
max-height: 35px;
|
||||
}
|
||||
|
||||
.password-title {
|
||||
margin: 8px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.password-text {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.button-style {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.password-row {
|
||||
margin: 23px 0 0;
|
||||
.password-card {
|
||||
border: none;
|
||||
.card-img {
|
||||
max-width: 216px;
|
||||
max-height: 35px;
|
||||
}
|
||||
.card-title {
|
||||
word-wrap: break-word;
|
||||
margin: 8px 0;
|
||||
text-align: left;
|
||||
font-size: 24px;
|
||||
color: #116d9d;
|
||||
}
|
||||
}
|
||||
.password-button {
|
||||
margin-top: 20px;
|
||||
}
|
||||
`;
|
||||
|
||||
@ -106,8 +103,7 @@ class Form extends React.PureComponent {
|
||||
|
||||
componentDidMount() {
|
||||
const { getConfirmationInfo, history } = this.props;
|
||||
getConfirmationInfo(this.state.key)
|
||||
.catch(error => {
|
||||
getConfirmationInfo(this.state.key).catch(error => {
|
||||
toastr.error(this.props.t(`${error}`));
|
||||
history.push("/");
|
||||
});
|
||||
@ -126,69 +122,65 @@ class Form extends React.PureComponent {
|
||||
render() {
|
||||
const { settings, isConfirmLoaded, t, greetingTitle } = this.props;
|
||||
const { isLoading, password, passwordEmpty } = this.state;
|
||||
const mdOptions = { size: 6, offset: 3 };
|
||||
|
||||
return !isConfirmLoaded ? (
|
||||
<Loader className="pageLoader" type="rombs" size={40} />
|
||||
) : (
|
||||
<BodyStyle>
|
||||
<Row className="password-row">
|
||||
<Col sm="12" md={mdOptions}>
|
||||
<Card className="password-card">
|
||||
<CardImg
|
||||
className="card-img"
|
||||
src="images/dark_general.png"
|
||||
alt="Logo"
|
||||
top
|
||||
/>
|
||||
<CardTitle className="card-title">
|
||||
{greetingTitle}
|
||||
</CardTitle>
|
||||
</Card>
|
||||
<Text.Body fontSize={14}>{t("PassworResetTitle")}</Text.Body>
|
||||
|
||||
<PasswordInput
|
||||
id="password"
|
||||
name="password"
|
||||
inputName="password"
|
||||
inputValue={password}
|
||||
size="huge"
|
||||
scale={true}
|
||||
type="password"
|
||||
isDisabled={isLoading}
|
||||
hasError={passwordEmpty}
|
||||
onValidateInput={this.validatePassword}
|
||||
generatorSpecial="!@#$%^&*"
|
||||
tabIndex={1}
|
||||
value={password}
|
||||
onChange={this.onChange}
|
||||
emailInputName="E-mail"
|
||||
passwordSettings={settings}
|
||||
tooltipPasswordTitle="Password must contain:"
|
||||
tooltipPasswordLength={`${t("ErrorPasswordLength", {
|
||||
fromNumber: 6,
|
||||
toNumber: 30
|
||||
})}:`}
|
||||
placeholder={t("PasswordCustomMode")}
|
||||
maxLength={30}
|
||||
onKeyDown={this.onKeyPress}
|
||||
isAutoFocussed={true}
|
||||
inputWidth="490px"
|
||||
/>
|
||||
<Button
|
||||
className="button-style"
|
||||
primary
|
||||
size="big"
|
||||
tabIndex={2}
|
||||
label={
|
||||
isLoading ? t("LoadingProcessing") : t("ImportContactsOkButton")
|
||||
}
|
||||
isDisabled={isLoading}
|
||||
isLoading={isLoading}
|
||||
onClick={this.onSubmit}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<div className="password-header">
|
||||
<img
|
||||
className="password-logo"
|
||||
src="images/dark_general.png"
|
||||
alt="Logo"
|
||||
/>
|
||||
<Text.Headline className="password-title" color="#116d9d">
|
||||
{greetingTitle}
|
||||
</Text.Headline>
|
||||
</div>
|
||||
<Text.Body className="password-text" fontSize={14}>
|
||||
{t("PassworResetTitle")}
|
||||
</Text.Body>
|
||||
<PasswordInput
|
||||
id="password"
|
||||
name="password"
|
||||
inputName="password"
|
||||
inputValue={password}
|
||||
size="huge"
|
||||
scale={true}
|
||||
type="password"
|
||||
isDisabled={isLoading}
|
||||
hasError={passwordEmpty}
|
||||
onValidateInput={this.validatePassword}
|
||||
generatorSpecial="!@#$%^&*"
|
||||
tabIndex={1}
|
||||
value={password}
|
||||
onChange={this.onChange}
|
||||
emailInputName="E-mail"
|
||||
passwordSettings={settings}
|
||||
tooltipPasswordTitle="Password must contain:"
|
||||
tooltipPasswordLength={`${t("ErrorPasswordLength", {
|
||||
fromNumber: 6,
|
||||
toNumber: 30
|
||||
})}:`}
|
||||
placeholder={t("PasswordCustomMode")}
|
||||
maxLength={30}
|
||||
onKeyDown={this.onKeyPress}
|
||||
isAutoFocussed={true}
|
||||
inputWidth="490px"
|
||||
/>
|
||||
<Button
|
||||
id="button"
|
||||
className="password-button"
|
||||
primary
|
||||
size="big"
|
||||
tabIndex={2}
|
||||
label={
|
||||
isLoading ? t("LoadingProcessing") : t("ImportContactsOkButton")
|
||||
}
|
||||
isDisabled={isLoading}
|
||||
isLoading={isLoading}
|
||||
onClick={this.onSubmit}
|
||||
/>
|
||||
</BodyStyle>
|
||||
);
|
||||
}
|
||||
@ -215,11 +207,12 @@ function mapStateToProps(state) {
|
||||
isConfirmLoaded: state.auth.isConfirmLoaded,
|
||||
settings: state.auth.settings.passwordSettings,
|
||||
isAuthenticated: state.auth.isAuthenticated,
|
||||
greetingTitle: state.auth.settings.greetingSettings,
|
||||
greetingTitle: state.auth.settings.greetingSettings
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
{ changePassword, getConfirmationInfo, logout }
|
||||
)(withRouter(withTranslation()(ChangePasswordForm)));
|
||||
export default connect(mapStateToProps, {
|
||||
changePassword,
|
||||
getConfirmationInfo,
|
||||
logout
|
||||
})(withRouter(withTranslation()(ChangePasswordForm)));
|
||||
|
@ -3,7 +3,6 @@ import { withRouter } from "react-router";
|
||||
import { withTranslation } from 'react-i18next';
|
||||
import { Button, TextInput, PageLayout, Text, PasswordInput, toastr, Loader } from 'asc-web-components';
|
||||
import styled from 'styled-components';
|
||||
import { Collapse } from 'reactstrap';
|
||||
import { connect } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import { store } from 'asc-web-common';
|
||||
@ -318,10 +317,9 @@ class Confirm extends React.PureComponent {
|
||||
|
||||
</Row>
|
||||
*/}
|
||||
<Collapse className='confirm-row'
|
||||
isOpen={!!this.state.errorText}>
|
||||
<div className="alert alert-danger">{this.state.errorText}</div>
|
||||
</Collapse>
|
||||
<Text.Body className='confirm-row' fontSize={14} color="#c30">
|
||||
{this.state.errorText}
|
||||
</Text.Body>
|
||||
</div>
|
||||
</ConfirmContainer>
|
||||
)
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React, { Suspense, useEffect } from "react";
|
||||
import React, { useEffect } from "react";
|
||||
import { connect } from 'react-redux';
|
||||
import { Loader, PageLayout } from "asc-web-components";
|
||||
import { PageLayout } from "asc-web-components";
|
||||
import i18n from "../i18n";
|
||||
import { I18nextProvider } from "react-i18next";
|
||||
import {
|
||||
@ -20,18 +20,13 @@ const Layout = ({ currentProductId, setCurrentProductId, language, children }) =
|
||||
|
||||
return (
|
||||
<I18nextProvider i18n={i18n}>
|
||||
<Suspense
|
||||
fallback={<Loader className="pageLoader" type="rombs" size={40} />}
|
||||
>
|
||||
<PageLayout
|
||||
withBodyScroll={true}
|
||||
articleHeaderContent={<ArticleHeaderContent />}
|
||||
articleBodyContent={<ArticleBodyContent />}
|
||||
sectionHeaderContent={<SectionHeaderContent />}
|
||||
sectionBodyContent={children}
|
||||
/>
|
||||
|
||||
</Suspense>
|
||||
<PageLayout
|
||||
withBodyScroll={true}
|
||||
articleHeaderContent={<ArticleHeaderContent />}
|
||||
articleBodyContent={<ArticleBodyContent />}
|
||||
sectionHeaderContent={<SectionHeaderContent />}
|
||||
sectionBodyContent={children}
|
||||
/>
|
||||
</I18nextProvider >
|
||||
);
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "asc-web-common",
|
||||
"version": "1.0.1",
|
||||
"version": "1.0.4",
|
||||
"description": "Ascensio System SIA common components and solutions library",
|
||||
"license": "AGPL-3.0",
|
||||
"files": [
|
||||
@ -122,4 +122,4 @@
|
||||
"node": ">=8",
|
||||
"npm": ">=5"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
export { default as PrivateRoute } from "./routing/privateRoute";
|
||||
export { default as PublicRoute } from "./routing/publicRoute";
|
||||
export { default as Login } from "./login";
|
||||
export { default as Login } from "./login";
|
||||
export { default as StudioLayout } from "./layout";
|
35
web/ASC.Web.Common/src/components/layout/i18n.js
Normal file
35
web/ASC.Web.Common/src/components/layout/i18n.js
Normal file
@ -0,0 +1,35 @@
|
||||
import i18n from "i18next";
|
||||
import en from "./locales/en/translation.json";
|
||||
import ru from "./locales/ru/translation.json";
|
||||
|
||||
const newInstance = i18n.createInstance();
|
||||
|
||||
const resources = {
|
||||
en: {
|
||||
translation: en//require("./locales/en/translation.json")
|
||||
},
|
||||
ru: {
|
||||
translation: ru//require("./locales/ru/translation.json")
|
||||
}
|
||||
};
|
||||
|
||||
newInstance.init({
|
||||
resources: resources,
|
||||
lng: '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;
|
89
web/ASC.Web.Common/src/components/layout/index.js
Normal file
89
web/ASC.Web.Common/src/components/layout/index.js
Normal file
@ -0,0 +1,89 @@
|
||||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import PropTypes from "prop-types";
|
||||
import { withRouter } from "react-router";
|
||||
import { withTranslation, I18nextProvider } from "react-i18next";
|
||||
import i18n from "./i18n";
|
||||
import { logout } from "../../store/auth/actions";
|
||||
import PureStudioLayout from "./pureStudioLayout";
|
||||
|
||||
const getSeparator = id => {
|
||||
return {
|
||||
separator: true,
|
||||
id: id
|
||||
};
|
||||
};
|
||||
|
||||
const toModuleWrapper = (item, iconName) => {
|
||||
return {
|
||||
id: item.id,
|
||||
title: item.title,
|
||||
iconName: iconName || "PeopleIcon",
|
||||
notifications: 0,
|
||||
url: item.link,
|
||||
onClick: () => window.open(item.link, "_self"),
|
||||
onBadgeClick: e => console.log(iconName + " Badge Clicked", e)
|
||||
};
|
||||
};
|
||||
|
||||
const getCustomModules = isAdmin => {
|
||||
if (!isAdmin) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const separator = getSeparator("nav-modules-separator");
|
||||
const settingsModuleWrapper = toModuleWrapper(
|
||||
{
|
||||
id: "settings",
|
||||
title: "Settings",
|
||||
link: "/settings"
|
||||
},
|
||||
"SettingsIcon"
|
||||
);
|
||||
|
||||
return [separator, settingsModuleWrapper];
|
||||
};
|
||||
|
||||
const getAvailableModules = (modules, currentUser) => {
|
||||
if (!modules.length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const isUserAdmin = currentUser.isAdmin;
|
||||
const customModules = getCustomModules(isUserAdmin);
|
||||
const separator = getSeparator("nav-products-separator");
|
||||
const products = modules.map(toModuleWrapper);
|
||||
|
||||
return [separator, ...products, ...customModules];
|
||||
};
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
hasChanges: state.auth.isAuthenticated && state.auth.isLoaded,
|
||||
availableModules: getAvailableModules(state.auth.modules, state.auth.user),
|
||||
currentUser: state.auth.user,
|
||||
currentModuleId: state.auth.settings.currentProductId,
|
||||
settings: state.auth.settings,
|
||||
language: state.auth.user.cultureName || state.auth.settings.culture
|
||||
};
|
||||
}
|
||||
|
||||
const StudioLayoutContainer = withTranslation()(PureStudioLayout);
|
||||
|
||||
const StudioLayout = props => {
|
||||
const { language } = props;
|
||||
i18n.changeLanguage(language);
|
||||
|
||||
return (
|
||||
<I18nextProvider i18n={i18n}>
|
||||
<StudioLayoutContainer {...props} />
|
||||
</I18nextProvider>
|
||||
);
|
||||
};
|
||||
|
||||
StudioLayout.propTypes = {
|
||||
logout: PropTypes.func.isRequired,
|
||||
language: PropTypes.string
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, { logout })(withRouter(StudioLayout));
|
85
web/ASC.Web.Common/src/components/layout/pureStudioLayout.js
Normal file
85
web/ASC.Web.Common/src/components/layout/pureStudioLayout.js
Normal file
@ -0,0 +1,85 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { Layout, Toast } from "asc-web-components";
|
||||
|
||||
class PureStudioLayout extends React.Component {
|
||||
shouldComponentUpdate(nextProps) {
|
||||
return this.props.hasChanges !== nextProps.hasChanges ||
|
||||
this.props.currentModuleId !== nextProps.currentModuleId;
|
||||
}
|
||||
|
||||
onProfileClick = () => {
|
||||
const { history, settings } = this.props;
|
||||
if (settings.homepage == "/products/people") {
|
||||
history.push("/products/people/view/@self");
|
||||
} else {
|
||||
window.open("/products/people/view/@self", "_self")
|
||||
}
|
||||
};
|
||||
|
||||
onAboutClick = () => {
|
||||
window.open("/about", "_self")
|
||||
};
|
||||
|
||||
onLogoutClick = () => {
|
||||
this.props.logout();
|
||||
};
|
||||
|
||||
onLogoClick = () => {
|
||||
window.open("/", "_self")
|
||||
};
|
||||
|
||||
render() {
|
||||
const { hasChanges, children, t } = this.props;
|
||||
|
||||
const currentUserActions = [
|
||||
{
|
||||
key: "ProfileBtn",
|
||||
label: t("Profile"),
|
||||
onClick: this.onProfileClick
|
||||
},
|
||||
{
|
||||
key: "AboutBtn",
|
||||
label: t("AboutCompanyTitle"),
|
||||
onClick: this.onAboutClick
|
||||
},
|
||||
{
|
||||
key: "LogoutBtn",
|
||||
label: t("LogoutButton"),
|
||||
onClick: this.onLogoutClick
|
||||
}
|
||||
];
|
||||
|
||||
const newProps = hasChanges
|
||||
? {
|
||||
currentUserActions: currentUserActions,
|
||||
onLogoClick: this.onLogoClick,
|
||||
...this.props
|
||||
}
|
||||
: {};
|
||||
|
||||
console.log("PureStudioLayout render", newProps);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Toast />
|
||||
<Layout key="1" {...newProps}>
|
||||
{children}
|
||||
</Layout>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
PureStudioLayout.propTypes = {
|
||||
logout: PropTypes.func.isRequired,
|
||||
language: PropTypes.string,
|
||||
hasChanges: PropTypes.bool,
|
||||
currentModuleId: PropTypes.string,
|
||||
history: PropTypes.object,
|
||||
settings: PropTypes.object,
|
||||
children: PropTypes.any,
|
||||
t: PropTypes.func
|
||||
};
|
||||
|
||||
export default PureStudioLayout;
|
@ -1,15 +1,6 @@
|
||||
import React, { useState, useEffect, useCallback } from "react";
|
||||
import React, { Component } 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,
|
||||
@ -22,329 +13,348 @@ import {
|
||||
} from "asc-web-components";
|
||||
import { connect } from "react-redux";
|
||||
import styled from "styled-components";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { withTranslation, I18nextProvider } from "react-i18next";
|
||||
import i18n from "./i18n";
|
||||
import SubModalDialog from "./sub-components/modal-dialog";
|
||||
import { login, setIsLoaded } from "../../store/auth/actions";
|
||||
import { sendInstructionsToChangePassword } from "../../api/people";
|
||||
|
||||
const FormContainer = styled(Container)`
|
||||
margin-top: 70px;
|
||||
const FormContainer = styled.form`
|
||||
margin: 50px auto 0 auto;
|
||||
max-width: 432px;
|
||||
|
||||
.link-style {
|
||||
float: right;
|
||||
line-height: 16px;
|
||||
.login-header {
|
||||
margin-bottom: 24px;
|
||||
|
||||
.login-logo {
|
||||
max-width: 216px;
|
||||
max-height: 35px;
|
||||
}
|
||||
|
||||
.login-title {
|
||||
margin: 8px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.text-body {
|
||||
.login-input {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.login-forgot-wrapper {
|
||||
height: 36px;
|
||||
|
||||
.login-checkbox-wrapper {
|
||||
position: absolute;
|
||||
display: inline-flex;
|
||||
|
||||
.login-checkbox {
|
||||
float: left;
|
||||
span {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
.login-tooltip {
|
||||
margin-left: 3px;
|
||||
display: inline-flex;
|
||||
}
|
||||
}
|
||||
.login-link {
|
||||
float: right;
|
||||
line-height: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.login-button {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.btn-style {
|
||||
.login-button-dialog {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.checkbox {
|
||||
float: left;
|
||||
span {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.question-icon {
|
||||
float: left;
|
||||
margin-left: 4px;
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
.login-row {
|
||||
margin: 23px 0 0;
|
||||
|
||||
.login-card {
|
||||
border: none;
|
||||
|
||||
.card-img {
|
||||
max-width: 216px;
|
||||
max-height: 35px;
|
||||
}
|
||||
.card-title {
|
||||
word-wrap: break-word;
|
||||
margin: 8px 0;
|
||||
text-align: left;
|
||||
font-size: 24px;
|
||||
color: #116d9d;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.button-row {
|
||||
margin: 16px 0 0;
|
||||
}
|
||||
`;
|
||||
|
||||
const TooltipStyle = styled.span`
|
||||
margin-left: 3px;
|
||||
position: absolute;
|
||||
margin-top: 2px;
|
||||
`;
|
||||
class Form extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
const mdOptions = { size: 6, offset: 3 };
|
||||
this.state = {
|
||||
identifierValid: true,
|
||||
identifier: "",
|
||||
isLoading: false,
|
||||
isDisabled: false,
|
||||
passwordValid: true,
|
||||
password: "",
|
||||
isChecked: false,
|
||||
openDialog: false,
|
||||
email: "",
|
||||
errorText: ""
|
||||
};
|
||||
}
|
||||
|
||||
const Form = props => {
|
||||
const { t } = useTranslation("translation", { i18n });
|
||||
const { login, setIsLoaded, match, history, language, greetingTitle } = props;
|
||||
const { params } = match;
|
||||
const [identifier, setIdentifier] = useState(params.confirmedEmail || "");
|
||||
const [identifierValid, setIdentifierValid] = useState(true);
|
||||
const [password, setPassword] = useState("");
|
||||
const [passwordValid, setPasswordValid] = useState(true);
|
||||
const [errorText, setErrorText] = useState("");
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
const [openDialog, setOpenDialog] = useState(false);
|
||||
const [email, setEmail] = useState("");
|
||||
const [isDisabled, setIsDisabled] = useState(false);
|
||||
const [isChecked, setIsisChecked] = useState(false);
|
||||
|
||||
const onClick = () => {
|
||||
setOpenDialog(true);
|
||||
setIsDisabled(true);
|
||||
setEmail(identifier);
|
||||
onChangeLogin = event => {
|
||||
this.setState({ identifier: event.target.value });
|
||||
!this.state.identifierValid && this.setState({ identifierValid: true });
|
||||
this.state.errorText && this.setState({ errorText: "" });
|
||||
};
|
||||
|
||||
const onDialogClose = () => {
|
||||
setOpenDialog(false);
|
||||
setIsDisabled(false);
|
||||
setIsLoading(false);
|
||||
setEmail("");
|
||||
onChangePassword = event => {
|
||||
this.setState({ password: event.target.value });
|
||||
!this.state.passwordValid && this.setState({ passwordValid: true });
|
||||
this.state.errorText && this.setState({ errorText: "" });
|
||||
};
|
||||
|
||||
const onSendPasswordInstructions = useCallback(() => {
|
||||
setIsLoading(true);
|
||||
sendInstructionsToChangePassword(email)
|
||||
.then(res => toastr.success(res), message => toastr.error(message))
|
||||
.finally(onDialogClose());
|
||||
}, [email]);
|
||||
onChangeEmail = event => {
|
||||
this.setState({ email: event.target.value });
|
||||
};
|
||||
|
||||
const onSubmit = useCallback(() => {
|
||||
errorText && setErrorText("");
|
||||
onChangeCheckbox = () => this.setState({ isChecked: !this.state.isChecked });
|
||||
|
||||
onClick = () => {
|
||||
this.setState({
|
||||
openDialog: true,
|
||||
isDisabled: true,
|
||||
email: this.state.identifier
|
||||
});
|
||||
};
|
||||
|
||||
onKeyPress = event => {
|
||||
if (event.key === "Enter") {
|
||||
!this.state.isDisabled
|
||||
? this.onSubmit()
|
||||
: this.onSendPasswordInstructions();
|
||||
}
|
||||
};
|
||||
|
||||
onSendPasswordInstructions = () => {
|
||||
this.setState({ isLoading: true });
|
||||
sendInstructionsToChangePassword(this.state.email)
|
||||
.then(
|
||||
res => toastr.success(res),
|
||||
message => toastr.error(message)
|
||||
)
|
||||
.finally(this.onDialogClose());
|
||||
};
|
||||
|
||||
onDialogClose = () => {
|
||||
this.setState({
|
||||
openDialog: false,
|
||||
isDisabled: false,
|
||||
isLoading: false,
|
||||
email: ""
|
||||
});
|
||||
};
|
||||
|
||||
onSubmit = () => {
|
||||
const { errorText, identifier, password } = this.state;
|
||||
const { login, setIsLoaded, history } = this.props;
|
||||
|
||||
errorText && this.setState({ errorText: "" });
|
||||
let hasError = false;
|
||||
|
||||
const userName = identifier.trim();
|
||||
|
||||
if (!userName) {
|
||||
hasError = true;
|
||||
setIdentifierValid(!hasError);
|
||||
this.setState({ identifierValid: !hasError });
|
||||
}
|
||||
|
||||
const pass = password.trim();
|
||||
|
||||
if (!pass) {
|
||||
hasError = true;
|
||||
setPasswordValid(!hasError);
|
||||
this.setState({ passwordValid: !hasError });
|
||||
}
|
||||
|
||||
if (hasError) return false;
|
||||
|
||||
setIsLoading(true);
|
||||
this.setState({ isLoading: true });
|
||||
|
||||
login(userName, pass).then(
|
||||
() => {
|
||||
//console.log("auth success", match, location, history);
|
||||
setIsLoading(false);
|
||||
login(userName, pass)
|
||||
.then(() => {
|
||||
setIsLoaded(true);
|
||||
history.push("/");
|
||||
},
|
||||
error => {
|
||||
//console.error("auth error", error);
|
||||
setErrorText(error);
|
||||
setIsLoading(false);
|
||||
}
|
||||
);
|
||||
}, [errorText, history, identifier, login, setIsLoaded, password]);
|
||||
})
|
||||
.catch(error => {
|
||||
this.setState({ errorText: error, isLoading: false });
|
||||
});
|
||||
};
|
||||
|
||||
const onKeyPress = useCallback(
|
||||
event => {
|
||||
if (event.key === "Enter") {
|
||||
!isDisabled ? onSubmit() : onSendPasswordInstructions();
|
||||
}
|
||||
},
|
||||
[onSendPasswordInstructions, onSubmit, isDisabled]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
componentDidMount() {
|
||||
const { language, match } = this.props;
|
||||
const { params } = match;
|
||||
i18n.changeLanguage(language);
|
||||
params.error && setErrorText(params.error);
|
||||
window.addEventListener("keyup", onKeyPress);
|
||||
// Remove event listeners on cleanup
|
||||
return () => {
|
||||
window.removeEventListener("keyup", onKeyPress);
|
||||
};
|
||||
}, [onKeyPress, params, language]);
|
||||
params.error && this.setState({ errorText: params.error });
|
||||
window.addEventListener("keyup", this.onKeyPress);
|
||||
}
|
||||
|
||||
const onChangePassword = event => {
|
||||
setPassword(event.target.value);
|
||||
!passwordValid && setPasswordValid(true);
|
||||
errorText && setErrorText("");
|
||||
};
|
||||
componentWillUnmount() {
|
||||
window.removeEventListener("keyup", this.onKeyPress);
|
||||
}
|
||||
|
||||
const onChangeLogin = event => {
|
||||
setIdentifier(event.target.value);
|
||||
!identifierValid && setIdentifierValid(true);
|
||||
errorText && setErrorText("");
|
||||
};
|
||||
render() {
|
||||
const { greetingTitle, match, t } = this.props;
|
||||
|
||||
const onChangeEmail = event => {
|
||||
setEmail(event.target.value);
|
||||
};
|
||||
const {
|
||||
identifierValid,
|
||||
identifier,
|
||||
isLoading,
|
||||
passwordValid,
|
||||
password,
|
||||
isChecked,
|
||||
openDialog,
|
||||
email,
|
||||
errorText
|
||||
} = this.state;
|
||||
const { params } = match;
|
||||
|
||||
// console.log('Login render');
|
||||
//console.log("Login render");
|
||||
|
||||
return (
|
||||
<FormContainer>
|
||||
<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
|
||||
return (
|
||||
<FormContainer>
|
||||
<div className="login-header">
|
||||
<img
|
||||
className="login-logo"
|
||||
src="images/dark_general.png"
|
||||
alt="Logo"
|
||||
/>
|
||||
<Text.Headline className="login-title" color="#116d9d">
|
||||
{greetingTitle}
|
||||
</Text.Headline>
|
||||
</div>
|
||||
|
||||
<TextInput
|
||||
id="login"
|
||||
name="login"
|
||||
hasError={!identifierValid}
|
||||
value={identifier}
|
||||
placeholder={t("RegistrationEmailWatermark")}
|
||||
size="huge"
|
||||
scale={true}
|
||||
isAutoFocussed={true}
|
||||
tabIndex={1}
|
||||
isDisabled={isLoading}
|
||||
autoComplete="username"
|
||||
onChange={this.onChangeLogin}
|
||||
onKeyDown={this.onKeyPress}
|
||||
className="login-input"
|
||||
/>
|
||||
|
||||
<TextInput
|
||||
id="password"
|
||||
name="password"
|
||||
type="password"
|
||||
hasError={!passwordValid}
|
||||
value={password}
|
||||
placeholder={t("Password")}
|
||||
size="huge"
|
||||
scale={true}
|
||||
isAutoFocussed={true}
|
||||
tabIndex={2}
|
||||
isDisabled={isLoading}
|
||||
autoComplete="current-password"
|
||||
onChange={this.onChangePassword}
|
||||
onKeyDown={this.onKeyPress}
|
||||
className="login-input"
|
||||
/>
|
||||
|
||||
<div className="login-forgot-wrapper">
|
||||
<div className="login-checkbox-wrapper">
|
||||
<Checkbox
|
||||
className="login-checkbox"
|
||||
isChecked={isChecked}
|
||||
onChange={this.onChangeCheckbox}
|
||||
label={t("Remember")}
|
||||
/>
|
||||
<CardTitle className="card-title">
|
||||
{greetingTitle}
|
||||
</CardTitle>
|
||||
</Card>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row className="login-row">
|
||||
<Col sm="12" md={mdOptions}>
|
||||
<TextInput
|
||||
id="login"
|
||||
name="login"
|
||||
hasError={!identifierValid}
|
||||
value={identifier}
|
||||
placeholder={t("RegistrationEmailWatermark")}
|
||||
size="huge"
|
||||
scale={true}
|
||||
isAutoFocussed={true}
|
||||
tabIndex={1}
|
||||
isDisabled={isLoading}
|
||||
autoComplete="username"
|
||||
onChange={onChangeLogin}
|
||||
onKeyDown={onKeyPress}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row className="login-row">
|
||||
<Col sm="12" md={mdOptions}>
|
||||
<TextInput
|
||||
id="password"
|
||||
name="password"
|
||||
type="password"
|
||||
hasError={!passwordValid}
|
||||
value={password}
|
||||
placeholder={t("Password")}
|
||||
size="huge"
|
||||
scale={true}
|
||||
tabIndex={2}
|
||||
isDisabled={isLoading}
|
||||
autoComplete="current-password"
|
||||
onChange={onChangePassword}
|
||||
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>
|
||||
<Checkbox
|
||||
className="checkbox"
|
||||
isChecked={isChecked}
|
||||
onChange={() => setIsisChecked(!isChecked)}
|
||||
label={t("Remember")}
|
||||
/>
|
||||
<TooltipStyle>
|
||||
<HelpButton
|
||||
helpButtonHeaderContent={t('CookieSettingsTitle')}
|
||||
className="login-tooltip"
|
||||
helpButtonHeaderContent={t("CookieSettingsTitle")}
|
||||
tooltipContent={
|
||||
<Text.Body fontSize={12}>{t("RememberHelper")}</Text.Body>
|
||||
}
|
||||
/>
|
||||
</TooltipStyle>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
|
||||
{openDialog ? (
|
||||
<SubModalDialog
|
||||
openDialog={openDialog}
|
||||
isLoading={isLoading}
|
||||
email={email}
|
||||
onChangeEmail={onChangeEmail}
|
||||
onSendPasswordInstructions={onSendPasswordInstructions}
|
||||
onDialogClose={onDialogClose}
|
||||
t={t}
|
||||
/>
|
||||
) : null}
|
||||
<Link
|
||||
fontSize={12}
|
||||
className="login-link"
|
||||
type="page"
|
||||
isHovered={true}
|
||||
onClick={this.onClick}
|
||||
>
|
||||
{t("ForgotPassword")}
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<Row className="button-row">
|
||||
<Col sm="12" md={mdOptions}>
|
||||
<Button
|
||||
primary
|
||||
size="big"
|
||||
label={isLoading ? t("LoadingProcessing") : t("LoginButton")}
|
||||
tabIndex={3}
|
||||
isDisabled={isLoading}
|
||||
{openDialog ? (
|
||||
<SubModalDialog
|
||||
openDialog={openDialog}
|
||||
isLoading={isLoading}
|
||||
onClick={onSubmit}
|
||||
email={email}
|
||||
onChangeEmail={this.onChangeEmail}
|
||||
onSendPasswordInstructions={this.onSendPasswordInstructions}
|
||||
onDialogClose={this.onDialogClose}
|
||||
t={t}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
{params.confirmedEmail && (
|
||||
<Row className="login-row">
|
||||
<Col sm="12" md={mdOptions}>
|
||||
<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}>
|
||||
<div className="alert alert-danger">{errorText}</div>
|
||||
</Col>
|
||||
</Row>
|
||||
</Collapse>
|
||||
</FormContainer>
|
||||
) : null}
|
||||
|
||||
<Button
|
||||
id="button"
|
||||
className="login-button"
|
||||
primary
|
||||
size="big"
|
||||
label={isLoading ? t("LoadingProcessing") : t("LoginButton")}
|
||||
tabIndex={3}
|
||||
isDisabled={isLoading}
|
||||
isLoading={isLoading}
|
||||
onClick={this.onSubmit}
|
||||
/>
|
||||
|
||||
{params.confirmedEmail && (
|
||||
<Text.Body isBold={true} fontSize={16}>
|
||||
{t("MessageEmailConfirmed")} {t("MessageAuthorize")}
|
||||
</Text.Body>
|
||||
)}
|
||||
<Text.Body fontSize={14} color="#c30">
|
||||
{errorText}
|
||||
</Text.Body>
|
||||
</FormContainer>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const FormWrapper = withTranslation()(Form);
|
||||
|
||||
const LoginForm = props => {
|
||||
const { language } = props;
|
||||
i18n.changeLanguage(language);
|
||||
|
||||
return (
|
||||
<I18nextProvider i18n={i18n}>
|
||||
<PageLayout sectionBodyContent={<FormWrapper {...props} />} />
|
||||
</I18nextProvider>
|
||||
);
|
||||
};
|
||||
|
||||
const LoginForm = props => (
|
||||
<PageLayout sectionBodyContent={<Form {...props} />} />
|
||||
);
|
||||
|
||||
LoginForm.propTypes = {
|
||||
Form.propTypes = {
|
||||
login: PropTypes.func.isRequired,
|
||||
match: PropTypes.object.isRequired,
|
||||
location: PropTypes.object.isRequired,
|
||||
history: PropTypes.object.isRequired
|
||||
history: PropTypes.object.isRequired,
|
||||
setIsLoaded: PropTypes.func.isRequired,
|
||||
greetingTitle: PropTypes.string.isRequired,
|
||||
t: PropTypes.func.isRequired,
|
||||
language: PropTypes.string.isRequired
|
||||
};
|
||||
|
||||
LoginForm.defaultProps = {
|
||||
Form.defaultProps = {
|
||||
identifier: "",
|
||||
password: "",
|
||||
email: ""
|
||||
};
|
||||
|
||||
LoginForm.propTypes = {
|
||||
language: PropTypes.string.isRequired
|
||||
};
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
language: state.auth.user.cultureName || state.auth.settings.culture,
|
||||
@ -352,7 +362,6 @@ function mapStateToProps(state) {
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
{ login, setIsLoaded }
|
||||
)(withRouter(LoginForm));
|
||||
export default connect(mapStateToProps, { login, setIsLoaded })(
|
||||
withRouter(LoginForm)
|
||||
);
|
||||
|
@ -45,7 +45,7 @@ class SubModalDialog extends React.Component {
|
||||
]}
|
||||
footerContent={[
|
||||
<Button
|
||||
className="btn-style"
|
||||
className="login-button-dialog"
|
||||
key="SendBtn"
|
||||
label={isLoading ? t("LoadingProcessing") : t("SendButton")}
|
||||
size="big"
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "asc-web-components",
|
||||
"version": "1.0.197",
|
||||
"version": "1.0.199",
|
||||
"description": "Ascensio System SIA component library",
|
||||
"license": "AGPL-3.0",
|
||||
"main": "dist/asc-web-components.js",
|
||||
|
@ -53,3 +53,4 @@ import { HelpButton } from "asc-web-components";
|
||||
| `place` | `string` | - | `top`, `right`, `bottom`, `left` | `top` | Tooltip placement |
|
||||
| `displayType` | `oneOf` | - | `dropdown`, `aside`, `auto` | `auto` | Tooltip display type |
|
||||
| `helpButtonHeaderContent` | `string` | - | - | - | Tooltip header content (tooltip opened in aside) |
|
||||
| `className` | `string` | - | - | - | Set component class |
|
||||
|
@ -115,7 +115,7 @@ class HelpButton extends React.Component {
|
||||
|
||||
onClick = () => {
|
||||
this.setState({isOpen: !this.state.isOpen});
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { isOpen, displayType } = this.state;
|
||||
@ -178,8 +178,7 @@ class HelpButton extends React.Component {
|
||||
<Backdrop onClick={this.onClose} visible={isOpen} zIndex={zIndex} />
|
||||
<Aside visible={isOpen} scale={false} zIndex={zIndex}>
|
||||
<Content>
|
||||
{
|
||||
helpButtonHeaderContent &&
|
||||
{helpButtonHeaderContent && (
|
||||
<Header>
|
||||
<HeaderText>
|
||||
<Text.Body isBold={true} fontSize={21}>
|
||||
@ -187,7 +186,7 @@ class HelpButton extends React.Component {
|
||||
</Text.Body>
|
||||
</HeaderText>
|
||||
</Header>
|
||||
}
|
||||
)}
|
||||
<Body>{tooltipContent}</Body>
|
||||
</Content>
|
||||
</Aside>
|
||||
@ -203,7 +202,8 @@ HelpButton.propTypes = {
|
||||
PropTypes.arrayOf(PropTypes.node),
|
||||
PropTypes.node
|
||||
]),
|
||||
tooltipContent: PropTypes.oneOfType([PropTypes.string, PropTypes.object]).isRequired,
|
||||
tooltipContent: PropTypes.oneOfType([PropTypes.string, PropTypes.object])
|
||||
.isRequired,
|
||||
offsetRight: PropTypes.number,
|
||||
tooltipMaxWidth: PropTypes.number,
|
||||
tooltipId: PropTypes.string,
|
||||
|
@ -31,8 +31,13 @@ const StyledArticle = styled.article`
|
||||
z-index: 400;
|
||||
`
|
||||
: `
|
||||
display: none;
|
||||
width: 0px;
|
||||
width: 240px;
|
||||
min-width: 240px;
|
||||
position: fixed;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: -240px;
|
||||
z-index: 400;
|
||||
`}
|
||||
}
|
||||
`;
|
||||
|
@ -56,7 +56,7 @@ class ToggleButton extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
checked: this.props.isChecked
|
||||
checked: props.isChecked
|
||||
};
|
||||
}
|
||||
|
||||
@ -104,4 +104,8 @@ ToggleButton.propTypes = {
|
||||
className: PropTypes.string
|
||||
};
|
||||
|
||||
ToggleIcon.propTypes = {
|
||||
isChecked: PropTypes.bool
|
||||
}
|
||||
|
||||
export default ToggleButton;
|
||||
|
Loading…
Reference in New Issue
Block a user