props.theme.headerHeight - 1}px;
- padding-top: ${props => 50 + props.theme.toolbarHeight}px;
+ margin-top: ${props => props.theme.headerHeight + (platform.select({ win32: 1 }) || 0)}px;
&::before {
content: ' ';
diff --git a/src/app/components/Modal/index.tsx b/src/app/components/Modal/index.tsx
index 7bdc382b4..1b041e206 100644
--- a/src/app/components/Modal/index.tsx
+++ b/src/app/components/Modal/index.tsx
@@ -7,6 +7,7 @@ import React from 'react';
import { InjectedIntl } from 'react-intl';
import themed from 'components/Theme/themed';
+import Header from 'containers/Modal/Header';
export interface IModalProps {
intl: InjectedIntl;
@@ -21,15 +22,6 @@ export type TModalComponentClass
=
React.ComponentType> |
React.SFC>;
-const StyledHeader = themed.div`
- background: ${props => props.theme.modalHeaderBackground};
- color: ${props => props.theme.modalHeaderForeground};
- margin: -1px -1px 0 -1px;
- height: 40px;
- line-height: 40px;
- padding: 0 15px;
-`;
-
const StyledBody = themed.div`
padding: 15px;
min-width: 300px;
@@ -42,13 +34,13 @@ const StyledFooter = themed.div`
`;
export abstract class ModalContainer extends React.Component
{
- public static Header = StyledHeader;
+ public static Header = Header;
public static Body = StyledBody;
public static Footer = StyledFooter;
}
export default abstract class Modal
extends React.Component, S> {
- public static Header = StyledHeader;
+ public static Header = Header;
public static Body = StyledBody;
public static Footer = StyledFooter;
}
\ No newline at end of file
diff --git a/src/app/components/Money/index.tsx b/src/app/components/Money/index.tsx
deleted file mode 100644
index bf5757889..000000000
--- a/src/app/components/Money/index.tsx
+++ /dev/null
@@ -1,23 +0,0 @@
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) EGAAS S.A. All rights reserved.
- * See LICENSE in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import * as React from 'react';
-import { FormattedNumber } from 'react-intl';
-
-export interface IMoneyProps {
- value: string | number;
- children?: never;
-}
-
-const Money: React.SFC = (props) => (
-
-);
-
-export default Money;
\ No newline at end of file
diff --git a/src/app/components/NotFound/index.tsx b/src/app/components/NotFound/index.tsx
deleted file mode 100644
index 59d4007ec..000000000
--- a/src/app/components/NotFound/index.tsx
+++ /dev/null
@@ -1,56 +0,0 @@
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) EGAAS S.A. All rights reserved.
- * See LICENSE in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import * as React from 'react';
-import { Link } from 'react-router-dom';
-import { FormattedMessage } from 'react-intl';
-
-import LocalizedDocumentTitle from 'components/DocumentTitle/LocalizedDocumentTitle';
-import Center from 'components/Center';
-
-export interface INotFoundProps {
- main?: boolean;
-}
-
-const NotFound: React.SFC = (props) => (
-
-
-
-
- {!props.main && (
-
- -
-
-
-
-
- - |
- -
-
-
-
-
- - |
- -
-
-
-
-
-
- )}
-
-
-
-);
-
-export default NotFound;
\ No newline at end of file
diff --git a/src/app/components/Protypo/Protypo.tsx b/src/app/components/Protypo/Protypo.tsx
index 508049191..b5640062f 100644
--- a/src/app/components/Protypo/Protypo.tsx
+++ b/src/app/components/Protypo/Protypo.tsx
@@ -9,19 +9,20 @@ import propTypes from 'prop-types';
import contextDefinitions from './contexts';
import { TProtypoElement, ISource } from 'apla/protypo';
import { IValidationResult } from 'components/Validation/ValidatedForm';
-import Heading from 'components/Heading';
+import Heading from './components/Heading';
import ToolButton, { IToolButtonProps } from 'containers/ToolButton/ToolButton';
import { IConstructorElementProps } from 'apla/editor';
+import { TBreadcrumbType } from 'apla/content';
export interface IProtypoProps extends IConstructorElementProps {
apiHost: string;
wrapper?: JSX.Element;
context: string;
- page: string;
+ page?: string;
+ menu?: string;
+ section: string;
content: TProtypoElement[];
menuPush: (params: { name: string, content: TProtypoElement[] }) => void;
- navigatePage: (params: { name: string, params: any, force?: boolean }) => void;
- navigate: (url: string) => void;
displayData: (link: string) => void;
}
@@ -37,65 +38,76 @@ export interface IParamSpec {
class Protypo extends React.Component {
private _lastID: number;
- private _menuPushBind: Function;
- private _navigatePageBind: Function;
- private _navigateBind: Function;
- private _resolveSourceBind: Function;
- private _renderElementsBind: Function;
private _title: string;
private _toolButtons: IToolButtonProps[];
private _sources: { [key: string]: ISource };
private _errors: { name: string, description: string }[];
- constructor(props: IProtypoProps) {
- super(props);
- this._menuPushBind = props.menuPush.bind(this);
- this._navigatePageBind = props.navigatePage.bind(this);
- this._navigateBind = props.navigate.bind(this);
- this._resolveSourceBind = this.resolveSource.bind(this);
- this._renderElementsBind = this.renderElements.bind(this);
- }
-
getChildContext() {
return {
protypo: this,
- menuPush: this._menuPushBind,
- navigatePage: this._navigatePageBind,
- navigate: this._navigateBind,
- resolveSource: this._resolveSourceBind,
- renderElements: this._renderElementsBind
+ section: this.props.section,
+ menuPush: this.props.menuPush,
+ resolveSource: this.resolveSource,
+ resolveText: this.resolveText,
+ getFromContext: this.getFromContext,
+ renderElements: this.renderElements
};
}
- getCurrentPage() {
+ getFromContext: (computeTitle?: React.ReactNode) => { type: TBreadcrumbType, section: string, name: string } | undefined = computeTitle => {
+ const title = computeTitle ? this.resolveText(computeTitle) : '';
+
+ if (this.props.page) {
+ return {
+ type: 'PAGE',
+ section: this.props.section,
+ title: title || this.props.page,
+ name: this.props.page
+ };
+ }
+ else if (this.props.menu) {
+ return {
+ type: 'MENU',
+ section: this.props.section,
+ title: title || this.props.menu,
+ name: this.props.menu
+ };
+ }
+ else {
+ return undefined;
+ }
+ }
+
+ getCurrentPage = () => {
return this.props.page;
}
- setTitle(title: string) {
+ setTitle = (title: string) => {
this._title = title;
}
- addToolButton(props: IToolButtonProps) {
+ addToolButton = (props: IToolButtonProps) => {
this._toolButtons.push(props);
}
- displayData(link: string) {
+ displayData = (link: string) => {
this.props.displayData(link);
}
- registerSource(name: string, payload: ISource) {
+ registerSource = (name: string, payload: ISource) => {
this._sources[name] = payload;
}
- resolveSource(name: string) {
+ resolveSource = (name: string) => {
return this._sources[name];
}
- resolveData(name: string) {
+ resolveData = (name: string) => {
return `${this.props.apiHost}${name}`;
}
- resolveParams(values: IParamsSpec, formValues?: { [key: string]: IValidationResult }) {
+ resolveParams = (values: IParamsSpec, formValues?: { [key: string]: IValidationResult }) => {
const result: { [key: string]: string } = {};
for (let itr in values) {
if (values.hasOwnProperty(itr)) {
@@ -114,7 +126,35 @@ class Protypo extends React.Component {
return result;
}
- renderElement(element: TProtypoElement, optionalKey?: string): React.ReactNode {
+ resolveText = (value: React.ReactNode) => {
+ let result = '';
+ if (value) {
+ if ('string' === typeof value || 'number' === typeof value) {
+ result += value;
+ }
+ else if ('object' === typeof value) {
+ let children = null;
+ if (Array.isArray(value)) {
+ children = value;
+ }
+ else if ('props' in value) {
+ children = value.props.children;
+ }
+ if (children) {
+ if (Array.isArray(children)) {
+ children.forEach(o => {
+ result += this.resolveText(o);
+ });
+ } else {
+ result += this.resolveText(children);
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ renderElement = (element: TProtypoElement, optionalKey?: string): React.ReactNode => {
switch (element.tag) {
case 'text':
return element.text;
@@ -160,7 +200,7 @@ class Protypo extends React.Component {
}
}
- renderElements(elements: TProtypoElement[], keyPrefix?: string): React.ReactNode[] {
+ renderElements = (elements: TProtypoElement[], keyPrefix?: string): React.ReactNode[] => {
if (!elements) {
return null;
}
@@ -170,7 +210,7 @@ class Protypo extends React.Component {
));
}
- renderHeading() {
+ renderHeading = () => {
return (this.props.context === 'page' && this._title) ? (
{this._title}
@@ -222,12 +262,13 @@ class Protypo extends React.Component {
}
(Protypo as any).childContextTypes = {
+ section: propTypes.string.isRequired,
protypo: propTypes.object.isRequired,
- navigatePage: propTypes.func.isRequired,
- navigate: propTypes.func.isRequired,
menuPush: propTypes.func.isRequired,
resolveSource: propTypes.func.isRequired,
- renderElements: propTypes.func.isRequired
+ resolveText: propTypes.func.isRequired,
+ renderElements: propTypes.func.isRequired,
+ getFromContext: propTypes.func.isRequired
};
export default Protypo;
diff --git a/src/app/components/Heading/index.tsx b/src/app/components/Protypo/components/Heading.tsx
similarity index 85%
rename from src/app/components/Heading/index.tsx
rename to src/app/components/Protypo/components/Heading.tsx
index d2989972d..b6eebae20 100644
--- a/src/app/components/Heading/index.tsx
+++ b/src/app/components/Protypo/components/Heading.tsx
@@ -3,16 +3,17 @@
* See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
-import * as React from 'react';
-import styled from 'styled-components';
+import React from 'react';
+import themed from 'components/Theme/themed';
-const StyledHeading = styled.div`
+const StyledHeading = themed.div`
z-index: 1000;
font-size: 20px;
line-height: 45px;
height: 46px;
color: #000;
font-weight: normal;
+ margin-top: 10px;
padding: 0 20px;
border: 0;
`;
diff --git a/src/app/components/Protypo/components/ToolButton.tsx b/src/app/components/Protypo/components/ToolButton.tsx
index eccbebc1f..978e2d032 100644
--- a/src/app/components/Protypo/components/ToolButton.tsx
+++ b/src/app/components/Protypo/components/ToolButton.tsx
@@ -4,9 +4,9 @@
*--------------------------------------------------------------------------------------------*/
import React from 'react';
-import propTypes from 'prop-types';
+import classNames from 'classnames';
-import Protypo from '../Protypo';
+import themed from 'components/Theme/themed';
export interface IToolButtonProps {
title?: string;
@@ -18,23 +18,44 @@ export interface IToolButtonProps {
onClick: (e: any) => void;
}
-interface IToolButtonContext {
- protypo: Protypo;
-}
+const StyledToolButton = themed.button`
+ border: 0;
+ background: 0;
+ outline: 0;
+ border: 0;
+ height: 35px;
+ line-height: 35px;
+ white-space: nowrap;
+ padding: 0 10px;
+ transition: background ease-in-out .12s;
+
+ &:hover {
+ background: rgba(0,0,0,0.05);
+ }
+
+ .toolbutton__icon {
+ font-size: 16px;
+ color: #4688ff;
+ margin-right: 8px;
+ }
+
+ .toolbutton__label {
+ vertical-align: top;
+ white-space: nowrap;
+ font-size: 15px;
+ color: #333;
+ }
+`;
-const ToolButton: React.SFC = (props, context: IToolButtonContext) => {
+const ToolButton: React.SFC = props => {
return (
-
-
-
- {props.title}
+
+
+
+ {props.title}
-
+
);
};
-ToolButton.contextTypes = {
- protypo: propTypes.object.isRequired
-};
-
export default ToolButton;
\ No newline at end of file
diff --git a/src/app/components/Protypo/functions/addToolButton.ts b/src/app/components/Protypo/functions/addToolButton.ts
index 5f07fe22a..4e130b5dd 100644
--- a/src/app/components/Protypo/functions/addToolButton.ts
+++ b/src/app/components/Protypo/functions/addToolButton.ts
@@ -3,7 +3,6 @@
* See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
-import Protypo from '../';
import { IParamsSpec } from 'components/Protypo/Protypo';
export interface IAddToolButtonProps {
@@ -13,9 +12,10 @@ export interface IAddToolButtonProps {
pageparams?: IParamsSpec;
}
-const addToolButton = (context: Protypo, props: IAddToolButtonProps) => {
+const addToolButton = (context: any, props: IAddToolButtonProps) => {
context.addToolButton({
...props,
+ section: context.section,
pageparams: context.resolveParams(props.pageparams)
});
};
diff --git a/src/app/components/Protypo/handlers/Button.tsx b/src/app/components/Protypo/handlers/Button.tsx
index 6ecd40667..2b9641fbe 100644
--- a/src/app/components/Protypo/handlers/Button.tsx
+++ b/src/app/components/Protypo/handlers/Button.tsx
@@ -16,6 +16,10 @@ import { IErrorRedirect } from 'apla/protypo';
export interface IButtonProps {
'class'?: string;
'className'?: string;
+ 'action'?: {
+ name: string;
+ params?: { [key: string]: string };
+ }[];
'alert'?: {
icon: string;
text: string;
@@ -45,6 +49,7 @@ export interface IButtonProps {
interface IButtonContext {
form: ValidatedForm;
+ section: string;
protypo: Protypo;
}
@@ -131,6 +136,7 @@ const Button: React.SFC = (props, context: IBu
return (
= (props, context: IBu
name: tx.name,
params: tx.data
}))}
+ from={context.protypo.getFromContext(props.children)}
contract={props.contract}
contractParams={getParams}
page={props.page}
+ section={context.section}
pageParams={getPageParams}
popup={popup}
errorRedirects={getErrorRedirectParams}
@@ -156,6 +164,7 @@ const Button: React.SFC = (props, context: IBu
Button.contextTypes = {
form: propTypes.object,
+ section: propTypes.string,
protypo: propTypes.object.isRequired
};
diff --git a/src/app/components/Protypo/handlers/Hint.tsx b/src/app/components/Protypo/handlers/Hint.tsx
index 9558a41dd..2aeb72a70 100644
--- a/src/app/components/Protypo/handlers/Hint.tsx
+++ b/src/app/components/Protypo/handlers/Hint.tsx
@@ -26,7 +26,7 @@ export const HintWrapper = themed.div`
font-weight: 300;
em.tool-icon {
- color: ${props => props.theme.toolbarIconColor};
+ color: #5b97e4,
transition: color .15s;
vertical-align: middle;
height: 18px;
@@ -35,12 +35,12 @@ export const HintWrapper = themed.div`
> span.button-label {
margin-left: 8px;
- color: ${props => props.theme.toolbarForeground};
+ color: #fff;
}
&:hover {
em.tool-icon {
- color: ${props => props.theme.toolbarIconHighlight};
+ color: #a9ccf9;
}
}
}
diff --git a/src/app/components/Protypo/handlers/LinkPage.tsx b/src/app/components/Protypo/handlers/LinkPage.tsx
index 821b5d288..e70925ac8 100644
--- a/src/app/components/Protypo/handlers/LinkPage.tsx
+++ b/src/app/components/Protypo/handlers/LinkPage.tsx
@@ -3,11 +3,12 @@
* See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
-import * as React from 'react';
-import * as propTypes from 'prop-types';
+import React from 'react';
+import propTypes from 'prop-types';
-import Protypo, { IParamsSpec } from '../Protypo';
+import { IParamsSpec } from '../Protypo';
import StyledComponent from './StyledComponent';
+import PageLink from 'containers/Routing/PageLink';
export interface ILinkPageProps {
'class'?: string;
@@ -17,31 +18,26 @@ export interface ILinkPageProps {
}
interface ILinkPageContext {
- protypo: Protypo;
- navigatePage: (params: { name: string, params: any, force?: boolean }) => void;
+ section: string;
+ getFromContext: () => any;
+ protypo: any;
}
-const LinkPage: React.SFC = (props, context: ILinkPageContext) => {
- const onNavigate = (e: React.MouseEvent) => {
- e.preventDefault();
- context.navigatePage({
- name: props.page,
- params: context.protypo.resolveParams(props.pageparams),
- force: true
- });
- return false;
- };
-
- return (
-
- {props.children}
-
- );
-};
+const LinkPage: React.SFC = (props, context: ILinkPageContext) => (
+
+ {props.children}
+
+);
LinkPage.contextTypes = {
protypo: propTypes.object.isRequired,
- navigatePage: propTypes.func.isRequired
+ section: propTypes.string.isRequired
};
export default StyledComponent(LinkPage);
\ No newline at end of file
diff --git a/src/app/components/Protypo/handlers/MenuItem.tsx b/src/app/components/Protypo/handlers/MenuItem.tsx
index cdcfa4448..8b3a7d67e 100644
--- a/src/app/components/Protypo/handlers/MenuItem.tsx
+++ b/src/app/components/Protypo/handlers/MenuItem.tsx
@@ -19,6 +19,8 @@ export interface IMenuItemProps {
}
export const StyledMenuItem = themed.div`
+ border-bottom: solid 1px ${props => props.theme.menuOutline};
+
> a, > a:hover {
text-decoration: none !important;
}
@@ -47,10 +49,10 @@ export const StyledMenuItem = themed.div`
display: block;
height: 50px;
line-height: 50px;
- padding: 0 25px;
+ padding: 0 18px;
color: ${props => props.theme.menuForeground};
font-size: 14px;
- font-weight: 200;
+ font-weight: 400;
text-align: left;
text-decoration: none;
overflow: hidden;
@@ -58,16 +60,16 @@ export const StyledMenuItem = themed.div`
white-space: nowrap;
.icon {
- margin-right: 14px;
+ margin-right: 16px;
color: ${props => props.theme.menuIconColor};
- font-size: 17px;
- position: relative;
- top: 3px;
+ font-size: 21px;
+ vertical-align: middle;
}
}
`;
interface IMenuItemContext {
+ section: string;
protypo: Protypo;
}
@@ -79,7 +81,16 @@ const MenuItem: React.SFC = (props, context: IMenuItemContext) =
return (
-
+
{props.icon && ()}
@@ -91,8 +102,8 @@ const MenuItem: React.SFC = (props, context: IMenuItemContext) =
};
MenuItem.contextTypes = {
- protypo: propTypes.object.isRequired,
- navigatePage: propTypes.func.isRequired
+ section: propTypes.string.isRequired,
+ protypo: propTypes.object.isRequired
};
export default MenuItem;
\ No newline at end of file
diff --git a/src/app/components/Routing/PageLink.tsx b/src/app/components/Routing/PageLink.tsx
index 630ef2aaf..abbc683ee 100644
--- a/src/app/components/Routing/PageLink.tsx
+++ b/src/app/components/Routing/PageLink.tsx
@@ -4,39 +4,36 @@
*--------------------------------------------------------------------------------------------*/
import React from 'react';
-import { LEGACY_PAGES } from 'lib/legacyPages';
+import { Link } from 'react-router-dom';
+import { generateRoute } from 'services/router';
+import { TBreadcrumbType } from 'apla/content';
export interface IPageLinkProps {
- section?: string;
- mainSection: string;
- currentSection: string;
+ className?: string;
+ section: string;
page: string;
params?: {
[key: string]: string
};
- className?: string;
- navigatePage: (params: { name: string, section: string, params: { [key: string]: string } }) => void;
-}
-
-const PageLink: React.SFC = props => {
- const sectionName = ((LEGACY_PAGES[props.page] && (LEGACY_PAGES[props.page].section || props.mainSection))) || props.section || props.currentSection;
-
- const navigateUrl = `/${sectionName}/${props.page}`;
- const navigatePage = (e: React.MouseEvent) => {
- e.preventDefault();
- props.navigatePage({
- name: props.page,
- section: sectionName,
- params: props.params
- });
- return false;
+ from?: {
+ name: string;
+ title?: string;
+ type: TBreadcrumbType;
};
+}
- return (
-
- {props.children}
-
- );
-};
+const PageLink: React.SFC = props => (
+
+ {props.children}
+
+);
export default PageLink;
\ No newline at end of file
diff --git a/src/app/components/StaticPages/TxInfo.tsx b/src/app/components/StaticPages/TxInfo.tsx
index 322d65992..f93216b18 100644
--- a/src/app/components/StaticPages/TxInfo.tsx
+++ b/src/app/components/StaticPages/TxInfo.tsx
@@ -13,6 +13,7 @@ import PrintZone from 'components/PrintZone';
import { FormattedMessage } from 'react-intl';
export interface ITxInfoProps {
+ section: string;
txStack: {
hash: string;
tx: ITransaction;
@@ -93,6 +94,7 @@ const TxInfo: React.SFC = props => (
))}
diff --git a/src/app/components/Tabs/index.tsx b/src/app/components/Tabs/index.tsx
deleted file mode 100644
index bf3d5237c..000000000
--- a/src/app/components/Tabs/index.tsx
+++ /dev/null
@@ -1,185 +0,0 @@
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) EGAAS S.A. All rights reserved.
- * See LICENSE in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import * as React from 'react';
-import styled from 'styled-components';
-
-const TabItems = styled.div`
- background-color: #707c91;
- background-color: rgba(0, 0, 0, 0.1);
-`;
-
-const TabsContainer = styled.div`
- display: flex;
- flex: 1 1;
- -ms-flex-direction: column;
- flex-direction: column;
-
- .tab-pane {
- display: none;
- flex: 1 1;
- -ms-flex-direction: column;
- flex-direction: column;
- }
-
- .tab-pane.active {
- display: flex;
- }
-`;
-
-const TabContent = styled.div`
- display: flex;
- flex: 1 1;
- flex-direction: column;
-`;
-
-const TabItem = styled.div`
- display: inline-block;
- color: #FFF;
- line-height: 26px;
-
- background-color: #465669;
- opacity: 0.5;
- cursor: pointer;
-
- margin-right: 1px;
-
- span {
- padding-left: 10px;
- padding-right: 10px;
- }
-
- a {
- color: #FFF;
- padding-left: 5px;
- padding-right: 10px;
- text-decoration: none;
- font-size: 16px;
- }
-
- a:hover {
- color: #FF5555;
- }
-
- &:hover {
- opacity: 0.8;
- }
-
- &.active {
- opacity: 1;
- }
-
- &.interfacePage {
- background-color: #883498;
- }
-
- &.interfaceBlock {
- background-color: #349837;
- }
-
- &.interfaceMenu {
- background-color: #985f34;
- }
-
- &.contract {
- background-color: #346198;
- }
-
- &.parameter {
- background-color: #333333;
- }
-`;
-
-export interface IConstructorTabsProps {
- tabList: { id: string, type: string, name?: string, visible?: boolean }[];
- children: JSX.Element[];
- openedTab: { id: string, type: string };
- onTabClose?: any;
- className?: string;
-}
-
-interface IConstructorTabsState {
- tabIndex: number;
- loaded: boolean;
-}
-
-export default class ConstructorTabs extends React.Component {
- constructor(props: IConstructorTabsProps) {
- super(props);
- this.state = {
- tabIndex: 0,
- loaded: false
- };
- }
-
- onTabSwitch(tabIndex: number) {
- this.setState({
- tabIndex,
- loaded: true
- });
- }
-
- componentWillReceiveProps(props: IConstructorTabsProps) {
- // open selected tab
- if (props.tabList && !this.state.loaded) {
- let tabIndex = props.tabList.findIndex((item: any) => item.id === props.openedTab.id && item.type === props.openedTab.type);
- if (tabIndex >= 0 && this.state.tabIndex < tabIndex) {
- this.setState({
- tabIndex,
- loaded: false
- });
- }
- }
- }
-
- onTabClose(id: string, type: string) {
- // if closed tab was active, set first tab active
-
- if (this.props.tabList) {
- let closedTabItemIndex = this.props.tabList.findIndex((tabItem: any) => tabItem.id === id && tabItem.type === type);
- if (closedTabItemIndex === this.state.tabIndex) {
- let switchToTabIndex = this.props.tabList.findIndex((tabItem: any, index: number) =>
- tabItem.visible !== false && index !== closedTabItemIndex
- );
- if (switchToTabIndex !== -1) {
- this.setState({
- tabIndex: switchToTabIndex,
- loaded: true
- });
- }
- }
- }
-
- let openedTabs = this.props.tabList.filter((tabItem: any, index: number) =>
- tabItem.visible !== false
- ).length;
-
- if (this.props.onTabClose && openedTabs > 1) {
- this.props.onTabClose(id, type);
- }
- }
-
- render() {
- return (
-
-
- {this.props.tabList && this.props.tabList.map((tab, index) => (
-
- {tab.name}
- ×
-
- ))}
-
-
- {this.props.children.map((element, index) => (
-
- {element}
-
- ))}
-
-
- );
- }
-}
\ No newline at end of file
diff --git a/src/app/components/Theme/baseTheme.ts b/src/app/components/Theme/baseTheme.ts
index e7c0c060e..bd3ef78de 100644
--- a/src/app/components/Theme/baseTheme.ts
+++ b/src/app/components/Theme/baseTheme.ts
@@ -9,33 +9,41 @@ import platform from 'lib/platform';
const baseTheme: IThemeDefinition = {
windowBorder: '#4c7dbd',
- headerBackground: '#586180',
+ headerBackground: '#354a69',
headerForeground: '#fff',
- headerBackgroundActive: '#f3f3f3',
- headerForegroundActive: '#194a8a',
headerHeight: platform.select({ desktop: 28, web: 0 }),
- toolbarBackground: '#f3f3f3',
- toolbarForeground: '#194a8a',
- toolbarOutline: '#e5e5e5',
- toolbarIconColor: '#5b97e4',
- toolbarIconHighlight: '#a9ccf9',
- toolbarDisabled: '#93a7bf',
- toolbarHeight: 40,
+ menubarSize: 40,
+ menubarBackground: '#3873A6',
+ menubarBackgroundActive: '#9CB9D2',
+ menubarBackgroundFocused: 'rgba(255,255,255,0.09)',
+ menubarBackgroundSecondary: '#ffa500',
+ menubarForeground: '#9CB9D3',
+ menubarForegroundActive: '#fff',
- progressBarForeground: '#b2c5dc',
+ toolbarBackground: '#f1f1f1',
+ toolbarBackgroundActive: 'rgba(0,0,0,0.1)',
+ toolbarBackgroundFocused: 'rgba(0,0,0,0.05)',
+ toolbarForeground: '#333',
+ toolbarForegroundActive: '#5d5d5d',
+ toolbarForegroundPrimary: '#4688ff',
+ toolbarForegroundDisabled: '#ccc',
+ toolbarHeight: 40,
+ toolbarSpacerForeground: '#C6C6C6',
- menuHeight: 40,
menuBackground: '#fff',
menuForeground: '#0a1d33',
- menuBackgroundActive: '#ececec',
- menuOutline: '#e5e4e5',
+ menuBackgroundActive: '#f6f7f9',
+ menuBorder: '#35abff',
+ menuOutline: '#eff2f5',
menuIconColor: '#3577cc',
menuPrimaryForeground: '#2886ff',
menuPrimaryActive: '#7bb0f5',
+ menuSize: 230,
+ menuSizeFolded: 55,
contentForeground: '#515253',
- contentBackground: '#f6f7fa',
+ contentBackground: '#fff',
editorBackground: '#c3c7ce',
@@ -55,19 +63,17 @@ const baseTheme: IThemeDefinition = {
sectionButtonPrimary: '#fff',
dropdownMenuBackground: '#fff',
- dropdownMenuForeground: '#666',
+ dropdownMenuForeground: '#464646',
dropdownMenuDisabled: '#ccc',
- dropdownMenuOutline: '#c5cbe2',
- dropdownMenuActive: 'rgba(0,0,0,0.1)',
- dropdownMenuSeparator: '#ddd',
+ dropdownMenuActive: 'rgba(0,0,0,0.06)',
+ dropdownMenuSeparator: '#efefef',
dropdownMenuPrimary: '#4b7dbd',
dropdownMenuSecondary: '#999',
- systemButtonSecondary: '#ffa500',
- systemButtonActive: 'rgba(0,0,0,0.1)',
-
securityWarningBackground: '#ff5555',
- securityWarningForeground: '#ffffff'
+ securityWarningForeground: '#ffffff',
+
+ uiBorderLight: '#e8eaf1'
};
export default baseTheme;
\ No newline at end of file
diff --git a/src/app/components/Main/Titlebar/DarwinTitlebar.tsx b/src/app/components/Titlebar/DarwinTitlebar.tsx
similarity index 98%
rename from src/app/components/Main/Titlebar/DarwinTitlebar.tsx
rename to src/app/components/Titlebar/DarwinTitlebar.tsx
index 3d695a1b0..e0cd748d7 100644
--- a/src/app/components/Main/Titlebar/DarwinTitlebar.tsx
+++ b/src/app/components/Titlebar/DarwinTitlebar.tsx
@@ -10,7 +10,7 @@ import { remote } from 'electron';
import imgControls from './wndControls.svg';
import { ITitlebarProps } from './';
-import SystemMenu from 'containers/Main/Titlebar/SystemMenu';
+import SystemMenu from 'containers/Titlebar/SystemMenu';
const StyledControls = styled.div`
-webkit-app-region: no-drag;
@@ -25,7 +25,7 @@ const StyledControls = styled.div`
.window-controls {
position: absolute;
left: 6px;
- top: 5px;
+ top: 2px;
button {
background: url(${imgControls}) 0 0 no-repeat;
diff --git a/src/app/components/Main/Titlebar/LinuxTitlebar.tsx b/src/app/components/Titlebar/LinuxTitlebar.tsx
similarity index 97%
rename from src/app/components/Main/Titlebar/LinuxTitlebar.tsx
rename to src/app/components/Titlebar/LinuxTitlebar.tsx
index 1da112d45..f185f328a 100644
--- a/src/app/components/Main/Titlebar/LinuxTitlebar.tsx
+++ b/src/app/components/Titlebar/LinuxTitlebar.tsx
@@ -3,13 +3,13 @@
* See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
-import * as React from 'react';
+import React from 'react';
import styled from 'styled-components';
import imgControls from './wndControls.svg';
import { remote } from 'electron';
import { ITitlebarProps } from './';
-import SystemMenu from 'containers/Main/Titlebar/SystemMenu';
+import SystemMenu from 'containers/Titlebar/SystemMenu';
const StyledControls = styled.div`
position: absolute;
diff --git a/src/app/components/Titlebar/SystemMenu.tsx b/src/app/components/Titlebar/SystemMenu.tsx
new file mode 100644
index 000000000..0411633fe
--- /dev/null
+++ b/src/app/components/Titlebar/SystemMenu.tsx
@@ -0,0 +1,73 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) EGAAS S.A. All rights reserved.
+ * See LICENSE in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+import React from 'react';
+import { remote } from 'electron';
+import { FormattedMessage } from 'react-intl';
+
+import themed from 'components/Theme/themed';
+import DropdownButton from 'components/Button/DropdownButton';
+import Heading from 'components/Dropdown/Heading';
+import Item from 'components/Dropdown/Item';
+
+const SystemDropdown = themed(DropdownButton)`
+ background: 0;
+ border: 0;
+ outline: 0;
+ color: #bad8ff;
+ width: ${props => props.theme.headerHeight}px !important;
+ height: ${props => props.theme.headerHeight}px !important;
+ padding: 0 !important;
+ margin: 0 !important;
+ outline: 0 !important;
+ min-width: 0 !important;
+ line-height: ${props => props.theme.headerHeight + 2}px !important;
+ transition: color ease-in-out .16s;
+ cursor: pointer !important;
+
+ &:hover {
+ color: #fff;
+ }
+`;
+
+export interface ISystemMenuProps {
+ align: 'left' | 'right';
+ onAbout: () => void;
+}
+
+const SystemMenu: React.SFC = props => {
+ const elements = [
+ (
+
+
+
+
+ -
+
+
+ - remote.getCurrentWindow().webContents.openDevTools({ mode: 'detach' })} icon="icon-calculator text-danger">
+
+
+
+ }
+ >
+
+
+ )
+ ];
+ return (
+
+ {(props.align === 'left' ? elements : elements.reverse()).map((e, i) => (
+ e
+ ))}
+
+ );
+};
+
+export default SystemMenu;
\ No newline at end of file
diff --git a/src/app/components/Main/Titlebar/WinTitlebar.tsx b/src/app/components/Titlebar/WinTitlebar.tsx
similarity index 97%
rename from src/app/components/Main/Titlebar/WinTitlebar.tsx
rename to src/app/components/Titlebar/WinTitlebar.tsx
index 52c9dbe8c..8b7dc0759 100644
--- a/src/app/components/Main/Titlebar/WinTitlebar.tsx
+++ b/src/app/components/Titlebar/WinTitlebar.tsx
@@ -3,13 +3,13 @@
* See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
-import * as React from 'react';
+import React from 'react';
import styled from 'styled-components';
import imgControls from './wndControls.svg';
import { remote } from 'electron';
import { ITitlebarProps } from './';
-import SystemMenu from 'containers/Main/Titlebar/SystemMenu';
+import SystemMenu from 'containers/Titlebar/SystemMenu';
const StyledControls = styled.div`
position: absolute;
diff --git a/src/app/components/Main/Titlebar/index.tsx b/src/app/components/Titlebar/index.tsx
similarity index 96%
rename from src/app/components/Main/Titlebar/index.tsx
rename to src/app/components/Titlebar/index.tsx
index 4b0e12970..126182e7f 100644
--- a/src/app/components/Main/Titlebar/index.tsx
+++ b/src/app/components/Titlebar/index.tsx
@@ -3,7 +3,7 @@
* See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
-import * as React from 'react';
+import React from 'react';
import styled from 'styled-components';
import platform from 'lib/platform';
@@ -13,6 +13,7 @@ export interface ITitlebarProps {
const StyledControls = styled.div`
position: relative;
+ z-index: 20000;
.window-title {
position: absolute;
diff --git a/src/app/components/Main/Titlebar/wndControls.svg b/src/app/components/Titlebar/wndControls.svg
similarity index 100%
rename from src/app/components/Main/Titlebar/wndControls.svg
rename to src/app/components/Titlebar/wndControls.svg
diff --git a/src/app/components/Tooltip/index.tsx b/src/app/components/Tooltip/index.tsx
index 2f8fc7e91..e763859ba 100644
--- a/src/app/components/Tooltip/index.tsx
+++ b/src/app/components/Tooltip/index.tsx
@@ -22,6 +22,7 @@ interface ITooltipState {
const StyledTooltip = themed.div`
position: absolute;
padding: 10px;
+ z-index: 700;
> div {
line-height: 16px;
diff --git a/src/app/components/Wrapper/index.tsx b/src/app/components/Wrapper/index.tsx
deleted file mode 100644
index b6c899513..000000000
--- a/src/app/components/Wrapper/index.tsx
+++ /dev/null
@@ -1,105 +0,0 @@
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) EGAAS S.A. All rights reserved.
- * See LICENSE in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import * as React from 'react';
-import { Link } from 'react-router-dom';
-import styled from 'styled-components';
-
-import LocalizedDocumentTitle from 'components/DocumentTitle/LocalizedDocumentTitle';
-import Heading from 'components/Heading';
-
-type TMixedContent =
- JSX.Element | string;
-
-export interface IWrapperProps {
- type: 'default' | 'fullscreen' | 'noscroll';
- title: { title: string, defaultTitle: string };
- heading?: {
- content: TMixedContent;
- toolButtons?: {
- url: string;
- icon: string;
- title: TMixedContent;
- }[];
- };
- description?: React.ReactNode;
- breadcrumbs?: IBreadcrumbProps[];
-}
-
-export interface IBreadcrumbProps {
- title: TMixedContent;
- url?: string;
-}
-
-const StyledDescription = styled.div`
- padding: 10px 20px;
- color: #84909e;
- border-bottom: 1px solid #cfdbe2;
-`;
-
-const StyledBreadcrumbs = styled.ul`
- padding: 10px 20px;
- color: #84909e;
- border-bottom: 1px solid #cfdbe2;
- list-style: none;
-`;
-
-const Breadcrumb: React.SFC = props => (
-
- {props.url ?
- (
- {props.title}
- ) : (
- {props.title}
- )
- }
-
-);
-
-const bodyClasses = {
- default: 'content-wrapper',
- fullscreen: 'fullscreen',
- noscroll: 'fullscreen-wrapper'
-};
-
-const Wrapper: React.SFC = props => (
-
-
- {props.heading && (
-
-
- {props.heading.toolButtons && props.heading.toolButtons.map((button, index) => (
-
-
- {button.title}
-
- ))}
-
- {props.heading.content}
-
- )}
-
- {props.description && (
-
- {props.description}
-
- )}
-
- {props.breadcrumbs && (
-
- {props.breadcrumbs.map((breadcrumb, index) => (
-
- ))}
-
- )}
-
-
- {props.children}
-
-
-
-);
-
-export default Wrapper;
\ No newline at end of file
diff --git a/src/app/containers/App.ts b/src/app/containers/App.ts
new file mode 100644
index 000000000..d7f772c31
--- /dev/null
+++ b/src/app/containers/App.ts
@@ -0,0 +1,31 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) EGAAS S.A. All rights reserved.
+ * See LICENSE in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+import { connect } from 'react-redux';
+import { IRootState } from 'modules';
+import { DragDropContext } from 'react-dnd';
+import { initialize } from 'modules/engine/actions';
+import HTML5Backend from 'react-dnd-html5-backend';
+
+import App from 'components/App';
+
+const mapStateToProps = (state: IRootState) => ({
+ locale: state.engine.locale || 'en-US',
+ localeMessages: state.engine.localeMessages,
+ isSessionAcquired: state.auth.isAcquired,
+ isAuthenticated: state.auth.isAuthenticated,
+ isLoaded: state.engine.isLoaded,
+ isFatal: !!state.engine.fatalError,
+ securityWarningClosed: state.storage.securityWarningClosed,
+ network: state.engine.guestSession && state.engine.guestSession.network
+});
+
+const mapDispatchToProps = {
+ initialize: initialize.started
+};
+
+export default DragDropContext(HTML5Backend)(
+ connect(mapStateToProps, mapDispatchToProps, null, { pure: false })(App)
+);
diff --git a/src/app/containers/App/index.tsx b/src/app/containers/App/index.tsx
deleted file mode 100644
index 0d984cd95..000000000
--- a/src/app/containers/App/index.tsx
+++ /dev/null
@@ -1,66 +0,0 @@
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) EGAAS S.A. All rights reserved.
- * See LICENSE in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import * as React from 'react';
-import { connect } from 'react-redux';
-import { IRootState } from 'modules';
-import { IntlProvider } from 'react-intl';
-import { DragDropContext } from 'react-dnd';
-import { switchWindow } from 'modules/gui/actions';
-import HTML5Backend from 'react-dnd-html5-backend';
-
-import App from 'components/App';
-import ThemeProvider from 'components/Theme/ThemeProvider';
-import baseTheme from 'components/Theme/baseTheme';
-
-export interface IAppContainerProps {
-}
-
-interface IAppContainerState {
- locale: string;
- isAuthenticated: boolean;
- isLoaded: boolean;
- isCollapsed: boolean;
- isFatal: boolean;
- localeMessages: { [key: string]: string };
- securityWarningClosed: boolean;
-}
-
-interface IAppContainerDispatch {
- switchWindow: typeof switchWindow.started;
-}
-
-const AppContainer: React.SFC = props => (
-
-
-
-
-
-);
-
-const mapStateToProps = (state: IRootState) => ({
- locale: state.engine.locale || 'en-US',
- localeMessages: state.engine.localeMessages,
- isAuthenticated: state.auth.isAuthenticated,
- isCollapsed: state.engine.isCollapsed,
- isLoaded: state.engine.isLoaded,
- isFatal: !!state.engine.fatalError,
- securityWarningClosed: state.storage.securityWarningClosed
-});
-
-const mapDispatchToProps = {
- switchWindow: switchWindow.started
-};
-
-export default DragDropContext(HTML5Backend)(
- connect(mapStateToProps, mapDispatchToProps, null, { pure: false })(AppContainer)
-);
diff --git a/src/app/containers/Auth/Wallet/Create.tsx b/src/app/containers/Auth/Wallet/Create.tsx
index ed668cd8c..9ad3e21e4 100644
--- a/src/app/containers/Auth/Wallet/Create.tsx
+++ b/src/app/containers/Auth/Wallet/Create.tsx
@@ -3,54 +3,23 @@
* See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
-import React from 'react';
import { connect } from 'react-redux';
import { IRootState } from 'modules';
-import { createWallet, importSeed, generateSeed, changeSeed, changeSeedConfirmation, importSeedConfirmation } from 'modules/auth/actions';
+import { createWallet } from 'modules/auth/actions';
import { ICreateWalletCall } from 'apla/auth';
import { sendAttachment } from 'modules/io/actions';
import Create from 'components/Auth/Wallet/Create';
-export interface ICreateContainerProps {
-
-}
-
-interface ICreateContainerState {
- seed: string;
- seedConfirm: string;
-}
-
-interface ICreateContainerDispatch {
- onImportSeed: () => void;
- onImportSeedConfirmation: () => void;
- onCreate: typeof createWallet.started;
- onGenerateSeed: () => void;
- onChangeSeed: (value: string) => void;
- onChangeSeedConfirmation: (value: string) => void;
- onDownloadSeed: (seed: string) => void;
-}
-
-const mapStateToProps = (state: IRootState) => ({
- seed: state.auth.seed,
- seedConfirm: state.auth.seedConfirm
+const mapStateToProps = (_state: IRootState) => ({
});
const mapDispatchToProps = {
onCreate: (params: ICreateWalletCall) => createWallet.started(params),
- onImportSeed: (file: File) => importSeed.started(file),
- onImportSeedConfirmation: (file: File) => importSeedConfirmation.started(file),
- onGenerateSeed: () => generateSeed.started(null),
- onChangeSeed: (value: string) => changeSeed(value),
- onChangeSeedConfirmation: (value: string) => changeSeedConfirmation(value),
onDownloadSeed: (seed: string) => sendAttachment({
name: 'seed.txt',
data: seed
})
};
-const CreateContainer: React.SFC = props => (
-
-);
-
-export default connect(mapStateToProps, mapDispatchToProps)(CreateContainer);
\ No newline at end of file
+export default connect(mapStateToProps, mapDispatchToProps)(Create);
\ No newline at end of file
diff --git a/src/app/containers/Auth/Wallet/Import.tsx b/src/app/containers/Auth/Wallet/Import.tsx
index d9dd1069a..80534a428 100644
--- a/src/app/containers/Auth/Wallet/Import.tsx
+++ b/src/app/containers/Auth/Wallet/Import.tsx
@@ -3,39 +3,17 @@
* See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
-import React from 'react';
import { connect } from 'react-redux';
import { IRootState } from 'modules';
-import { importSeed, importWallet } from 'modules/auth/actions';
+import { importWallet } from 'modules/auth/actions';
import Import from 'components/Auth/Wallet/Import';
-export interface IImportContainerProps {
-
-}
-
-interface IImportContainerState {
- backup: string;
- pending: boolean;
-}
-
-interface IImportContainerDispatch {
- onImportBackup: () => void;
- onConfirm: (params: { backup: string, password: string }) => void;
-}
-
-const mapStateToProps = (state: IRootState) => ({
- backup: state.auth.seed,
- pending: false
+const mapStateToProps = (_state: IRootState) => ({
});
const mapDispatchToProps = {
- onImportBackup: (file: File) => importSeed.started(file),
onConfirm: importWallet.started
};
-const ImportContainer: React.SFC = props => (
-
-);
-
-export default connect(mapStateToProps, mapDispatchToProps)(ImportContainer);
\ No newline at end of file
+export default connect(mapStateToProps, mapDispatchToProps)(Import);
\ No newline at end of file
diff --git a/src/app/containers/Auth/index.ts b/src/app/containers/Auth/index.ts
new file mode 100644
index 000000000..300b5cacd
--- /dev/null
+++ b/src/app/containers/Auth/index.ts
@@ -0,0 +1,23 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) EGAAS S.A. All rights reserved.
+ * See LICENSE in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+import { connect } from 'react-redux';
+import { IRootState } from 'modules';
+import { modalShow } from 'modules/modal/actions';
+
+import Auth from 'components/Auth';
+
+const mapStateToProps = (state: IRootState) => ({
+});
+
+const mapDispatchToProps = {
+ changeLocale: () => modalShow({
+ id: 'CHANGE_LOCALE',
+ type: 'CHANGE_LOCALE',
+ params: {}
+ })
+};
+
+export default connect(mapStateToProps, mapDispatchToProps)(Auth);
\ No newline at end of file
diff --git a/src/app/containers/Auth/index.tsx b/src/app/containers/Auth/index.tsx
deleted file mode 100644
index 3fbdf0dd8..000000000
--- a/src/app/containers/Auth/index.tsx
+++ /dev/null
@@ -1,48 +0,0 @@
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) EGAAS S.A. All rights reserved.
- * See LICENSE in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import React from 'react';
-import { connect } from 'react-redux';
-import { IRootState } from 'modules';
-import { modalShow } from 'modules/modal/actions';
-
-import Auth from 'components/Auth';
-
-export interface IAuthContainerProps {
-
-}
-
-interface IAuthContainerState {
- locale: string;
-}
-
-interface IAuthContainerDispatch {
- changeLocale: (locale: string) => void;
-}
-
-const mapStateToProps = (state: IRootState) => ({
- locale: state.storage.locale
-});
-
-const mapDispatchToProps = {
- changeLocale: (locale: string) => modalShow({
- id: 'CHANGE_LOCALE',
- type: 'CHANGE_LOCALE',
- params: {
- value: locale
- }
- })
-};
-
-const AuthContainer: React.SFC = props => {
- const changeLocale = () =>
- props.changeLocale(props.locale);
-
- return (
-
- );
-};
-
-export default connect(mapStateToProps, mapDispatchToProps)(AuthContainer);
\ No newline at end of file
diff --git a/src/app/containers/Button/TxButton.tsx b/src/app/containers/Button/TxButton.tsx
index 58f78be96..814fc9fe5 100644
--- a/src/app/containers/Button/TxButton.tsx
+++ b/src/app/containers/Button/TxButton.tsx
@@ -10,15 +10,23 @@ import { OrderedMap } from 'immutable';
import { IRootState } from 'modules';
import { connect } from 'react-redux';
import { buttonInteraction } from 'modules/content/actions';
+import { TBreadcrumbType } from 'apla/content';
+import { IErrorRedirect, IAction } from 'apla/protypo';
import Button from 'components/Button';
-import { IErrorRedirect } from 'apla/protypo';
export interface ITxButtonProps {
disabled?: boolean;
silent?: boolean;
className?: string;
+ actions: IAction[];
+ from?: {
+ type: TBreadcrumbType;
+ section: string;
+ name: string;
+ };
+
// Called first
confirm?: {
icon: string;
@@ -42,6 +50,7 @@ export interface ITxButtonProps {
// Redirect if all previous actions succeeded
page?: string;
+ section: string;
pageParams?: { [key: string]: any } | (() => { [key: string]: any });
// Page must be rendered within a modal dialog
@@ -100,11 +109,14 @@ class TxButton extends React.Component ({
- account: state.auth.wallet && state.auth.wallet.wallet,
- privateKey: state.auth.privateKey
-});
-
-export default connect(mapStateToProps, {
- onError: () => modalShow({
- id: 'E_INVALID_PASSWORD',
- type: 'AUTH_ERROR',
- params: {
- error: 'E_INVALID_PASSWORD'
- }
- }),
- onCopy: () => modalShow({
- id: 'I_COPIED',
- type: 'INFO',
- params: {
- value: ()
- }
- })
-})(Backup);
\ No newline at end of file
diff --git a/src/app/containers/Main/DefaultPage/index.tsx b/src/app/containers/Main/DefaultPage/index.tsx
deleted file mode 100644
index 55fbe6f4c..000000000
--- a/src/app/containers/Main/DefaultPage/index.tsx
+++ /dev/null
@@ -1,40 +0,0 @@
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) EGAAS S.A. All rights reserved.
- * See LICENSE in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import React from 'react';
-import { connect } from 'react-redux';
-import { IRootState } from 'modules';
-import { ecosystemInit } from 'modules/content/actions';
-
-export interface IDefaultPageContainerProps {
-}
-
-interface IDefaultPageContainerState {
-
-}
-
-interface IDefaultPageContainerDispatch {
- ecosystemInit: typeof ecosystemInit.started;
-}
-
-class DefaultPageContainer extends React.Component {
- componentDidMount() {
- this.props.ecosystemInit({});
- }
-
- render() {
- return null as JSX.Element;
- }
-}
-
-const mapStateToProps = (state: IRootState) => ({
-
-});
-
-const mapDispatchToProps = {
- ecosystemInit: ecosystemInit.started
-};
-
-export default connect(mapStateToProps, mapDispatchToProps)(DefaultPageContainer);
\ No newline at end of file
diff --git a/src/app/containers/Main/Editor/ConstructorTabbed.tsx b/src/app/containers/Main/Editor/ConstructorTabbed.tsx
index fd8bc783b..d39289b5e 100644
--- a/src/app/containers/Main/Editor/ConstructorTabbed.tsx
+++ b/src/app/containers/Main/Editor/ConstructorTabbed.tsx
@@ -13,6 +13,7 @@ import { generatePageTemplate } from 'modules/editor/actions';
import { IChangePageCall, TConstructorData, IAddTagCall, IOperateTagCall, IMoveTreeTag, ISetTagCanDropPositionCall } from 'apla/editor';
export interface IConstructorTabbedContainerProps {
+ section: string;
pageID: string;
pageName: string;
menus?: { id: string, name: string, conditions: string, value: string }[];
@@ -153,6 +154,7 @@ class ConstructorTabbedContainer extends React.Component {
- private _pendingClose: number;
-
- constructor(props: IEditorContainerProps & InjectedIntlProps & IEditorContainerState & IEditorContainerDispatch) {
- super(props);
-
- if (props.open && props.name) {
- props.onTabLoad({
- type: props.open,
- name: props.name
- });
- }
- else if (props.appId && props.create) {
- props.onTabCreate({
- type: props.create,
- appId: props.appId
- });
- }
- }
-
- componentWillReceiveProps(props: IEditorContainerProps & IEditorContainerState & IEditorContainerDispatch) {
- if ('number' === typeof this._pendingClose && props.modalResult) {
- if ('RESULT' === props.modalResult.reason) {
- this.props.onTabClose(this._pendingClose);
- }
-
- this._pendingClose = null;
- }
-
- if (props.open && props.name && (this.props.open !== props.open || this.props.name !== props.name)) {
- props.onTabLoad({
- type: props.open,
- name: props.name
- });
- }
-
- if (props.appId && props.create && (this.props.appId !== props.appId && this.props.create !== props.create)) {
- props.onTabCreate({
- type: props.create,
- appId: props.appId
- });
- }
- }
-
- onTabClose = (index: number) => {
- const tab = this.props.tabs[index];
-
- if (tab.dirty) {
- this._pendingClose = index;
- this.props.modalShow({
- id: 'EDITOR_CLOSE',
- type: 'CONFIRM',
- params: {
- description: this.props.intl.formatMessage({
- id: 'editor.close.confirm',
- defaultMessage: 'Do you really want to close \'{name}\' without saving changes?'
- }, { name: tab.name })
- }
- });
- }
- else {
- this.props.onTabClose(index);
- }
- }
-
- render() {
- return (
-
- );
- }
-}
-
const mapStateToProps = (state: IRootState) => ({
+ mainSection: state.sections.mainSection,
tabIndex: state.editor.tabIndex,
tabs: state.editor.tabs,
- modalResult: state.modal.result
});
const mapDispatchToProps = {
- modalShow: modalShow,
- onTabCreate: createEditorTab.started,
onTabLoad: loadEditorTab.started,
- onTabChange: changeEditorTab,
- onTabClose: closeEditorTab,
- onTabCloseAll: closeAllEditorTab,
- onTabCloseSaved: closeSavedEditorTab,
+ onTabChange: (uuid: string) => changeEditorTab(uuid),
+ onTabClose: (uuid: string) => closeEditorTab(uuid),
+ onTabCloseAll: () => modalShow({
+ id: 'EDITOR_CLOSE_ALL',
+ type: 'EDITOR_CLOSE_ALL',
+ params: {}
+ }),
+ onTabCloseSaved: () => closeSavedEditorTab(),
onTabUpdate: updateEditorTab,
};
-export default connect(mapStateToProps, mapDispatchToProps)(injectIntl(EditorContainer));
\ No newline at end of file
+export default connect(mapStateToProps, mapDispatchToProps)(Editor);
\ No newline at end of file
diff --git a/src/app/containers/Main/Header/LangMenu.ts b/src/app/containers/Main/Header/LangMenu.ts
new file mode 100644
index 000000000..266cbdd79
--- /dev/null
+++ b/src/app/containers/Main/Header/LangMenu.ts
@@ -0,0 +1,20 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) EGAAS S.A. All rights reserved.
+ * See LICENSE in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+import { IRootState } from 'modules';
+import { connect } from 'react-redux';
+import { setLocale } from 'modules/engine/actions';
+
+import LangMenu from 'components/Main/Header/LangMenu';
+
+const mapStateToProps = (state: IRootState) => ({
+ locale: state.engine.locale,
+ locales: state.engine.locales
+});
+
+export default connect(mapStateToProps, {
+ onChange: setLocale.started
+
+})(LangMenu);
\ No newline at end of file
diff --git a/src/app/containers/Main/Header/NotificationsMenu.ts b/src/app/containers/Main/Header/NotificationsMenu.ts
new file mode 100644
index 000000000..a4912821e
--- /dev/null
+++ b/src/app/containers/Main/Header/NotificationsMenu.ts
@@ -0,0 +1,19 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) EGAAS S.A. All rights reserved.
+ * See LICENSE in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+import { connect } from 'react-redux';
+import { IRootState } from 'modules';
+
+import NotificationsMenu from 'components/Main/Header/NotificationsMenu';
+import findNotificationsCount from 'modules/socket/util/findNotificationsCount';
+
+const mapStateToProps = (state: IRootState) => ({
+ count: findNotificationsCount(state.socket, state.auth.wallet),
+ offline: !state.socket.connected,
+ mainSection: state.sections.mainSection,
+ notificationsBody: state.content.notifications
+});
+
+export default connect(mapStateToProps)(NotificationsMenu);
\ No newline at end of file
diff --git a/src/app/containers/Widgets/UserMenu/index.tsx b/src/app/containers/Main/Header/UserMenu.ts
similarity index 87%
rename from src/app/containers/Widgets/UserMenu/index.tsx
rename to src/app/containers/Main/Header/UserMenu.ts
index f7a934f6b..faa0a6633 100644
--- a/src/app/containers/Widgets/UserMenu/index.tsx
+++ b/src/app/containers/Main/Header/UserMenu.ts
@@ -5,10 +5,10 @@
import { IRootState } from 'modules';
import { connect } from 'react-redux';
-import { logout, changePassword, switchWallet } from 'modules/auth/actions';
+import { logout, changePassword, switchWallet, backupAccount } from 'modules/auth/actions';
import { modalShow } from 'modules/modal/actions';
-import UserMenu from 'components/Main/UserMenu';
+import UserMenu from 'components/Main/Header/UserMenu';
const mapStateToProps = (state: IRootState) => ({
isDefaultWallet: state.auth.isDefaultWallet,
@@ -30,6 +30,7 @@ export default connect(mapStateToProps, {
ecosystem
}
}),
+ onBackup: () => backupAccount(),
onChangePassword: () => changePassword.started(null)
})(UserMenu);
\ No newline at end of file
diff --git a/src/app/modules/engine/reducers/setCollapsedHandler.ts b/src/app/containers/Main/Header/index.ts
similarity index 52%
rename from src/app/modules/engine/reducers/setCollapsedHandler.ts
rename to src/app/containers/Main/Header/index.ts
index aae00714c..695b73f15 100644
--- a/src/app/modules/engine/reducers/setCollapsedHandler.ts
+++ b/src/app/containers/Main/Header/index.ts
@@ -3,13 +3,13 @@
* See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
-import { State } from '../reducer';
-import { setCollapsed } from '../actions';
-import { Reducer } from 'modules';
+import { connect } from 'react-redux';
+import { IRootState } from 'modules';
-const setCollapsedHandler: Reducer = (state, payload) => ({
- ...state,
- isCollapsed: payload
+import Header from 'components/Main/Header';
+
+const mapStateToProps = (state: IRootState) => ({
+ isAuthorized: !!state.auth.privateKey
});
-export default setCollapsedHandler;
\ No newline at end of file
+export default connect(mapStateToProps)(Header);
\ No newline at end of file
diff --git a/src/app/containers/Main/Navigation/ResizeHandle.tsx b/src/app/containers/Main/Navigation/ResizeHandle.tsx
deleted file mode 100644
index 2e35c2bc0..000000000
--- a/src/app/containers/Main/Navigation/ResizeHandle.tsx
+++ /dev/null
@@ -1,47 +0,0 @@
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) EGAAS S.A. All rights reserved.
- * See LICENSE in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import * as React from 'react';
-import { connect } from 'react-redux';
-import { IRootState } from 'modules';
-import { setResizing } from 'modules/content/actions';
-import { navigationToggle } from 'modules/sections/actions';
-import { saveNavigationSize } from 'modules/storage/actions';
-
-import ResizeHandle from 'components/Main/Navigation/ResizeHandle';
-
-interface IResizeHandleContainerProps {
-
-}
-
-interface IResizeHandleContainerState {
- width: number;
- resizing: boolean;
- disabled: boolean;
-}
-
-interface IResizeHandleContainerDispatch {
- setResizing: typeof setResizing;
- navigationResize: typeof saveNavigationSize;
- navigationToggle: typeof navigationToggle;
-}
-
-const ResizeHandleContainer: React.SFC = (props) => (
-
-);
-
-const mapStateToProps = (state: IRootState) => ({
- width: state.storage.navigationSize,
- resizing: state.content.navigationResizing,
- disabled: !state.engine.isCollapsed
-});
-
-const mapDispatchToProps = {
- setResizing,
- navigationResize: saveNavigationSize,
- navigationToggle
-};
-
-export default connect(mapStateToProps, mapDispatchToProps)(ResizeHandleContainer);
\ No newline at end of file
diff --git a/src/app/containers/Main/Navigation/index.tsx b/src/app/containers/Main/Navigation/index.tsx
deleted file mode 100644
index a644b64eb..000000000
--- a/src/app/containers/Main/Navigation/index.tsx
+++ /dev/null
@@ -1,58 +0,0 @@
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) EGAAS S.A. All rights reserved.
- * See LICENSE in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import * as React from 'react';
-import { connect } from 'react-redux';
-import { IRootState } from 'modules';
-import { ecosystemInit } from 'modules/content/actions';
-import { menuPop, menuPush } from 'modules/sections/actions';
-import { TMenu } from 'apla/content';
-
-import Navigation from 'components/Main/Navigation';
-
-interface INavigationContainerProps {
-
-}
-
-interface INavigationContainerState {
- preloading: boolean;
- preloadingError: string;
- visible: boolean;
- width: number;
- menus: TMenu[];
-}
-
-interface INavigationContainerDispatch {
- menuPop: typeof menuPop;
- menuPush: typeof menuPush;
- ecosystemInit: typeof ecosystemInit.started;
-}
-
-const NavigationContainer: React.SFC = (props) => (
-
-);
-
-const mapStateToProps = (state: IRootState) => {
- const section = state.sections.sections[state.sections.section] || state.sections.sections.home;
- return {
- preloading: state.content.preloading,
- preloadingError: state.content.preloadingError,
- visible: state.sections.sections[state.sections.section] && (
- state.sections.sections[state.sections.section].menuDisabled ?
- false :
- state.sections.sections[state.sections.section].menuVisible
- ),
- width: state.storage.navigationSize,
- menus: section ? section.menus : []
- };
-};
-
-const mapDispatchToProps = {
- menuPop,
- menuPush,
- ecosystemInit: ecosystemInit.started
-};
-
-export default connect(mapStateToProps, mapDispatchToProps)(NavigationContainer);
\ No newline at end of file
diff --git a/src/app/containers/Main/Navigator/Menu/ResizeHandle.ts b/src/app/containers/Main/Navigator/Menu/ResizeHandle.ts
new file mode 100644
index 000000000..d8e3ad2ae
--- /dev/null
+++ b/src/app/containers/Main/Navigator/Menu/ResizeHandle.ts
@@ -0,0 +1,22 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) EGAAS S.A. All rights reserved.
+ * See LICENSE in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+import { connect } from 'react-redux';
+import { IRootState } from 'modules';
+import { setMenuFolded } from 'modules/storage/actions';
+
+import ResizeHandle from 'components/Main/Navigator/Menu/ResizeHandle';
+
+const mapStateToProps = (state: IRootState) => ({
+ folded: state.storage.menuFolded
+});
+
+const mapDispatchToProps = {
+ setMenuFolded
+};
+
+export default connect(mapStateToProps, mapDispatchToProps, (state, dispatch: any) => ({
+ onFoldToggle: () => dispatch.setMenuFolded(!state.folded)
+}))(ResizeHandle);
\ No newline at end of file
diff --git a/src/app/containers/Main/Navigator/Menu/index.ts b/src/app/containers/Main/Navigator/Menu/index.ts
new file mode 100644
index 000000000..42a9709c0
--- /dev/null
+++ b/src/app/containers/Main/Navigator/Menu/index.ts
@@ -0,0 +1,45 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) EGAAS S.A. All rights reserved.
+ * See LICENSE in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+import { connect } from 'react-redux';
+import { IRootState } from 'modules';
+import { menuPop } from 'modules/sections/actions';
+import { setMenuActive } from 'modules/content/actions';
+
+import Menu from 'components/Main/Navigator/Menu';
+
+export interface INavigationProps {
+ section: string;
+}
+
+const mapStateToProps = (state: IRootState, props: INavigationProps) => {
+ const section = state.sections.sections[props.section];
+ return {
+ menus: section ? section.menus : [],
+ folded: state.storage.menuFolded,
+ active: state.content.menuActive
+ };
+};
+
+const mapDispatchToProps = {
+ menuPop,
+ setMenuActive
+};
+
+export default connect(mapStateToProps, mapDispatchToProps, (state, dispatch: any, props) => ({
+ ...state,
+ ...props,
+ menuPop: () => dispatch.menuPop(props.section),
+ onMouseOver: () => {
+ if (state.folded && !state.active) {
+ dispatch.setMenuActive(true);
+ }
+ },
+ onMouseLeave: () => {
+ if (state.folded && state.active) {
+ dispatch.setMenuActive(false);
+ }
+ }
+}))(Menu);
\ No newline at end of file
diff --git a/src/app/containers/Main/Navigator/Sections/Selector.ts b/src/app/containers/Main/Navigator/Sections/Selector.ts
new file mode 100644
index 000000000..4d242d13d
--- /dev/null
+++ b/src/app/containers/Main/Navigator/Sections/Selector.ts
@@ -0,0 +1,31 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) EGAAS S.A. All rights reserved.
+ * See LICENSE in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+import _ from 'lodash';
+import { connect } from 'react-redux';
+import { IRootState } from 'modules';
+import { ISection, TPageParams } from 'apla/content';
+
+import Selector from 'components/Main/Navigator/Sections/Selector';
+
+const mapSectionParam = (section: ISection) => {
+ const page = section.page ? section.page.name : section.defaultPage;
+ const params: TPageParams = section.page ? section.page.params : {};
+
+ return {
+ index: section.index,
+ title: section.title,
+ name: section.name,
+ page,
+ params
+ };
+};
+
+const mapStateToProps = (state: IRootState, props: { section?: string }) => ({
+ section: null === props.section ? null : (props.section || state.sections.mainSection),
+ values: _.map(state.sections.sections, mapSectionParam).sort((a, b) => a.index - b.index)
+});
+
+export default connect(mapStateToProps)(Selector);
\ No newline at end of file
diff --git a/src/app/containers/Main/Navigator/Sections/index.ts b/src/app/containers/Main/Navigator/Sections/index.ts
new file mode 100644
index 000000000..7ba9eab2d
--- /dev/null
+++ b/src/app/containers/Main/Navigator/Sections/index.ts
@@ -0,0 +1,21 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) EGAAS S.A. All rights reserved.
+ * See LICENSE in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+import { connect } from 'react-redux';
+import { IRootState } from 'modules';
+import { menuPop } from 'modules/sections/actions';
+
+import Sections from 'components/Main/Navigator/Sections';
+
+const mapStateToProps = (state: IRootState) => ({
+ folded: state.storage.menuFolded,
+ menuActive: state.content.menuActive
+});
+
+const mapDispatchToProps = {
+ menuPop: menuPop
+};
+
+export default connect(mapStateToProps, mapDispatchToProps)(Sections);
\ No newline at end of file
diff --git a/src/app/containers/Main/Navigator/index.ts b/src/app/containers/Main/Navigator/index.ts
new file mode 100644
index 000000000..18e65d1e4
--- /dev/null
+++ b/src/app/containers/Main/Navigator/index.ts
@@ -0,0 +1,38 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) EGAAS S.A. All rights reserved.
+ * See LICENSE in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+import { connect } from 'react-redux';
+import { IRootState } from 'modules';
+import { reloadPage } from 'modules/sections/actions';
+
+import Navigator from 'components/Main/Navigator';
+
+interface Props {
+ section?: string;
+ page?: string;
+}
+
+const mapStateToProps = (state: IRootState, props: Props) => {
+ const sectionName = props.section || state.sections.mainSection;
+ const section = state.sections.sections[sectionName];
+ const defaultPage = section ? section.defaultPage : '';
+ const page = props.page || defaultPage;
+
+ return {
+ stylesheet: state.content.stylesheet,
+ section: sectionName,
+ sections: state.sections.sections,
+ page
+ };
+};
+
+const mapDispatchToProps = {
+ reloadPage
+};
+
+export default connect(mapStateToProps, mapDispatchToProps, (state, dispatch: any, props) => ({
+ ...state,
+ onRefresh: () => dispatch.reloadPage({ section: props.section })
+}))(Navigator);
\ No newline at end of file
diff --git a/src/app/containers/Main/Page/index.tsx b/src/app/containers/Main/Page/index.tsx
deleted file mode 100644
index d74ac0386..000000000
--- a/src/app/containers/Main/Page/index.tsx
+++ /dev/null
@@ -1,138 +0,0 @@
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) EGAAS S.A. All rights reserved.
- * See LICENSE in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import * as React from 'react';
-import * as _ from 'lodash';
-import * as queryString from 'query-string';
-import { connect } from 'react-redux';
-import { IRootState } from 'modules';
-import { ecosystemInit } from 'modules/content/actions';
-import { renderPage, renderLegacyPage, navigatePage, switchSection } from 'modules/sections/actions';
-import { TSection } from 'apla/content';
-import { LEGACY_PAGES } from 'lib/legacyPages';
-
-import Page from 'components/Main/Page';
-import NotFound from 'components/Main/Page/NotFound';
-
-export interface IPageContainerProps {
- match?: { params: { [key: string]: string } };
- location?: {
- key: string;
- search: string;
- };
-}
-
-interface IPageContainerState {
- initialized: boolean;
- section: string;
- sections: {
- [name: string]: TSection;
- };
-}
-
-interface IPageContainerDispatch {
- navigatePage: typeof navigatePage.started;
- renderPage: typeof renderPage.started;
- renderLegacyPage: typeof renderLegacyPage.started;
- switchSection: typeof switchSection;
- ecosystemInit: typeof ecosystemInit.started;
-}
-
-class PageContainer extends React.Component {
- componentDidMount() {
- if (!this.props.initialized) {
- this.props.ecosystemInit({
- section: this.props.match.params.section
- });
- }
- }
-
- componentWillReceiveProps(props: IPageContainerProps & IPageContainerState & IPageContainerDispatch) {
- if (!props.initialized) {
- return;
- }
-
- if (props.section !== props.match.params.section && this.props.match.params.section !== props.match.params.section) {
- this.props.switchSection(props.match.params.section);
- }
- else {
- this.renderPage(props);
- }
- }
-
- renderPage(props: IPageContainerProps & IPageContainerState & IPageContainerDispatch) {
- const section = props.sections[props.match.params.section];
- const isPending = section ? section.pending : false;
- const requestPage = (props.match.params.pageName || (section && section.defaultPage));
- const params = queryString.parse(props.location.search);
-
- if (!isPending && section) {
- if (!section.page || section.page.name !== requestPage || section.force || this.props.location.search !== props.location.search) {
- const legacyPage = LEGACY_PAGES[requestPage];
-
- if (legacyPage && (!legacyPage.section || section.name === legacyPage.section)) {
- props.renderLegacyPage({
- section: legacyPage.section || section.name,
- name: requestPage,
- menu: legacyPage.menu,
- params
- });
- }
- else {
- props.renderPage({
- key: props.location.key,
- section: section.name,
- name: requestPage,
- params
- });
- }
- }
- }
- }
-
- render() {
- return (
-
- {this.props.initialized && !this.props.sections[this.props.match.params.section] && (
-
- )}
- {_.map(this.props.sections, section => {
- const isLegacy = section.page && section.page.legacy;
- const legacyPage = isLegacy ? LEGACY_PAGES[section.page.name] : null;
-
- return (
-
- {isLegacy ? legacyPage.render({ ...section.page.params, children: section.page && section.page.content }) : (
-
- )}
-
- );
- })}
-
- );
- }
-}
-
-const mapStateToProps = (state: IRootState) => ({
- initialized: state.sections.inited,
- section: state.sections.section,
- sections: state.sections.sections
-});
-
-const mapDispatchToProps = {
- navigatePage: navigatePage.started,
- renderPage: renderPage.started,
- renderLegacyPage: renderLegacyPage.started,
- ecosystemInit: ecosystemInit.started,
- switchSection
-};
-
-export default connect(mapStateToProps, mapDispatchToProps)(PageContainer);
\ No newline at end of file
diff --git a/src/app/containers/Main/Titlebar/SystemMenu.tsx b/src/app/containers/Main/Titlebar/SystemMenu.tsx
deleted file mode 100644
index 1f949a1eb..000000000
--- a/src/app/containers/Main/Titlebar/SystemMenu.tsx
+++ /dev/null
@@ -1,57 +0,0 @@
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) EGAAS S.A. All rights reserved.
- * See LICENSE in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import React from 'react';
-import { IRootState } from 'modules';
-import { connect } from 'react-redux';
-import { modalShow } from 'modules/modal/actions';
-
-import SystemMenu from 'components/Main/Titlebar/SystemMenu';
-
-export interface ISystemMenuContainerProps {
- align: 'left' | 'right';
-}
-
-interface ISystemMenuContainerState {
- locale: string;
-}
-
-interface ISystemMenuContainerDispatch {
- modalShow: typeof modalShow;
-}
-
-const SystemMenuContainer: React.SFC = (props) => {
- const onAbout = () => {
- props.modalShow({
- id: 'ABOUT',
- type: 'ABOUT',
- params: {}
- });
- };
-
- const onChangeLocale = () => {
- props.modalShow({
- id: 'CHANGE_LOCALE',
- type: 'CHANGE_LOCALE',
- params: {
- value: props.locale
- }
- });
- };
-
- return (
-
- );
-};
-
-const mapStateToProps = (state: IRootState) => ({
- locale: state.storage.locale
-});
-
-const mapDispatchToProps = {
- modalShow: modalShow
-};
-
-export default connect(mapStateToProps, mapDispatchToProps)(SystemMenuContainer);
\ No newline at end of file
diff --git a/src/app/containers/Main/Toolbar/EditorToolbar.tsx b/src/app/containers/Main/Toolbar/EditorToolbar.tsx
deleted file mode 100644
index 3db0fd892..000000000
--- a/src/app/containers/Main/Toolbar/EditorToolbar.tsx
+++ /dev/null
@@ -1,110 +0,0 @@
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) EGAAS S.A. All rights reserved.
- * See LICENSE in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import * as React from 'react';
-import { IRootState } from 'modules';
-import { connect } from 'react-redux';
-import { modalShow } from 'modules/modal/actions';
-import { editorSave, revertEditorTab, changeEditorTool, debugContract } from 'modules/editor/actions';
-import { IModalResult } from 'apla/modal';
-import { TEditorTab } from 'apla/editor';
-import { injectIntl, InjectedIntlProps } from 'react-intl';
-
-import EditorToolbar from 'components/Main/Toolbar/EditorToolbar';
-
-export interface IEditorToolbarProps {
-
-}
-
-interface IEditorToolbarState {
- modalResult: IModalResult;
- currentTab: TEditorTab;
- currentTabIndex: number;
- canSave: boolean;
- canRevert: boolean;
-}
-
-interface IEditorToolbarDispatch {
- modalShow: typeof modalShow;
- changeEditorTool: typeof changeEditorTool.started;
- revertEditorTab: typeof revertEditorTab;
- editorSave: typeof editorSave;
- onExec: typeof debugContract;
-}
-
-class EditorToolbarContainer extends React.Component {
- private _pendingRevert: number;
-
- onRevert = () => {
- this._pendingRevert = this.props.currentTabIndex;
- this.props.modalShow({
- id: 'EDITOR_REVERT',
- type: 'CONFIRM',
- params: {
- description: this.props.intl.formatMessage({
- id: 'editor.revert.confirm',
- defaultMessage: 'Do you really want to discard all changes?'
- })
- }
- });
- }
-
- onSave = () => {
- if (this.props.currentTab) {
- this.props.editorSave(this.props.currentTab);
- }
- }
-
- onExec = () => {
- this.props.onExec(this.props.currentTab.name);
- }
-
- componentWillReceiveProps(props: IEditorToolbarProps & IEditorToolbarState & IEditorToolbarDispatch) {
- if ('number' === typeof this._pendingRevert && props.modalResult) {
- if ('RESULT' === props.modalResult.reason) {
- this.props.revertEditorTab(this._pendingRevert);
- }
- this._pendingRevert = null;
- }
- }
-
- render() {
- return (
-
- );
- }
-}
-
-const mapStateToProps = (state: IRootState) => {
- const currentTab = state.editor.tabs[state.editor.tabIndex];
-
- return {
- currentTab,
- currentTabIndex: state.editor.tabIndex,
- modalResult: state.modal.result,
- canSave: !state.editor.pending &&
- currentTab && currentTab.dirty,
- canRevert: !state.editor.pending &&
- currentTab && (currentTab.dirty && null !== currentTab.initialValue)
- };
-};
-
-const mapDispatchToProps = {
- modalShow: modalShow,
- onExec: debugContract,
- revertEditorTab: revertEditorTab,
- changeEditorTool: changeEditorTool.started,
- editorSave
-};
-
-export default connect(mapStateToProps, mapDispatchToProps)(injectIntl(EditorToolbarContainer));
\ No newline at end of file
diff --git a/src/app/containers/Main/index.tsx b/src/app/containers/Main/index.tsx
deleted file mode 100644
index d887f104b..000000000
--- a/src/app/containers/Main/index.tsx
+++ /dev/null
@@ -1,61 +0,0 @@
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) EGAAS S.A. All rights reserved.
- * See LICENSE in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import React from 'react';
-import { connect, Dispatch } from 'react-redux';
-import { Route } from 'react-router-dom';
-import { IRootState } from 'modules';
-import { reloadPage, navigationToggle, renderSection, navigatePage, closeSection } from '../../modules/sections/actions';
-
-import { AnimatedSwitch } from 'components/Animation';
-import Main, { IMainProps } from 'components/Main';
-import DefaultPage from 'containers/Main/DefaultPage';
-import Page from 'containers/Main/Page';
-import NotFound from 'components/NotFound';
-
-const MainContainer: React.SFC = props => (
-
-
-
-
- } />
-
-
-);
-
-const mapStateToProps = (state: IRootState) => ({
- network: state.auth.session && state.auth.session.network,
- isAuthorized: !!state.auth.privateKey,
- stylesheet: state.content.stylesheet,
- section: state.sections.section,
- sections: state.sections.sections,
- navigationSize: state.storage.navigationSize,
- navigationVisible: state.sections.sections[state.sections.section] &&
- (state.sections.sections[state.sections.section].menuDisabled ?
- false :
- state.sections.sections[state.sections.section].menuVisible
- ),
- transactionsCount: state.tx.transactions.count()
-});
-
-const mapDispatchToProps = (dispatch: Dispatch) => ({
- onNavigationToggle: () => {
- dispatch(navigationToggle());
- },
- onNavigateHome: () => {
- dispatch(navigatePage.started({ params: {} }));
- },
- onRefresh: (section: string) => {
- dispatch(reloadPage.started({}));
- },
- onSwitchSection: (section: string) => {
- dispatch(renderSection(section));
- },
- onCloseSection: (section: string) => {
- dispatch(closeSection(section));
- }
-});
-
-export default connect(mapStateToProps, mapDispatchToProps)(MainContainer);
\ No newline at end of file
diff --git a/src/app/containers/Modal/BackupModal.tsx b/src/app/containers/Modal/BackupModal.tsx
new file mode 100644
index 000000000..944eb6263
--- /dev/null
+++ b/src/app/containers/Modal/BackupModal.tsx
@@ -0,0 +1,36 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) EGAAS S.A. All rights reserved.
+ * See LICENSE in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+import React from 'react';
+import { connect } from 'react-redux';
+import { IRootState } from 'modules';
+import { IModalProps } from 'components/Modal';
+import { FormattedMessage } from 'react-intl';
+import { modalShow } from 'modules/modal/actions';
+
+import BackupModal from 'components/Modal/BackupModal';
+
+const mapStateToProps = (state: IRootState) => ({
+ privateKey: state.auth.privateKey,
+ publicKey: state.auth.wallet.wallet.publicKey,
+ address: state.auth.wallet.wallet.address
+});
+
+export default connect(mapStateToProps, {
+ modalShow
+
+}, (state, dispatch: any, props: IModalProps) => ({
+ ...props,
+ params: {
+ ...state,
+ onCopy: () => dispatch.modalShow({
+ id: 'I_COPIED',
+ type: 'INFO',
+ params: {
+ value: ()
+ }
+ })
+ },
+}))(BackupModal);
\ No newline at end of file
diff --git a/src/app/containers/Modal/ChangeLocaleModal.tsx b/src/app/containers/Modal/ChangeLocaleModal.ts
similarity index 66%
rename from src/app/containers/Modal/ChangeLocaleModal.tsx
rename to src/app/containers/Modal/ChangeLocaleModal.ts
index 24f5d6e76..25d30a39f 100644
--- a/src/app/containers/Modal/ChangeLocaleModal.tsx
+++ b/src/app/containers/Modal/ChangeLocaleModal.ts
@@ -8,20 +8,23 @@ import { IRootState } from 'modules';
import { IModalProps } from 'components/Modal';
import { setLocale } from 'modules/engine/actions';
-import ChangeLocaleModal, { IChangeLocaleModalProps } from 'components/Modal/ChangeLocale';
+import ChangeLocaleModal from 'components/Modal/ChangeLocaleModal';
-const mapStateToProps = (state: IRootState, props: IModalProps) => ({
+const mapStateToProps = (state: IRootState) => ({
+ value: state.engine.locale,
locales: state.engine.locales
});
export default connect(mapStateToProps, {
setLocale: setLocale.started
-}, (state, dispatch: any, props) => ({
+}, (state, dispatch: any, props: IModalProps) => ({
...props,
params: {
+ ...state,
...props.params,
- locales: state.locales,
- onChangeLocale: dispatch.setLocale
- }
+ onChangeLocale: (locale: string) => {
+ dispatch.setLocale(locale);
+ }
+ },
}))(ChangeLocaleModal);
\ No newline at end of file
diff --git a/src/app/containers/Modal/EditorCloseAllModal.ts b/src/app/containers/Modal/EditorCloseAllModal.ts
new file mode 100644
index 000000000..3bc514a77
--- /dev/null
+++ b/src/app/containers/Modal/EditorCloseAllModal.ts
@@ -0,0 +1,31 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) EGAAS S.A. All rights reserved.
+ * See LICENSE in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+import { connect } from 'react-redux';
+import { IRootState } from 'modules';
+import { modalClose } from 'modules/modal/actions';
+import { closeAllEditorTabs } from 'modules/editor/actions';
+import { IModalProps } from 'components/Modal';
+
+import EditorCloseAllModal from 'components/Modal/EditorCloseAllModal';
+
+const mapStateToProps = (state: IRootState) => ({
+});
+
+export default connect(mapStateToProps, {
+ modalClose,
+ closeAllEditorTabs
+
+}, (_state, dispatch: any, props: IModalProps) => ({
+ ...props,
+ onResult: (_data: void) => {
+ dispatch.modalClose({
+ reason: 'RESULT',
+ data: null
+ });
+
+ dispatch.closeAllEditorTabs();
+ }
+}))(EditorCloseAllModal);
\ No newline at end of file
diff --git a/src/app/containers/Modal/EditorCloseModal.ts b/src/app/containers/Modal/EditorCloseModal.ts
new file mode 100644
index 000000000..059bd6d4a
--- /dev/null
+++ b/src/app/containers/Modal/EditorCloseModal.ts
@@ -0,0 +1,42 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) EGAAS S.A. All rights reserved.
+ * See LICENSE in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+import { connect } from 'react-redux';
+import { IRootState } from 'modules';
+import { modalClose } from 'modules/modal/actions';
+import { destroyEditorTab } from 'modules/editor/actions';
+import { IModalProps } from 'components/Modal';
+
+import EditorCloseModal from 'components/Modal/EditorCloseModal';
+
+interface Props {
+ uuid: string;
+}
+
+const mapStateToProps = (state: IRootState, props: IModalProps) => {
+ const tab = state.editor.tabs.find(t => t.uuid === props.params.uuid);
+ return {
+ name: tab ? tab.name : ''
+ };
+};
+
+export default connect(mapStateToProps, {
+ modalClose,
+ destroyEditorTab
+
+}, (state, dispatch: any, props: IModalProps) => ({
+ ...props,
+ params: {
+ ...state
+ },
+ onResult: (_data: void) => {
+ dispatch.modalClose({
+ reason: 'RESULT',
+ data: null
+ });
+
+ dispatch.destroyEditorTab(props.params.uuid);
+ }
+}))(EditorCloseModal);
\ No newline at end of file
diff --git a/src/app/containers/Modal/EditorRevertModal.ts b/src/app/containers/Modal/EditorRevertModal.ts
new file mode 100644
index 000000000..f1eaf0d51
--- /dev/null
+++ b/src/app/containers/Modal/EditorRevertModal.ts
@@ -0,0 +1,42 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) EGAAS S.A. All rights reserved.
+ * See LICENSE in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+import { connect } from 'react-redux';
+import { IRootState } from 'modules';
+import { modalClose } from 'modules/modal/actions';
+import { resetEditorTab } from 'modules/editor/actions';
+import { IModalProps } from 'components/Modal';
+
+import EditorRevertModal from 'components/Modal/EditorRevertModal';
+
+interface Props {
+ uuid: string;
+}
+
+const mapStateToProps = (state: IRootState, props: IModalProps) => {
+ const tab = state.editor.tabs.find(t => t.uuid === props.params.uuid);
+ return {
+ name: tab ? tab.name : ''
+ };
+};
+
+export default connect(mapStateToProps, {
+ modalClose,
+ resetEditorTab
+
+}, (state, dispatch: any, props: IModalProps) => ({
+ ...props,
+ params: {
+ ...state
+ },
+ onResult: (_data: void) => {
+ dispatch.modalClose({
+ reason: 'RESULT',
+ data: null
+ });
+
+ dispatch.resetEditorTab(props.params.uuid);
+ }
+}))(EditorRevertModal);
\ No newline at end of file
diff --git a/src/app/containers/Modal/Header.ts b/src/app/containers/Modal/Header.ts
new file mode 100644
index 000000000..6a70eeb60
--- /dev/null
+++ b/src/app/containers/Modal/Header.ts
@@ -0,0 +1,23 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) EGAAS S.A. All rights reserved.
+ * See LICENSE in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+import { connect } from 'react-redux';
+import { IRootState } from 'modules';
+import { modalClose } from 'modules/modal/actions';
+
+import Header from 'components/Modal/Header';
+
+const mapStateToProps = (state: IRootState) => ({
+
+});
+
+const mapDispatchToProps = {
+ onClose: () => modalClose({
+ reason: 'CANCEL',
+ data: null
+ })
+};
+
+export default connect<{}, { onClose: () => void }, {}>(mapStateToProps, mapDispatchToProps)(Header);
\ No newline at end of file
diff --git a/src/app/containers/Modal/RolePickerModal.tsx b/src/app/containers/Modal/RolePickerModal.tsx
index 2ae183b60..ec21f2d53 100644
--- a/src/app/containers/Modal/RolePickerModal.tsx
+++ b/src/app/containers/Modal/RolePickerModal.tsx
@@ -7,9 +7,9 @@ import { connect } from 'react-redux';
import { IRootState } from 'modules';
import { IModalProps } from 'components/Modal';
import { switchWallet } from 'modules/auth/actions';
+import { modalClose } from 'modules/modal/actions';
import RolePickerModal from 'components/Modal/RolePickerModal';
-import { modalClose } from 'modules/modal/actions';
export interface IRolePickerModalProps {
account: string;
diff --git a/src/app/containers/Routing/PageLink.ts b/src/app/containers/Routing/PageLink.ts
new file mode 100644
index 000000000..4c2aa0e64
--- /dev/null
+++ b/src/app/containers/Routing/PageLink.ts
@@ -0,0 +1,19 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) EGAAS S.A. All rights reserved.
+ * See LICENSE in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+import { connect } from 'react-redux';
+import { IRootState } from 'modules';
+
+import PageLink from 'components/Routing/PageLink';
+
+interface Props {
+ section?: string;
+}
+
+const mapStateToProps = (state: IRootState, props: Props) => ({
+ section: props.section || state.sections.mainSection
+});
+
+export default connect(mapStateToProps, {})(PageLink);
\ No newline at end of file
diff --git a/src/app/containers/Routing/PageLink.tsx b/src/app/containers/Routing/PageLink.tsx
deleted file mode 100644
index 691e51107..000000000
--- a/src/app/containers/Routing/PageLink.tsx
+++ /dev/null
@@ -1,44 +0,0 @@
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) EGAAS S.A. All rights reserved.
- * See LICENSE in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import * as React from 'react';
-import { connect } from 'react-redux';
-import { IRootState } from 'modules';
-import { navigatePage } from '../../modules/sections/actions';
-
-import PageLink from 'components/Routing/PageLink';
-
-export interface IPageLinkContainerProps {
- page: string;
- section?: string;
- className?: string;
- params?: {
- [key: string]: string;
- };
-}
-
-interface IPageLinkContainerState {
- mainSection: string;
- currentSection: string;
-}
-
-interface IPageLinkContainerDispatch {
- navigatePage: typeof navigatePage.started;
-}
-
-const PageLinkContainer: React.SFC = (props) => (
-
-);
-
-const mapStateToProps = (state: IRootState) => ({
- mainSection: state.sections.mainSection,
- currentSection: state.sections.section
-});
-
-const mapDispatchToProps = {
- navigatePage: navigatePage.started
-};
-
-export default connect(mapStateToProps, mapDispatchToProps)(PageLinkContainer);
\ No newline at end of file
diff --git a/src/app/containers/Titlebar/SystemMenu.ts b/src/app/containers/Titlebar/SystemMenu.ts
new file mode 100644
index 000000000..d75a30fab
--- /dev/null
+++ b/src/app/containers/Titlebar/SystemMenu.ts
@@ -0,0 +1,26 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) EGAAS S.A. All rights reserved.
+ * See LICENSE in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+import { IRootState } from 'modules';
+import { connect } from 'react-redux';
+import { modalShow } from 'modules/modal/actions';
+
+import SystemMenu from 'components/Titlebar/SystemMenu';
+
+const mapStateToProps = (state: IRootState) => ({
+});
+
+const mapDispatchToProps = {
+ modalShow: modalShow
+};
+
+export default connect(mapStateToProps, mapDispatchToProps, (state, dispatch: any, props) => ({
+ ...props,
+ onAbout: () => dispatch.modalShow({
+ id: 'ABOUT',
+ type: 'ABOUT',
+ params: {}
+ })
+}))(SystemMenu);
\ No newline at end of file
diff --git a/src/app/containers/ToolButton/ToolButton.tsx b/src/app/containers/ToolButton/ToolButton.tsx
index bb4cc038f..94a9ad218 100644
--- a/src/app/containers/ToolButton/ToolButton.tsx
+++ b/src/app/containers/ToolButton/ToolButton.tsx
@@ -5,6 +5,7 @@
import React from 'react';
import uuid from 'uuid';
+import propTypes from 'prop-types';
import { IRootState } from 'modules';
import { connect } from 'react-redux';
import { buttonInteraction } from 'modules/content/actions';
@@ -37,6 +38,11 @@ interface IToolButtonDispatch {
class ToolButtonContainer extends React.Component {
private _uuid: string = null;
+ static contextTypes = {
+ protypo: propTypes.object.isRequired,
+ section: propTypes.string.isRequired
+ };
+
onClick = (e: React.MouseEvent) => {
e.preventDefault();
this._uuid = uuid.v4();
@@ -59,9 +65,12 @@ class ToolButtonContainer extends React.Component {
+ const currentTab = state.editor.tabs[state.editor.tabIndex];
+
+ return {
+ currentTab,
+ canSave: !state.editor.pending &&
+ currentTab && currentTab.dirty,
+ canRevert: !state.editor.pending &&
+ currentTab && (currentTab.dirty && null !== currentTab.initialValue)
+ };
+};
+
+const mapDispatchToProps = {
+ debugContract,
+ revertEditorTab,
+ editorSave,
+ createEditorTab: createEditorTab.started,
+ changeEditorTool: changeEditorTool.started
+};
+
+export default connect(mapStateToProps, mapDispatchToProps, (state, dispatch: any) => ({
+ ...state,
+ onExec: () => { dispatch.debugContract(state.currentTab.name); },
+ onRevert: () => { dispatch.revertEditorTab(state.currentTab.uuid); },
+ onToolChange: (tool: string) => { dispatch.changeEditorTool(tool); },
+ onSave: () => { dispatch.editorSave(state.currentTab); },
+ onCreateTab: (type: string) => { dispatch.createEditorTab(type); }
+
+}))(EditorToolbar);
\ No newline at end of file
diff --git a/src/app/containers/Widgets/NotificationsMenu/index.tsx b/src/app/containers/Widgets/NotificationsMenu/index.tsx
deleted file mode 100644
index af36aceee..000000000
--- a/src/app/containers/Widgets/NotificationsMenu/index.tsx
+++ /dev/null
@@ -1,61 +0,0 @@
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) EGAAS S.A. All rights reserved.
- * See LICENSE in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import React from 'react';
-import { connect } from 'react-redux';
-import { IRootState } from 'modules';
-import { fetchNotifications } from 'modules/content/actions';
-import { TProtypoElement } from 'apla/protypo';
-
-import NotificationsMenu from 'components/Main/NotificationsMenu';
-
-export interface INotificationsMenuContainerProps {
-
-}
-
-interface INotificationsMenuContainerState {
- offline: boolean;
- count: number;
- notificationsBody: TProtypoElement[];
-}
-
-interface INotificationsMenuContainerDispatch {
- fetchNotifications: typeof fetchNotifications.started;
-}
-
-class NotificationsContainer extends React.Component {
- componentWillReceiveProps(props: INotificationsMenuContainerProps & INotificationsMenuContainerState & INotificationsMenuContainerDispatch) {
- if (this.props.count !== props.count) {
- props.fetchNotifications(null);
- }
- }
-
- render() {
- return (
-
- );
- }
-}
-
-const mapStateToProps = (state: IRootState) => {
- const notifications = state.auth.wallet && state.auth.wallet.wallet ? state.socket.notifications.filter(l =>
- ((state.auth.wallet.role && state.auth.wallet.role.id === l.role) || l.role === '0') &&
- l.id === state.auth.wallet.wallet.id &&
- l.ecosystem === state.auth.wallet.access.ecosystem
- ).map(l => l.count) : [];
- const count = notifications.length ? notifications.reduce((a, b) => a + b) : 0;
-
- return {
- count,
- offline: !state.socket.connected,
- notificationsBody: state.content.notifications
- };
-};
-
-const mapDispatchToProps = {
- fetchNotifications: fetchNotifications.started
-};
-
-export default connect(mapStateToProps, mapDispatchToProps)(NotificationsContainer);
\ No newline at end of file
diff --git a/src/app/containers/Widgets/Protypo/index.tsx b/src/app/containers/Widgets/Protypo/index.tsx
index 7bacd5cf4..d8bf5fafd 100644
--- a/src/app/containers/Widgets/Protypo/index.tsx
+++ b/src/app/containers/Widgets/Protypo/index.tsx
@@ -3,63 +3,31 @@
* See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
-import * as React from 'react';
import { connect } from 'react-redux';
import { IRootState } from 'modules';
-import { navigate } from 'modules/engine/actions';
import { displayData } from 'modules/content/actions';
-import { navigatePage, menuPush } from 'modules/sections/actions';
+import { menuPush } from 'modules/sections/actions';
import { TProtypoElement } from 'apla/protypo';
-import Protypo from 'components/Protypo';
-
-export interface IProtypoContainerProps {
- editable?: boolean;
+export interface IProtypoProps {
wrapper?: JSX.Element;
context: string;
+ page?: string;
+ menu?: string;
+ section: string;
content: TProtypoElement[];
- changePage?: any;
- setTagCanDropPosition?: any;
- addTag?: any;
- moveTag?: any;
- copyTag?: any;
- removeTag?: any;
- selectTag?: any;
- selectedTag?: any;
- logic?: boolean;
-}
-
-interface IProtypoContainerState {
- apiHost: string;
- page: string;
}
-interface IProtypoContainerDispatch {
- navigatePage: typeof navigatePage.started;
- navigate: typeof navigate;
- menuPush: typeof menuPush;
- displayData: typeof displayData.started;
-}
-
-const ProtypoContainer: React.SFC = (props) => (
-
-);
-
-const mapStateToProps = (state: IRootState) => {
- const section = state.sections.sections[state.sections.section];
+import Protypo from 'components/Protypo';
- return {
- apiHost: state.auth.session && (state.auth.session.network.apiHost + '/api/v2'),
- section: state.sections.section,
- page: section && section.page && section.page.name
- };
-};
+const mapStateToProps = (state: IRootState, props: IProtypoProps) => ({
+ apiHost: state.auth.session && (state.auth.session.network.apiHost + '/api/v2'),
+ page: props.page,
+ ...props
+});
-const mapDispatchToProps = {
- navigatePage: navigatePage.started,
- navigate,
+export default connect(mapStateToProps, {
menuPush,
displayData: displayData.started
-};
-export default connect(mapStateToProps, mapDispatchToProps)(ProtypoContainer);
\ No newline at end of file
+})(Protypo as any);
\ No newline at end of file
diff --git a/src/app/containers/Widgets/ProtypoConstructor/index.tsx b/src/app/containers/Widgets/ProtypoConstructor/index.tsx
index c4a1926bd..0b86d8b0c 100644
--- a/src/app/containers/Widgets/ProtypoConstructor/index.tsx
+++ b/src/app/containers/Widgets/ProtypoConstructor/index.tsx
@@ -11,6 +11,7 @@ import { TProtypoElement } from 'apla/protypo';
import ProtypoConstructor from 'components/ProtypoConstructor';
export interface IProtypoConstructorContainerProps {
+ section: string;
editable?: boolean;
wrapper?: JSX.Element;
context: string;
@@ -38,12 +39,11 @@ const ProtypoConstructorContainer: React.SFC
);
-const mapStateToProps = (state: IRootState) => {
- const section = state.sections.sections[state.sections.section];
+const mapStateToProps = (state: IRootState, props: IProtypoConstructorContainerProps) => {
+ const section = state.sections.sections[props.section];
return {
apiHost: state.auth.session && (state.auth.session.network.apiHost + '/api/v2'),
- section: state.sections.section,
page: section.page && section.page.name
};
};
diff --git a/src/app/images/logoHeader.svg b/src/app/images/logoHeader.svg
new file mode 100644
index 000000000..3133f976a
--- /dev/null
+++ b/src/app/images/logoHeader.svg
@@ -0,0 +1,27 @@
+
diff --git a/src/app/lib/aplaAPI/index.ts b/src/app/lib/aplaAPI/index.ts
index c7624e84f..585e43078 100644
--- a/src/app/lib/aplaAPI/index.ts
+++ b/src/app/lib/aplaAPI/index.ts
@@ -210,7 +210,11 @@ class AplaAPI {
})
});
public keyinfo = this.setEndpoint<{ id: string }, IKeyInfo>('get', 'keyinfo/{id}', {
- requestTransformer: request => null
+ requestTransformer: request => null,
+ responseTransformer: response => ({
+ ...response,
+ ecosystems: response.ecosystems || []
+ })
});
// Data getters
diff --git a/src/app/lib/routing.ts b/src/app/lib/routing.ts
new file mode 100644
index 000000000..dd3d5405f
--- /dev/null
+++ b/src/app/lib/routing.ts
@@ -0,0 +1,35 @@
+/*---------------------------------------------------------------------------------------------
+* Copyright (c) EGAAS S.A. All rights reserved.
+* See LICENSE in the project root for license information.
+*--------------------------------------------------------------------------------------------*/
+
+import React from 'react';
+import Header from 'containers/Main/Header';
+import Navigator from 'containers/Main/Navigator';
+import Editor from 'containers/Main/Editor';
+
+interface RouteDict {
+ [name: string]: {
+ Header: React.ComponentType;
+ Content: React.ComponentType;
+ mapHeaderParams?: (params: any) => any;
+ mapContentParams?: (params: any) => any;
+ };
+}
+export const mainRoute = '/:app?/:page?/:action?';
+
+export const routes: RouteDict = {
+ browse: {
+ Header,
+ Content: Navigator,
+ mapContentParams: params => ({
+ app: params.app,
+ section: params.page,
+ page: params.action
+ })
+ },
+ editor: {
+ Header,
+ Content: Editor
+ }
+};
\ No newline at end of file
diff --git a/src/app/lib/legacyPages.tsx b/src/app/lib/staticPages.tsx
similarity index 50%
rename from src/app/lib/legacyPages.tsx
rename to src/app/lib/staticPages.tsx
index 4171552d3..e255aabd5 100644
--- a/src/app/lib/legacyPages.tsx
+++ b/src/app/lib/staticPages.tsx
@@ -4,41 +4,28 @@
*--------------------------------------------------------------------------------------------*/
import React from 'react';
-import Backup from 'containers/Main/Backup';
-import Editor from 'containers/Main/Editor';
import TxInfo from 'containers/StaticPages/TxInfo';
-export interface ILegacyPage {
- menu: string;
- section: string;
+export interface IStaticPage {
renderSubstitute?: (props?: T) => {
name: string;
params: TSubParams;
};
- render: (props?: T) => React.ReactNode;
+ render: (section: string, props?: T) => React.ReactNode;
}
-const LEGACY_PAGES: { [page: string]: ILegacyPage } = {
- 'backup': { section: null, menu: null, render: () => },
- 'editor': {
- section: 'editor',
- menu: null,
- render: (props: { open?: string, create?: string, name?: string, vde?: string }) =>
-
- },
+const STATIC_PAGES: { [page: string]: IStaticPage } = {
'txinfo': {
- section: null,
- menu: null,
renderSubstitute: props => ({
name: props.page,
params: {
txhashes: props.txhashes
}
}),
- render: props =>
+ render: (section, props) =>
}
};
export {
- LEGACY_PAGES
+ STATIC_PAGES
};
\ No newline at end of file
diff --git a/src/app/modules/auth/actions.ts b/src/app/modules/auth/actions.ts
index fe0f8fdca..c3ed66e3e 100644
--- a/src/app/modules/auth/actions.ts
+++ b/src/app/modules/auth/actions.ts
@@ -9,15 +9,11 @@ import { ICreateWalletCall, IImportWalletCall } from 'apla/auth';
import { IAccount } from 'apla/api';
const actionCreator = actionCreatorFactory('auth');
+export const acquireSession = actionCreator.async('ACQUIRE_SESSION');
export const login = actionCreator.async('LOGIN');
export const loginGuest = actionCreator.async('LOGIN_GUEST');
export const logout = actionCreator.async('LOGOUT');
export const inviteEcosystem = actionCreator<{ ecosystem: string, redirectPage?: string }>('INVITE_ECOSYSTEM');
-export const generateSeed = actionCreator.async('GENERATE_SEED');
-export const importSeed = actionCreator.async('IMPORT_SEED');
-export const importSeedConfirmation = actionCreator.async('IMPORT_SEED_CONFIRMATION');
-export const changeSeed = actionCreator('CHANGE_SEED');
-export const changeSeedConfirmation = actionCreator('CHANGE_SEED_CONFIRMATION');
export const createWallet = actionCreator.async('CREATE_WALLET');
export const importWallet = actionCreator.async('IMPORT_WALLET');
export const removeWallet = actionCreator('REMOVE_WALLET');
@@ -27,4 +23,5 @@ export const authorize = actionCreator('AUTHORIZE');
export const deauthorize = actionCreator('DEAUTHORIZE');
export const changePassword = actionCreator.async('CHANGE_PASSWORD');
export const loadWallets = actionCreator.async('LOAD_WALLETS');
-export const loadWallet = actionCreator('LOAD_WALLET');
\ No newline at end of file
+export const loadWallet = actionCreator('LOAD_WALLET');
+export const backupAccount = actionCreator('BACKUP_ACCOUNT');
\ No newline at end of file
diff --git a/src/app/modules/auth/epic.ts b/src/app/modules/auth/epic.ts
index 6866206e5..ecf404eb0 100644
--- a/src/app/modules/auth/epic.ts
+++ b/src/app/modules/auth/epic.ts
@@ -9,27 +9,24 @@ import logoutEpic from './epics/logoutEpic';
import authorizeEpic from './epics/authorizeEpic';
import createWalletEpic from './epics/createWalletEpic';
import importWalletEpic from './epics/importWalletEpic';
-import importSeedEpic from './epics/importSeedEpic';
-import generateSeedEpic from './epics/generateSeedEpic';
import authErrorEpic from './epics/authErrorEpic';
import removeWalletEpic from './epics/removeWalletEpic';
import logoutEmptySessionEpic from './epics/logoutEmptySessionEpic';
import changePasswordEpic from './epics/changePasswordEpic';
import changePasswordDoneEpic from './epics/changePasswordDoneEpic';
-import importSeedConfirmationEpic from './epics/importSeedConfirmationEpic';
import loadWalletsEpic from './epics/loadWalletsEpic';
import reloadWalletsEpic from './epics/reloadWalletsEpic';
import loadSavedWalletEpic from './epics/loadSavedWalletEpic';
import switchWalletEpic from './epics/switchWalletEpic';
import loginGuestEpic from './epics/loginGuestEpic';
+import acquireSessionEpic from './epics/acquireSessionEpic';
+import backupAccountEpic from './epics/backupAccountEpic';
export default combineEpics(
+ acquireSessionEpic,
authorizeEpic,
createWalletEpic,
- generateSeedEpic,
importWalletEpic,
- importSeedEpic,
- importSeedConfirmationEpic,
loginEpic,
authErrorEpic,
logoutEmptySessionEpic,
@@ -41,5 +38,6 @@ export default combineEpics(
changePasswordEpic,
changePasswordDoneEpic,
switchWalletEpic,
- loginGuestEpic
+ loginGuestEpic,
+ backupAccountEpic
);
\ No newline at end of file
diff --git a/src/app/modules/auth/epics/acquireSessionEpic.ts b/src/app/modules/auth/epics/acquireSessionEpic.ts
new file mode 100644
index 000000000..81582ded4
--- /dev/null
+++ b/src/app/modules/auth/epics/acquireSessionEpic.ts
@@ -0,0 +1,77 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) EGAAS S.A. All rights reserved.
+ * See LICENSE in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+import { Action } from 'redux';
+import { Epic } from 'modules';
+import { acquireSession } from '../actions';
+import { ISection } from 'apla/content';
+import { sectionsInit } from 'modules/sections/actions';
+import { fetchNotifications, ecosystemInit } from 'modules/content/actions';
+import { Observable } from 'rxjs';
+
+enum RemoteSectionStatus {
+ Removed = '0',
+ Default = '1',
+ Main = '2'
+}
+
+const acquireSessionEpic: Epic = (action$, store, { api }) => action$.ofAction(acquireSession.started)
+ .flatMap(action => {
+ const state = store.getState();
+ const client = api({
+ apiHost: action.payload.network.apiHost,
+ sessionToken: action.payload.sessionToken
+ });
+
+ return Observable.forkJoin(
+ Observable.from(client.sections({ locale: state.storage.locale })).map(s => s.list),
+ Observable.from(client.getParam({ name: 'stylesheet' })).map(p => p.value).catch(e => Observable.of('')),
+ Observable.from(client.getParam({ name: 'print_stylesheet' })).map(p => p.value).catch(e => Observable.of(''))
+
+ ).flatMap(([sections, stylesheet, printStylesheet]) => {
+ const sectionsResult: { [name: string]: ISection } = {};
+ const mainSection = sections.find(l => RemoteSectionStatus.Main === l.status);
+
+ sections.forEach((section, index) => {
+ sectionsResult[section.urlname] = {
+ index,
+ name: section.urlname,
+ title: section.title,
+ defaultPage: section.page,
+ breadcrumbs: [{
+ caller: '',
+ type: 'PAGE',
+ title: section.title,
+ section: section.urlname,
+ page: section.page,
+ params: {}
+ }],
+ menus: [],
+ page: undefined
+ };
+ });
+
+ return Observable.of(
+ sectionsInit({
+ mainSection: mainSection ? mainSection.urlname : sections[0].urlname,
+ sections: sectionsResult
+ }),
+ ecosystemInit({
+ stylesheet,
+ printStylesheet
+ }),
+ fetchNotifications.started(undefined),
+ acquireSession.done({
+ params: action.payload,
+ result: true
+ })
+ );
+ }).catch(e => Observable.of(acquireSession.done({
+ params: action.payload,
+ result: false
+ })));
+ });
+
+export default acquireSessionEpic;
\ No newline at end of file
diff --git a/src/app/modules/auth/epics/backupAccountEpic.ts b/src/app/modules/auth/epics/backupAccountEpic.ts
new file mode 100644
index 000000000..3e6f071b8
--- /dev/null
+++ b/src/app/modules/auth/epics/backupAccountEpic.ts
@@ -0,0 +1,39 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) EGAAS S.A. All rights reserved.
+ * See LICENSE in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+import { Epic } from 'modules';
+import { backupAccount } from '../actions';
+import { modalShow } from 'modules/modal/actions';
+import { Observable } from 'rxjs';
+import { txAuthorize } from 'modules/tx/actions';
+import { isType } from 'typescript-fsa';
+
+const backupAccountEpic: Epic = (action$, store) => action$.ofAction(backupAccount)
+ .flatMap(action =>
+ Observable.if(
+ () => !!store.getState().auth.privateKey,
+ Observable.defer(() => Observable.of(modalShow({
+ id: 'BACKUP',
+ type: 'BACKUP',
+ params: {}
+ }))),
+ Observable.merge(
+ Observable.of(txAuthorize.started({})),
+ action$.filter(l => txAuthorize.done.match(l) || txAuthorize.failed.match(l))
+ .take(1)
+ .flatMap(result => Observable.if(
+ () => isType(result, txAuthorize.done),
+ Observable.defer(() => Observable.of(modalShow({
+ id: 'BACKUP',
+ type: 'BACKUP',
+ params: {}
+ }))),
+ Observable.empty()
+ ))
+ )
+ )
+ );
+
+export default backupAccountEpic;
\ No newline at end of file
diff --git a/src/app/modules/auth/epics/generateSeedEpic.ts b/src/app/modules/auth/epics/generateSeedEpic.ts
deleted file mode 100644
index 60eeea7c7..000000000
--- a/src/app/modules/auth/epics/generateSeedEpic.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) EGAAS S.A. All rights reserved.
- * See LICENSE in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import { Epic } from 'modules';
-import { generateSeed } from '../actions';
-import keyring from 'lib/keyring';
-
-const authorizeEpic: Epic = (action$, store) => action$.ofAction(generateSeed.started)
- .map(action =>
- generateSeed.done({
- params: action.payload,
- result: keyring.generateSeed()
- })
- );
-
-export default authorizeEpic;
\ No newline at end of file
diff --git a/src/app/modules/auth/epics/importSeedConfirmationEpic.ts b/src/app/modules/auth/epics/importSeedConfirmationEpic.ts
deleted file mode 100644
index c9d5200e6..000000000
--- a/src/app/modules/auth/epics/importSeedConfirmationEpic.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) EGAAS S.A. All rights reserved.
- * See LICENSE in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import { Epic } from 'modules';
-import { importSeedConfirmation } from '../actions';
-import { Observable } from 'rxjs/Observable';
-import { readTextFile } from 'lib/fs';
-
-const importSeedConfirmationEpic: Epic = (action$, store) => action$.ofAction(importSeedConfirmation.started)
- .switchMap(action =>
- Observable.from(readTextFile(action.payload))
- .map(payload =>
- importSeedConfirmation.done({
- params: null,
- result: payload
- })
-
- ).catch(e =>
- Observable.of(importSeedConfirmation.failed({
- params: null,
- error: null
- }))
- )
- );
-
-export default importSeedConfirmationEpic;
\ No newline at end of file
diff --git a/src/app/modules/auth/epics/importSeedEpic.ts b/src/app/modules/auth/epics/importSeedEpic.ts
deleted file mode 100644
index df00c0c3d..000000000
--- a/src/app/modules/auth/epics/importSeedEpic.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) EGAAS S.A. All rights reserved.
- * See LICENSE in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import { Epic } from 'modules';
-import { importSeed } from '../actions';
-import { Observable } from 'rxjs/Observable';
-import { readTextFile } from 'lib/fs';
-
-const importSeedEpic: Epic = (action$, store) => action$.ofAction(importSeed.started)
- .switchMap(action =>
- Observable.from(readTextFile(action.payload))
- .map(payload =>
- importSeed.done({
- params: null,
- result: payload
- })
-
- ).catch(e =>
- Observable.of(importSeed.failed({
- params: null,
- error: null
- }))
- )
- );
-
-export default importSeedEpic;
\ No newline at end of file
diff --git a/src/app/modules/auth/epics/loginEpic.ts b/src/app/modules/auth/epics/loginEpic.ts
index d4a6a1597..582f003f5 100644
--- a/src/app/modules/auth/epics/loginEpic.ts
+++ b/src/app/modules/auth/epics/loginEpic.ts
@@ -5,7 +5,7 @@
import { Action } from 'redux';
import { Epic } from 'modules';
-import { login } from '../actions';
+import { login, acquireSession } from '../actions';
import { Observable } from 'rxjs/Observable';
import keyring from 'lib/keyring';
import { push } from 'connected-react-router';
@@ -39,20 +39,23 @@ const loginEpic: Epic = (action$, store, { api }) => action$.ofAction(login.star
})
// Successful authentication. Yield the result
- .flatMap(session => {
+ .flatMap(response => {
+ const sessionResult = {
+ sessionToken: response.token,
+ network: networkEndpoint
+ };
+
return Observable.of(
push('/'),
login.done({
params: action.payload,
result: {
- session: {
- sessionToken: session.token,
- network: networkEndpoint
- },
+ session: sessionResult,
privateKey,
publicKey
}
- })
+ }),
+ acquireSession.started(sessionResult)
);
})
diff --git a/src/app/modules/auth/epics/logoutEpic.ts b/src/app/modules/auth/epics/logoutEpic.ts
index 06ef7090c..a7b3bc4ef 100644
--- a/src/app/modules/auth/epics/logoutEpic.ts
+++ b/src/app/modules/auth/epics/logoutEpic.ts
@@ -7,13 +7,18 @@ import { Action } from 'redux';
import { Epic } from 'modules';
import { logout, deauthorize } from '../actions';
import { Observable } from 'rxjs/Observable';
+import { closeAllEditorTabs } from 'modules/editor/actions';
+import { isType } from 'typescript-fsa';
+import { discoverNetwork } from 'modules/engine/actions';
-const logoutEpic: Epic = (action$, store) => action$.ofAction(logout.started)
+const logoutEpic: Epic = (action$, store) => action$
+ .filter(action => isType(action, logout.started) || isType(action, discoverNetwork.done))
.flatMap(action =>
Observable.of(
deauthorize(null),
+ closeAllEditorTabs(),
logout.done({
- params: action.payload,
+ params: null,
result: null
})
)
diff --git a/src/app/modules/auth/reducer.ts b/src/app/modules/auth/reducer.ts
index fba2761a8..2e3d60cee 100644
--- a/src/app/modules/auth/reducer.ts
+++ b/src/app/modules/auth/reducer.ts
@@ -17,23 +17,19 @@ import createWalletFailedHandler from './reducers/createWalletFailedHandler';
import importWalletHandler from './reducers/importWalletHandler';
import importWalletDoneHandler from './reducers/importWalletDoneHandler';
import importWalletFailedHandler from './reducers/importWalletFailedHandler';
-import importSeedDoneHandler from './reducers/importSeedDoneHandler';
import selectWalletHandler from './reducers/selectWalletHandler';
import authorizeHandler from './reducers/authorizeHandler';
import deauthorizeHandler from './reducers/deauthorizeHandler';
-import generateSeedDoneHandler from './reducers/generateSeedDoneHandler';
-import changeSeedHandler from './reducers/changeSeedHandler';
-import changeSeedConfirmationHandler from './reducers/changeSeedConfirmation';
-import importSeedConfirmationDoneHandler from './reducers/importSeedConfirmationDoneHandler';
import loadWalletsDoneHandler from './reducers/loadWalletsDoneHandler';
import loadWalletHandler from './reducers/loadWalletHandler';
import loginGuestHandler from './reducers/loginGuestHandler';
import loginGuestDoneHandler from './reducers/loginGuestDoneHandler';
import loginGuestFailedHandler from './reducers/loginGuestFailedHandler';
+import acquireSessionHandler from './reducers/acquireSessionHandler';
+import acquireSessionDoneHandler from './reducers/acquireSessionDoneHandler';
export type State = {
- readonly seed: string;
- readonly seedConfirm: string;
+ readonly isAcquired: boolean;
readonly isAuthenticated: boolean;
readonly isLoggingIn: boolean;
readonly isCreatingWallet: boolean;
@@ -50,8 +46,7 @@ export type State = {
};
export const initialState: State = {
- seed: '',
- seedConfirm: '',
+ isAcquired: false,
isAuthenticated: false,
isLoggingIn: false,
isCreatingWallet: false,
@@ -81,13 +76,10 @@ export default reducerWithInitialState(initialState)
.case(actions.importWallet.started, importWalletHandler)
.case(actions.importWallet.done, importWalletDoneHandler)
.case(actions.importWallet.failed, importWalletFailedHandler)
- .case(actions.importSeed.done, importSeedDoneHandler)
- .case(actions.importSeedConfirmation.done, importSeedConfirmationDoneHandler)
.case(actions.selectWallet, selectWalletHandler)
.case(actions.authorize, authorizeHandler)
.case(actions.deauthorize, deauthorizeHandler)
- .case(actions.generateSeed.done, generateSeedDoneHandler)
- .case(actions.changeSeed, changeSeedHandler)
- .case(actions.changeSeedConfirmation, changeSeedConfirmationHandler)
.case(actions.loadWallets.done, loadWalletsDoneHandler)
- .case(actions.loadWallet, loadWalletHandler);
\ No newline at end of file
+ .case(actions.loadWallet, loadWalletHandler)
+ .case(actions.acquireSession.started, acquireSessionHandler)
+ .case(actions.acquireSession.done, acquireSessionDoneHandler);
\ No newline at end of file
diff --git a/src/app/modules/auth/reducers/importSeedConfirmationDoneHandler.ts b/src/app/modules/auth/reducers/acquireSessionDoneHandler.ts
similarity index 60%
rename from src/app/modules/auth/reducers/importSeedConfirmationDoneHandler.ts
rename to src/app/modules/auth/reducers/acquireSessionDoneHandler.ts
index 1a20431d8..d64abad55 100644
--- a/src/app/modules/auth/reducers/importSeedConfirmationDoneHandler.ts
+++ b/src/app/modules/auth/reducers/acquireSessionDoneHandler.ts
@@ -4,12 +4,13 @@
*--------------------------------------------------------------------------------------------*/
import { State } from '../reducer';
-import { importSeed } from '../actions';
+import { acquireSession } from '../actions';
import { Reducer } from 'modules';
-const importSeedConfirmationDoneHandler: Reducer = (state, payload) => ({
+const acquireSessionDoneHandler: Reducer = (state, payload): State => ({
...state,
- seedConfirm: payload.result
+ isAuthenticated: payload.result,
+ isAcquired: payload.result
});
-export default importSeedConfirmationDoneHandler;
\ No newline at end of file
+export default acquireSessionDoneHandler;
\ No newline at end of file
diff --git a/src/app/modules/auth/reducers/importSeedDoneHandler.ts b/src/app/modules/auth/reducers/acquireSessionHandler.ts
similarity index 66%
rename from src/app/modules/auth/reducers/importSeedDoneHandler.ts
rename to src/app/modules/auth/reducers/acquireSessionHandler.ts
index ff7438712..0c7530fad 100644
--- a/src/app/modules/auth/reducers/importSeedDoneHandler.ts
+++ b/src/app/modules/auth/reducers/acquireSessionHandler.ts
@@ -4,12 +4,12 @@
*--------------------------------------------------------------------------------------------*/
import { State } from '../reducer';
-import { importSeed } from '../actions';
+import { acquireSession } from '../actions';
import { Reducer } from 'modules';
-const importSeedDoneHandler: Reducer = (state, payload) => ({
+const acquireSessionHandler: Reducer = (state): State => ({
...state,
- seed: payload.result
+ isAcquired: false
});
-export default importSeedDoneHandler;
\ No newline at end of file
+export default acquireSessionHandler;
\ No newline at end of file
diff --git a/src/app/modules/auth/reducers/generateSeedDoneHandler.ts b/src/app/modules/auth/reducers/generateSeedDoneHandler.ts
deleted file mode 100644
index ce4e8a784..000000000
--- a/src/app/modules/auth/reducers/generateSeedDoneHandler.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) EGAAS S.A. All rights reserved.
- * See LICENSE in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import { State } from '../reducer';
-import { generateSeed } from '../actions';
-import { Reducer } from 'modules';
-
-const generateSeedDoneHandler: Reducer = (state, payload) => ({
- ...state,
- seed: payload.result
-});
-
-export default generateSeedDoneHandler;
\ No newline at end of file
diff --git a/src/app/modules/content/actions.ts b/src/app/modules/content/actions.ts
index 447eb965a..a263483e6 100644
--- a/src/app/modules/content/actions.ts
+++ b/src/app/modules/content/actions.ts
@@ -9,8 +9,8 @@ import { TProtypoElement, IButtonInteraction } from 'apla/protypo';
const actionCreator = actionCreatorFactory('content');
// Navigation
-export const setResizing = actionCreator('SET_RESIZING');
-export const ecosystemInit = actionCreator.async<{ section?: string }, { stylesheet: string, printStylesheet: string }, string>('ECOSYSTEM_INIT');
+export const ecosystemInit = actionCreator<{ stylesheet: string, printStylesheet: string }>('ECOSYSTEM_INIT');
+export const setMenuActive = actionCreator('SET_MENU_ACTIVE');
// Interaction
export const buttonInteraction = actionCreator('BUTTON_INTERACTION');
diff --git a/src/app/modules/content/epic.ts b/src/app/modules/content/epic.ts
index f29e7c015..32707ba52 100644
--- a/src/app/modules/content/epic.ts
+++ b/src/app/modules/content/epic.ts
@@ -4,13 +4,11 @@
*--------------------------------------------------------------------------------------------*/
import { combineEpics } from 'redux-observable';
-import ecosystemInitEpic from './epics/ecosystemInitEpic';
import displayDataEpic from './epics/displayDataEpic';
import fetchNotificationsEpic from './epics/fetchNotificationsEpic';
import buttonInteractionEpic from './epics/buttonInteractionEpic';
export default combineEpics(
- ecosystemInitEpic,
displayDataEpic,
fetchNotificationsEpic,
buttonInteractionEpic
diff --git a/src/app/modules/content/epics/buttonInteractionEpic.ts b/src/app/modules/content/epics/buttonInteractionEpic.ts
index 96bbe1bc9..b73e07af9 100644
--- a/src/app/modules/content/epics/buttonInteractionEpic.ts
+++ b/src/app/modules/content/epics/buttonInteractionEpic.ts
@@ -3,15 +3,18 @@
* See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
+import { Action } from 'redux';
import { Epic } from 'modules';
import { Observable } from 'rxjs/Observable';
import { buttonInteraction } from 'modules/content/actions';
import { isType } from 'typescript-fsa';
import { txCall, txExec } from 'modules/tx/actions';
-import { modalShow, modalClose, modalPage } from 'modules/modal/actions';
-import { navigatePage } from 'modules/sections/actions';
+import { modalShow, modalClose } from 'modules/modal/actions';
+import { push } from 'connected-react-router';
+import { renderPage } from 'modules/sections/actions';
+import { createEditorTab, loadEditorTab } from 'modules/editor/actions';
-const buttonInteractionEpic: Epic = (action$, store, { api }) => action$.ofAction(buttonInteraction)
+const buttonInteractionEpic: Epic = (action$, store, { routerService }) => action$.ofAction(buttonInteraction)
// Show confirmation window if there is any
.flatMap(rootAction => {
return Observable.if(
@@ -46,6 +49,7 @@ const buttonInteractionEpic: Epic = (action$, store, { api }) => action$.ofActio
Observable.of(txCall({
uuid: action.payload.uuid,
silent: action.payload.silent,
+ section: action.payload.from.section,
contracts: action.payload.contracts,
errorRedirects: action.payload.errorRedirects
})),
@@ -76,36 +80,45 @@ const buttonInteractionEpic: Epic = (action$, store, { api }) => action$.ofActio
}
}).flatMap(action => {
- if (isType(action, buttonInteraction)) {
- if (action.payload.page) {
- const params = action.payload.page.params;
- if ('txinfo' === action.payload.page.name) {
- params.txhashes = (action.meta.txHashes || []).join(',');
- }
+ if (isType(action, buttonInteraction) && action.payload.page) {
+ const params = action.payload.page.params;
+ if ('txinfo' === action.payload.page.name) {
+ params.txhashes = ((action.meta || {}).txHashes || []).join(',');
+ }
- if (action.payload.popup) {
- return Observable.of(modalPage({
- name: action.payload.page.name,
- params,
- title: action.payload.popup.title,
- width: action.payload.popup.width
- }));
- }
- else {
- return Observable.of(navigatePage.started({
- name: action.payload.page.name,
- params,
- force: true
- }));
- }
+ if (action.payload.popup) {
+ return Observable.of(renderPage.started({
+ location: null,
+ section: action.payload.page.section,
+ name: action.payload.page.name,
+ params: action.payload.page.params,
+ popup: action.payload.popup
+ }));
}
else {
- return Observable.empty();
+ const redirectUrl = routerService.generateRoute(`/browse/${action.payload.page.section}/${action.payload.page.name}`, action.payload.page.params);
+ return Observable.of(
+ push(redirectUrl, { from: action.payload.from })
+ );
}
}
else {
return Observable.of(action);
}
+
+ }).flatMap(action => {
+ if (isType(action, buttonInteraction)) {
+ return Observable.from(action.payload.actions).flatMap(buttonAction => {
+ switch (buttonAction.name) {
+ case 'CREATE': return Observable.of(createEditorTab.started(buttonAction.params.Type));
+ case 'EDIT': return Observable.of(loadEditorTab.started({ type: buttonAction.params.Type, name: buttonAction.params.Name }));
+ default: return Observable.empty();
+ }
+ });
+ }
+ else {
+ return Observable.of(action);
+ }
});
});
diff --git a/src/app/modules/content/epics/ecosystemInitEpic.ts b/src/app/modules/content/epics/ecosystemInitEpic.ts
deleted file mode 100644
index 126e1315a..000000000
--- a/src/app/modules/content/epics/ecosystemInitEpic.ts
+++ /dev/null
@@ -1,62 +0,0 @@
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) EGAAS S.A. All rights reserved.
- * See LICENSE in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import { Action } from 'redux';
-import { Epic } from 'modules';
-import { Observable } from 'rxjs/Observable';
-import { ecosystemInit, fetchNotifications } from 'modules/content/actions';
-import { sectionsInit } from 'modules/sections/actions';
-import { logout, selectWallet } from 'modules/auth/actions';
-
-const ecosystemInitEpic: Epic = (action$, store, { api }) => action$.ofAction(ecosystemInit.started)
- .flatMap(action => {
- const state = store.getState();
- const client = api({
- apiHost: state.auth.session.network.apiHost,
- sessionToken: state.auth.session.sessionToken
- });
-
- return Observable.zip(
- Observable.from(client.getParam({ name: 'stylesheet' }))
- .map(l => l.value)
- .catch(e => Observable.of('')),
- Observable.from(client.getParam({ name: 'print_stylesheet' }))
- .map(l => l.value)
- .catch(e => Observable.of(''))
- ).flatMap(([stylesheet, printStylesheet]) =>
- Observable.of(
- fetchNotifications.started(null),
- ecosystemInit.done({
- params: action.payload,
- result: {
- stylesheet,
- printStylesheet
- }
- }),
- sectionsInit.started(action.payload.section)
- )
- ).catch(e => {
- if ('E_OFFLINE' === e.error || 'E_SERVER' === e.error || 'E_TOKENEXPIRED' === e.error) {
- const wallet = store.getState().auth.wallet;
-
- return Observable.of(
- logout.started(null),
- selectWallet(wallet),
- ecosystemInit.failed({
- params: action.payload,
- error: e.error
- })
- );
- }
- return Observable.of(
- ecosystemInit.failed({
- params: action.payload,
- error: e.error
- })
- );
- });
- });
-
-export default ecosystemInitEpic;
\ No newline at end of file
diff --git a/src/app/modules/content/reducer.ts b/src/app/modules/content/reducer.ts
index 0ae8daa5b..cce7e0608 100644
--- a/src/app/modules/content/reducer.ts
+++ b/src/app/modules/content/reducer.ts
@@ -6,35 +6,27 @@
import * as actions from './actions';
import { reducerWithInitialState } from 'typescript-fsa-reducers';
import { TProtypoElement } from 'apla/protypo';
-import ecosystemInitDoneHandler from './reducers/ecosystemInitDoneHandler';
-import ecosystemInitFailedHandler from './reducers/ecosystemInitFailedHandler';
import fetchNotificationsDoneHandler from './reducers/fetchNotificationsDoneHandler';
-import setResizingHandler from './reducers/setResizingHandler';
import ecosystemInitHandler from './reducers/ecosystemInitHandler';
import reloadStylesheetHandler from './reducers/reloadStylesheetHandler';
+import setMenuActiveHandler from './reducers/setMenuActiveHandler';
export type State = {
- readonly preloading: boolean;
- readonly preloadingError: string;
readonly stylesheet: string;
readonly printStylesheet: string;
- readonly navigationResizing: boolean;
readonly notifications: TProtypoElement[];
+ readonly menuActive: boolean;
};
export const initialState: State = {
- preloading: false,
- preloadingError: null,
stylesheet: null,
printStylesheet: null,
- navigationResizing: false,
- notifications: null
+ notifications: null,
+ menuActive: false
};
export default reducerWithInitialState(initialState)
- .case(actions.ecosystemInit.done, ecosystemInitDoneHandler)
- .case(actions.ecosystemInit.failed, ecosystemInitFailedHandler)
- .case(actions.ecosystemInit.started, ecosystemInitHandler)
+ .case(actions.ecosystemInit, ecosystemInitHandler)
.case(actions.fetchNotifications.done, fetchNotificationsDoneHandler)
- .case(actions.setResizing, setResizingHandler)
- .case(actions.reloadStylesheet, reloadStylesheetHandler);
\ No newline at end of file
+ .case(actions.reloadStylesheet, reloadStylesheetHandler)
+ .case(actions.setMenuActive, setMenuActiveHandler);
\ No newline at end of file
diff --git a/src/app/modules/content/reducers/ecosystemInitDoneHandler.ts b/src/app/modules/content/reducers/ecosystemInitDoneHandler.ts
deleted file mode 100644
index bbf20ef86..000000000
--- a/src/app/modules/content/reducers/ecosystemInitDoneHandler.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) EGAAS S.A. All rights reserved.
- * See LICENSE in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import { State } from '../reducer';
-import { ecosystemInit } from '../actions';
-import { Reducer } from 'modules';
-
-const ecosystemInitDoneHandler: Reducer = (state, payload) => ({
- ...state,
- stylesheet: payload.result.stylesheet,
- printStylesheet: payload.result.printStylesheet
-});
-
-export default ecosystemInitDoneHandler;
\ No newline at end of file
diff --git a/src/app/modules/content/reducers/ecosystemInitFailedHandler.ts b/src/app/modules/content/reducers/ecosystemInitFailedHandler.ts
deleted file mode 100644
index 3a53558a4..000000000
--- a/src/app/modules/content/reducers/ecosystemInitFailedHandler.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) EGAAS S.A. All rights reserved.
- * See LICENSE in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import { State } from '../reducer';
-import { ecosystemInit } from '../actions';
-import { Reducer } from 'modules';
-
-const ecosystemInitFailedHandler: Reducer = (state, payload) => ({
- ...state,
- preloading: false,
- preloadingError: payload.error
-});
-
-export default ecosystemInitFailedHandler;
\ No newline at end of file
diff --git a/src/app/modules/content/reducers/ecosystemInitHandler.ts b/src/app/modules/content/reducers/ecosystemInitHandler.ts
index e0fe2f68c..4fdff459b 100644
--- a/src/app/modules/content/reducers/ecosystemInitHandler.ts
+++ b/src/app/modules/content/reducers/ecosystemInitHandler.ts
@@ -7,12 +7,10 @@ import { State } from '../reducer';
import { ecosystemInit } from '../actions';
import { Reducer } from 'modules';
-const ecosystemInitHandler: Reducer = (state, payload) => ({
+const ecosystemInitDoneHandler: Reducer = (state, payload) => ({
...state,
- preloading: true,
- preloadingError: null,
- stylesheet: '',
+ stylesheet: payload.stylesheet,
printStylesheet: ''
});
-export default ecosystemInitHandler;
\ No newline at end of file
+export default ecosystemInitDoneHandler;
\ No newline at end of file
diff --git a/src/app/modules/auth/reducers/changeSeedHandler.ts b/src/app/modules/content/reducers/setMenuActiveHandler.ts
similarity index 67%
rename from src/app/modules/auth/reducers/changeSeedHandler.ts
rename to src/app/modules/content/reducers/setMenuActiveHandler.ts
index d4aad59a2..24e3136dc 100644
--- a/src/app/modules/auth/reducers/changeSeedHandler.ts
+++ b/src/app/modules/content/reducers/setMenuActiveHandler.ts
@@ -4,12 +4,12 @@
*--------------------------------------------------------------------------------------------*/
import { State } from '../reducer';
-import { changeSeed } from '../actions';
+import { setMenuActive } from '../actions';
import { Reducer } from 'modules';
-const changeSeedHandler: Reducer = (state, payload) => ({
+const setMenuActiveHandler: Reducer = (state, payload) => ({
...state,
- seed: payload
+ menuActive: payload
});
-export default changeSeedHandler;
\ No newline at end of file
+export default setMenuActiveHandler;
\ No newline at end of file
diff --git a/src/app/modules/dependencies.ts b/src/app/modules/dependencies.ts
index 68c283104..c1e9cc4b6 100644
--- a/src/app/modules/dependencies.ts
+++ b/src/app/modules/dependencies.ts
@@ -8,6 +8,7 @@ import CodeGenerator, { setIds, convertToTreeData, findTagById, copyObject, idGe
import Properties from 'lib/constructor/properties';
import getConstructorTemplate from 'lib/constructor/templates';
import resolveTagHandler from 'lib/constructor/tags';
+import * as routerService from 'services/router';
import 'whatwg-fetch';
export interface IStoreDependencies {
@@ -15,6 +16,7 @@ export interface IStoreDependencies {
defaultKey: string;
defaultPassword: string;
constructorModule: IConstructorDependenies;
+ routerService: typeof routerService;
}
export interface IAPIDependency {
@@ -54,7 +56,8 @@ const storeDependencies: IStoreDependencies = {
resolveTagHandler,
CodeGenerator,
Properties
- }
+ },
+ routerService
};
export default storeDependencies;
\ No newline at end of file
diff --git a/src/app/modules/editor/actions.ts b/src/app/modules/editor/actions.ts
index 855f81b41..32d263965 100644
--- a/src/app/modules/editor/actions.ts
+++ b/src/app/modules/editor/actions.ts
@@ -7,7 +7,7 @@ import actionCreatorFactory from 'typescript-fsa';
import { TProtypoElement } from 'apla/protypo';
import {
- IEditorTabCreateCall, ILoadEditorTabCall, ICreateEditorTabCall, IReloadEditorTabCall, TEditorTab, IChangePageCall, IChangePageResult, ISaveConstructorHistoryResult,
+ IEditorTabCreateCall, ILoadEditorTabCall, IReloadEditorTabCall, TEditorTab, IChangePageCall, IChangePageResult, ISaveConstructorHistoryResult,
IConstructorUndoRedoResult, ISetTagCanDropPositionCall, ISetTagCanDropPositionResult, IAddTagCall, IOperateTagCall, IOperateTagResult, IMoveTreeTag, ISelectTagResult,
IGetPageTreeResult
} from 'apla/editor';
@@ -15,14 +15,16 @@ import {
const actionCreator = actionCreatorFactory('editor');
export const editorSave = actionCreator('EDITOR_SAVE');
-export const createEditorTab = actionCreator.async('CREATE_EDITOR_TAB');
+export const createEditorTab = actionCreator.async('CREATE_EDITOR_TAB');
export const loadEditorTab = actionCreator.async('LOAD_EDITOR_TAB');
-export const changeEditorTab = actionCreator('CHANGE_EDITOR_TAB');
-export const closeEditorTab = actionCreator('CLOSE_EDITOR_TAB');
-export const closeAllEditorTab = actionCreator('CLOSE_ALL_EDITOR_TAB');
+export const changeEditorTab = actionCreator('CHANGE_EDITOR_TAB');
+export const closeEditorTab = actionCreator('CLOSE_EDITOR_TAB');
+export const closeAllEditorTabs = actionCreator('CLOSE_ALL_EDITOR_TABS');
export const closeSavedEditorTab = actionCreator('CLOSE_SAVED_EDITOR_TAB');
+export const destroyEditorTab = actionCreator('DESTROY_EDITOR_TAB');
export const updateEditorTab = actionCreator('UPDATE_EDITOR_TAB');
-export const revertEditorTab = actionCreator('REVERT_EDITOR_TAB');
+export const revertEditorTab = actionCreator('REVERT_EDITOR_TAB');
+export const resetEditorTab = actionCreator('RESET_EDITOR_TAB');
export const reloadEditorTab = actionCreator('RELOAD_EDITOR_TAB');
export const changeEditorTool = actionCreator.async('CHANGE_EDITOR_TOOL');
export const setPageTemplate = actionCreator('SET_PAGE_TEMPLATE');
@@ -39,4 +41,4 @@ export const saveConstructorHistory = actionCreator.async('CONSTRUCTOR_UNDO');
export const constructorRedo = actionCreator.async('CONSTRUCTOR_REDO');
export const generatePageTemplate = actionCreator('GENERATE_PAGE_TEMPLATE');
-export const debugContract = actionCreator('DEBUG_CONTRACT');
+export const debugContract = actionCreator('DEBUG_CONTRACT');
\ No newline at end of file
diff --git a/src/app/modules/editor/epic.ts b/src/app/modules/editor/epic.ts
index 68515bee6..ca8ae84e2 100644
--- a/src/app/modules/editor/epic.ts
+++ b/src/app/modules/editor/epic.ts
@@ -29,6 +29,8 @@ import constructorUndoEpic from './epics/constructorUndoEpic';
import constructorRedoEpic from './epics/constructorRedoEpic';
import setTagCanDropPositionEpic from './epics/setTagCanDropPositionEpic';
import debugContractEpic from './epics/debugContractEpic';
+import revertEditorTabEpic from './epics/revertEditorTabEpic';
+import openEditorEpic from './epics/openEditorEpic';
export default combineEpics(
changeEditorToolEpic,
@@ -55,5 +57,7 @@ export default combineEpics(
constructorUndoEpic,
constructorRedoEpic,
setTagCanDropPositionEpic,
- debugContractEpic
+ debugContractEpic,
+ revertEditorTabEpic,
+ openEditorEpic
);
\ No newline at end of file
diff --git a/src/app/modules/editor/epics/closeEditorTabEpic.ts b/src/app/modules/editor/epics/closeEditorTabEpic.ts
index 1ebd27754..f0bc396c4 100644
--- a/src/app/modules/editor/epics/closeEditorTabEpic.ts
+++ b/src/app/modules/editor/epics/closeEditorTabEpic.ts
@@ -6,19 +6,30 @@
import { Action } from 'redux';
import { Epic } from 'redux-observable';
import { IRootState } from 'modules';
-import { closeEditorTab } from '../actions';
-import { updateSection } from 'modules/sections/actions';
+import { closeEditorTab, destroyEditorTab } from '../actions';
+import { Observable } from 'rxjs';
+import { modalShow } from 'modules/modal/actions';
-const closeEditorTabEpic: Epic =
- (action$, store) => action$.ofAction(closeEditorTab)
- .map(action => {
- const state = store.getState();
- const section = state.sections.sections.editor;
+const closeEditorTabEpic: Epic = (action$, store) => action$.ofAction(closeEditorTab)
+ .flatMap(action => {
+ const state = store.getState();
+ const tab = state.editor.tabs.find(t => t.uuid === action.payload);
- return updateSection({
- ...section,
- visible: 0 < state.editor.tabs.length
- });
- });
+ if (!tab) {
+ return Observable.empty();
+ }
+
+ if (tab.dirty) {
+ return Observable.of(modalShow({
+ id: 'EDITOR_CLOSE',
+ type: 'EDITOR_CLOSE_UNSAVED',
+ params: {
+ uuid: tab.uuid
+ }
+ }));
+ }
+
+ return Observable.of(destroyEditorTab(tab.uuid));
+ });
export default closeEditorTabEpic;
\ No newline at end of file
diff --git a/src/app/modules/editor/epics/createEditorTabEpic.ts b/src/app/modules/editor/epics/createEditorTabEpic.ts
index bbc18770a..51150368f 100644
--- a/src/app/modules/editor/epics/createEditorTabEpic.ts
+++ b/src/app/modules/editor/epics/createEditorTabEpic.ts
@@ -3,71 +3,51 @@
* See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
-import { Action } from 'redux';
-import { Epic } from 'redux-observable';
-import { IRootState } from 'modules';
+import uuid from 'uuid';
+import { Epic } from 'modules';
import { createEditorTab } from '../actions';
-import { updateSection } from 'modules/sections/actions';
-import { Observable } from 'rxjs/Observable';
-import { replace } from 'connected-react-router';
-const createEditorTabEpic: Epic =
- (action$, store) => action$.ofAction(createEditorTab.started)
- .delay(0)
- .map(action => {
- const state = store.getState();
+const createEditorTabEpic: Epic = (action$, store) => action$.ofAction(createEditorTab.started)
+ .map(action => {
+ const state = store.getState();
- const ids = state.editor.tabs
- .filter(l => l.new)
- .map(l => l.id)
- .sort();
+ const ids = state.editor.tabs
+ .filter(l => l.new)
+ .map(l => l.id)
+ .sort();
- const id = (ids.length ? parseInt(ids[ids.length - 1], 10) + 1 : 1).toString();
+ const id = (ids.length ? parseInt(ids[ids.length - 1], 10) + 1 : 1).toString();
- switch (action.payload.type) {
- case 'contract':
- return createEditorTab.done({
- params: action.payload,
- result: {
- id,
- name: null,
- value: 'contract ... {\n data {\n\n }\n conditions {\n\n }\n action {\n\n }\n}'
- }
- });
-
- case 'page':
- case 'block':
- case 'menu':
- return createEditorTab.done({
- params: action.payload,
- result: {
- id,
- name,
- value: ''
- }
- });
-
- default: return createEditorTab.failed({
+ switch (action.payload) {
+ case 'contract':
+ return createEditorTab.done({
params: action.payload,
- error: null
+ result: {
+ uuid: uuid.v4(),
+ id,
+ name: null,
+ value: 'contract ... {\n data {\n\n }\n conditions {\n\n }\n action {\n\n }\n}'
+ }
});
- }
- })
- .flatMap(action => {
- const editor = store.getState().sections.sections.editor;
- return Observable.of(
- replace('/editor'),
- updateSection({
- ...editor,
- visible: true,
- page: {
- ...editor.page,
- params: {}
+ case 'page':
+ case 'block':
+ case 'menu':
+ return createEditorTab.done({
+ params: action.payload,
+ result: {
+ uuid: uuid.v4(),
+ id,
+ name: null,
+ value: ''
}
- }),
- action
- );
- });
+ });
+
+ default: return createEditorTab.failed({
+ params: action.payload,
+ error: null
+ });
+ }
+ });
export default createEditorTabEpic;
\ No newline at end of file
diff --git a/src/app/modules/editor/epics/loadEditorTabEpic.ts b/src/app/modules/editor/epics/loadEditorTabEpic.ts
index 65818c9a9..327d49114 100644
--- a/src/app/modules/editor/epics/loadEditorTabEpic.ts
+++ b/src/app/modules/editor/epics/loadEditorTabEpic.ts
@@ -3,12 +3,10 @@
* See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
-import { Action } from 'redux';
+import uuid from 'uuid';
import { Epic } from 'modules';
import { loadEditorTab } from '../actions';
import { Observable } from 'rxjs/Observable';
-import { updateSection } from 'modules/sections/actions';
-import { replace } from 'connected-react-router';
const loadEditorTabEpic: Epic = (action$, store, { api }) => action$.ofAction(loadEditorTab.started)
.flatMap(action => {
@@ -19,122 +17,111 @@ const loadEditorTabEpic: Epic = (action$, store, { api }) => action$.ofAction(lo
});
const nameParser = /^(@[0-9]+)?(.*)$/i;
- switch (action.payload.type) {
- case 'contract':
- return Observable.fromPromise(client.getContract({
- name: action.payload.name
-
- }).then(contract =>
- client.getRow({
- table: 'contracts',
- id: contract.tableid.toString()
-
- }).then(row => ({
- id: contract.tableid.toString(),
- name: nameParser.exec(contract.name)[2],
- contract: row.value
- }))
-
- )).map(data =>
- loadEditorTab.done({
- params: action.payload,
- result: {
- type: 'contract',
- id: data.id,
- new: false,
- name: data.contract.name,
- tool: 'editor',
- value: data.contract.value,
- initialValue: data.contract.value,
- dirty: false
- }
- })
- );
-
- case 'page':
- return Observable.from(client.getPage({
- name: action.payload.name
-
- })).map(data =>
- loadEditorTab.done({
- params: action.payload,
- result: {
- type: 'page',
- id: data.id.toString(),
- new: false,
- name: data.name,
- tool: 'editor',
- value: data.value,
- initialValue: data.value,
- dirty: false
- }
- })
- );
-
- case 'menu':
- return Observable.from(client.getMenu({
- name: action.payload.name
-
- })).map(data =>
- loadEditorTab.done({
- params: action.payload,
- result: {
- type: 'menu',
- id: data.id.toString(),
- new: false,
- name: data.name,
- tool: 'editor',
- value: data.value,
- initialValue: data.value,
- dirty: false
- }
- })
- );
-
- case 'block':
- return Observable.from(client.getBlock({
- name: action.payload.name
-
- })).map(data =>
- loadEditorTab.done({
- params: action.payload,
- result: {
- type: 'block',
- id: data.id.toString(),
- new: false,
- name: data.name,
- tool: 'editor',
- value: data.value,
- initialValue: data.value,
- dirty: false
- }
- })
- );
-
- default:
- throw { error: 'E_FAILED' };
- }
-
- }).flatMap(result => {
- const editor = store.getState().sections.sections.editor;
- return Observable.of(
- replace('/editor'),
- result,
- updateSection({
- ...editor,
- visible: true,
- page: {
- ...editor.page,
- params: {}
- }
- })
- );
-
- }).catch(error =>
- Observable.of(loadEditorTab.failed({
- params: null,
+ return Observable.of(action.payload.type).flatMap(type => {
+ switch (type) {
+ case 'contract':
+ return Observable.fromPromise(client.getContract({
+ name: action.payload.name
+
+ }).then(contract =>
+ client.getRow({
+ table: 'contracts',
+ id: contract.tableid.toString()
+
+ }).then(row => ({
+ id: contract.tableid.toString(),
+ name: nameParser.exec(contract.name)[2],
+ contract: row.value
+ }))
+
+ )).map(data =>
+ loadEditorTab.done({
+ params: action.payload,
+ result: {
+ uuid: uuid.v4(),
+ type: 'contract',
+ id: data.id,
+ new: false,
+ name: data.contract.name,
+ tool: 'editor',
+ value: data.contract.value,
+ initialValue: data.contract.value,
+ dirty: false
+ }
+ })
+ );
+
+ case 'page':
+ return Observable.from(client.getPage({
+ name: action.payload.name
+
+ })).map(data =>
+ loadEditorTab.done({
+ params: action.payload,
+ result: {
+ uuid: uuid.v4(),
+ type: 'page',
+ id: data.id.toString(),
+ new: false,
+ name: data.name,
+ tool: 'editor',
+ value: data.value,
+ initialValue: data.value,
+ dirty: false
+ }
+ })
+ );
+
+ case 'menu':
+ return Observable.from(client.getMenu({
+ name: action.payload.name
+
+ })).map(data =>
+ loadEditorTab.done({
+ params: action.payload,
+ result: {
+ uuid: uuid.v4(),
+ type: 'menu',
+ id: data.id.toString(),
+ new: false,
+ name: data.name,
+ tool: 'editor',
+ value: data.value,
+ initialValue: data.value,
+ dirty: false
+ }
+ })
+ );
+
+ case 'block':
+ return Observable.from(client.getBlock({
+ name: action.payload.name
+
+ })).map(data =>
+ loadEditorTab.done({
+ params: action.payload,
+ result: {
+ uuid: uuid.v4(),
+ type: 'block',
+ id: data.id.toString(),
+ new: false,
+ name: data.name,
+ tool: 'editor',
+ value: data.value,
+ initialValue: data.value,
+ dirty: false
+ }
+ })
+ );
+
+ default:
+ throw { error: 'E_FAILED' };
+ }
+
+ }).catch(error => Observable.of(loadEditorTab.failed({
+ params: action.payload,
error
- }))
- );
+ })));
+ });
export default loadEditorTabEpic;
\ No newline at end of file
diff --git a/src/app/modules/editor/epics/newBlockEpic.ts b/src/app/modules/editor/epics/newBlockEpic.ts
index a0c21ccfc..78cf6c326 100644
--- a/src/app/modules/editor/epics/newBlockEpic.ts
+++ b/src/app/modules/editor/epics/newBlockEpic.ts
@@ -20,12 +20,17 @@ const newBlockEpic: Epic = (action$, store, { api }) => action$.ofAction(editorS
sessionToken: state.auth.session.sessionToken
});
- return ModalObservable<{ name: string, conditions: string }>(action$, {
+ return Observable.from(client.getData({
+ name: 'applications',
+ columns: ['id', 'deleted', 'name']
+
+ })).flatMap(apps => ModalObservable<{ name: string, app: string, conditions: string }>(action$, {
modal: {
id,
type: 'CREATE_INTERFACE',
params: {
- type: 'block'
+ type: 'block',
+ apps: apps.list.filter(l => '0' === l.deleted)
}
},
success: result => TxObservable(action$, {
@@ -37,7 +42,7 @@ const newBlockEpic: Epic = (action$, store, { api }) => action$.ofAction(editorS
Name: result.name,
Value: action.payload.value,
Conditions: result.conditions,
- ApplicationId: action.payload.appId || 0
+ ApplicationId: result.app || 0
}]
}]
},
@@ -55,7 +60,7 @@ const newBlockEpic: Epic = (action$, store, { api }) => action$.ofAction(editorS
}
}))
})
- });
+ }));
});
export default newBlockEpic;
\ No newline at end of file
diff --git a/src/app/modules/editor/epics/newContractEpic.ts b/src/app/modules/editor/epics/newContractEpic.ts
index 753e7e561..9bf2f31d2 100644
--- a/src/app/modules/editor/epics/newContractEpic.ts
+++ b/src/app/modules/editor/epics/newContractEpic.ts
@@ -8,6 +8,7 @@ import { Observable } from 'rxjs';
import { Epic } from 'modules';
import { editorSave, reloadEditorTab } from '../actions';
import TxObservable from 'modules/tx/util/TxObservable';
+import ModalObservable from 'modules/modal/util/ModalObservable';
const newContractEpic: Epic = (action$, store, { api }) => action$.ofAction(editorSave)
.filter(l => l.payload.new && 'contract' === l.payload.type)
@@ -19,33 +20,46 @@ const newContractEpic: Epic = (action$, store, { api }) => action$.ofAction(edit
sessionToken: state.auth.session.sessionToken
});
- return TxObservable(action$, {
- tx: {
- uuid: id,
- contracts: [{
- name: '@1NewContract',
- params: [{
- Value: action.payload.value,
- Conditions: 'true',
- ApplicationId: action.payload.appId ? action.payload.appId : 0
- }]
- }]
- },
- success: results => Observable.from(results).flatMap(result => Observable.fromPromise(client.getRow({
- table: 'contracts',
- id: result.status.result
+ return Observable.from(client.getData({
+ name: 'applications',
+ columns: ['id', 'deleted', 'name']
- })).map(response => reloadEditorTab({
- type: action.payload.type,
- id: action.payload.id,
- data: {
- new: false,
- id: String(result.status.result),
- name: response.value.name,
- initialValue: action.payload.value
+ })).flatMap(apps => ModalObservable<{ app: string, conditions: string }>(action$, {
+ modal: {
+ id,
+ type: 'CREATE_CONTRACT',
+ params: {
+ apps: apps.list.filter(l => '0' === l.deleted)
}
- })))
- });
+ },
+ success: result => TxObservable(action$, {
+ tx: {
+ uuid: id,
+ contracts: [{
+ name: '@1NewContract',
+ params: [{
+ Value: action.payload.value,
+ Conditions: result.conditions,
+ ApplicationId: result.app || 0
+ }]
+ }]
+ },
+ success: results => Observable.from(results).flatMap(tx => Observable.fromPromise(client.getRow({
+ table: 'contracts',
+ id: tx.status.result
+
+ })).map(response => reloadEditorTab({
+ type: action.payload.type,
+ id: action.payload.id,
+ data: {
+ new: false,
+ id: String(tx.status.result),
+ name: response.value.name,
+ initialValue: action.payload.value
+ }
+ })))
+ })
+ }));
});
export default newContractEpic;
\ No newline at end of file
diff --git a/src/app/modules/editor/epics/newMenuEpic.ts b/src/app/modules/editor/epics/newMenuEpic.ts
index 7c90cd907..6d2a001be 100644
--- a/src/app/modules/editor/epics/newMenuEpic.ts
+++ b/src/app/modules/editor/epics/newMenuEpic.ts
@@ -20,12 +20,17 @@ const newMenuEpic: Epic = (action$, store, { api }) => action$.ofAction(editorSa
sessionToken: state.auth.session.sessionToken
});
- return ModalObservable<{ name: string, conditions: string }>(action$, {
+ return Observable.from(client.getData({
+ name: 'applications',
+ columns: ['id', 'deleted', 'name']
+
+ })).flatMap(apps => ModalObservable<{ name: string, app: string, conditions: string }>(action$, {
modal: {
id,
type: 'CREATE_INTERFACE',
params: {
- type: 'menu'
+ type: 'menu',
+ apps: apps.list.filter(l => '0' === l.deleted)
}
},
success: result => TxObservable(action$, {
@@ -37,7 +42,7 @@ const newMenuEpic: Epic = (action$, store, { api }) => action$.ofAction(editorSa
Name: result.name,
Value: action.payload.value,
Conditions: result.conditions,
- ApplicationId: action.payload.appId ? action.payload.appId : 0
+ ApplicationId: result.app || 0
}]
}]
},
@@ -55,7 +60,7 @@ const newMenuEpic: Epic = (action$, store, { api }) => action$.ofAction(editorSa
}
}))
})
- });
+ }));
});
export default newMenuEpic;
\ No newline at end of file
diff --git a/src/app/modules/editor/epics/newPageEpic.ts b/src/app/modules/editor/epics/newPageEpic.ts
index e765e25fe..0e1aa748c 100644
--- a/src/app/modules/editor/epics/newPageEpic.ts
+++ b/src/app/modules/editor/epics/newPageEpic.ts
@@ -20,16 +20,22 @@ const newPageEpic: Epic = (action$, store, { api }) => action$.ofAction(editorSa
});
const id = uuid.v4();
- return Observable.fromPromise(client.getData({
- name: 'menu',
- columns: ['name']
-
- })).flatMap(menus => ModalObservable<{ name: string, menu: string, conditions: string }>(action$, {
+ return Observable.zip(
+ Observable.from(client.getData({
+ name: 'menu',
+ columns: ['name']
+ })),
+ Observable.from(client.getData({
+ name: 'applications',
+ columns: ['id', 'deleted', 'name']
+ }))
+ ).flatMap(([menus, apps]) => ModalObservable<{ name: string, app: string, menu: string, conditions: string }>(action$, {
modal: {
id,
type: 'CREATE_PAGE',
params: {
- menus: menus.list.map(l => l.name)
+ menus: menus.list.map(l => l.name),
+ apps: apps.list.filter(l => '0' === l.deleted)
}
},
success: result => TxObservable(action$, {
@@ -42,7 +48,7 @@ const newPageEpic: Epic = (action$, store, { api }) => action$.ofAction(editorSa
Value: action.payload.value,
Menu: result.menu,
Conditions: result.conditions,
- ApplicationId: action.payload.appId || 0
+ ApplicationId: result.app || 0
}]
}]
},
diff --git a/src/app/modules/gui/epics/switchWindowOnLoginEpic.ts b/src/app/modules/editor/epics/openEditorEpic.ts
similarity index 51%
rename from src/app/modules/gui/epics/switchWindowOnLoginEpic.ts
rename to src/app/modules/editor/epics/openEditorEpic.ts
index 91bedfd4a..47808094f 100644
--- a/src/app/modules/gui/epics/switchWindowOnLoginEpic.ts
+++ b/src/app/modules/editor/epics/openEditorEpic.ts
@@ -4,14 +4,12 @@
*--------------------------------------------------------------------------------------------*/
import { Epic } from 'modules';
-import { switchWindow } from '../actions';
-import { login, loginGuest } from 'modules/auth/actions';
+import { createEditorTab, loadEditorTab } from '../actions';
import { isType } from 'typescript-fsa';
+import { push } from 'connected-react-router';
-const switchWindowOnLoginEpic: Epic =
- (action$, store) => action$.filter(action => isType(action, login.done) || isType(action, loginGuest.done))
- .map(action =>
- switchWindow.started('main')
- );
+const openEditorEpic: Epic = (action$, store) => action$
+ .filter(action => isType(action, createEditorTab.done) || isType(action, loadEditorTab.done))
+ .map(() => push('/editor'));
-export default switchWindowOnLoginEpic;
\ No newline at end of file
+export default openEditorEpic;
\ No newline at end of file
diff --git a/src/app/modules/editor/epics/revertEditorTabEpic.ts b/src/app/modules/editor/epics/revertEditorTabEpic.ts
new file mode 100644
index 000000000..b422b8ce0
--- /dev/null
+++ b/src/app/modules/editor/epics/revertEditorTabEpic.ts
@@ -0,0 +1,35 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) EGAAS S.A. All rights reserved.
+ * See LICENSE in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+import { Action } from 'redux';
+import { Epic } from 'redux-observable';
+import { IRootState } from 'modules';
+import { resetEditorTab, revertEditorTab } from '../actions';
+import { Observable } from 'rxjs';
+import { modalShow } from 'modules/modal/actions';
+
+const revertEditorTabEpic: Epic = (action$, store) => action$.ofAction(revertEditorTab)
+ .flatMap(action => {
+ const state = store.getState();
+ const tab = state.editor.tabs.find(t => t.uuid === action.payload);
+
+ if (!tab) {
+ return Observable.empty();
+ }
+
+ if (tab.dirty) {
+ return Observable.of(modalShow({
+ id: 'EDITOR_REVERT',
+ type: 'EDITOR_REVERT_UNSAVED',
+ params: {
+ uuid: tab.uuid
+ }
+ }));
+ }
+
+ return Observable.of(resetEditorTab(tab.uuid));
+ });
+
+export default revertEditorTabEpic;
\ No newline at end of file
diff --git a/src/app/modules/editor/reducer.ts b/src/app/modules/editor/reducer.ts
index fdebadebc..72e1ac3f7 100644
--- a/src/app/modules/editor/reducer.ts
+++ b/src/app/modules/editor/reducer.ts
@@ -9,12 +9,11 @@ import { reducerWithInitialState } from 'typescript-fsa-reducers/dist';
import changeEditorToolDoneHandler from './reducers/changeEditorToolDoneHandler';
import changeEditorTabHandler from './reducers/changeEditorTabHandler';
import changeEditorToolStartedHandler from './reducers/changeEditorToolStartedHandler';
-import closeEditorTabHandler from './reducers/closeEditorTabHandler';
import closeAllEditorTabHandler from './reducers/closeAllEditorTabHandler';
import closeSavedEditorTabHandler from './reducers/closeSavedEditorTabHandler';
import createEditorTabDoneHandler from './reducers/createEditorTabDoneHandler';
import reloadEditorTabHandler from './reducers/reloadEditorTabHandler';
-import revertEditorTabHandler from './reducers/revertEditorTabHandler';
+import resetEditorTabHandler from './reducers/resetEditorTabHandler';
import updateEditorTabHandler from './reducers/updateEditorTabHandler';
import loadEditorTabDoneHandler from './reducers/loadEditorTabDoneHandler';
import getPageTreeDoneHandler from './reducers/getPageTreeDoneHandler';
@@ -30,6 +29,7 @@ import setTagCanDropPositionDoneHandler from './reducers/setTagCanDropPositionDo
import constructorUndoDoneHandler from './reducers/constructorUndoDoneHandler';
import constructorRedoDoneHandler from './reducers/constructorRedoDoneHandler';
import setPageTemplateHandler from './reducers/setPageTemplateHandler';
+import destroyEditorTabHandler from './reducers/destroyEditorTabHandler';
export type State = {
readonly pending: boolean;
@@ -47,13 +47,13 @@ export default reducerWithInitialState(initialState)
.case(actions.changeEditorTab, changeEditorTabHandler)
.case(actions.changeEditorTool.done, changeEditorToolDoneHandler)
.case(actions.changeEditorTool.started, changeEditorToolStartedHandler)
- .case(actions.closeEditorTab, closeEditorTabHandler)
- .case(actions.closeAllEditorTab, closeAllEditorTabHandler)
+ .case(actions.destroyEditorTab, destroyEditorTabHandler)
+ .case(actions.closeAllEditorTabs, closeAllEditorTabHandler)
.case(actions.closeSavedEditorTab, closeSavedEditorTabHandler)
.case(actions.createEditorTab.done, createEditorTabDoneHandler)
.case(actions.loadEditorTab.done, loadEditorTabDoneHandler)
.case(actions.reloadEditorTab, reloadEditorTabHandler)
- .case(actions.revertEditorTab, revertEditorTabHandler)
+ .case(actions.resetEditorTab, resetEditorTabHandler)
.case(actions.updateEditorTab, updateEditorTabHandler)
.case(actions.getPageTree.done, getPageTreeDoneHandler)
.case(actions.getPageTree.failed, getPageTreeFailedHandler)
diff --git a/src/app/modules/editor/reducers/changeEditorTabHandler.ts b/src/app/modules/editor/reducers/changeEditorTabHandler.ts
index b0129153b..7fa583710 100644
--- a/src/app/modules/editor/reducers/changeEditorTabHandler.ts
+++ b/src/app/modules/editor/reducers/changeEditorTabHandler.ts
@@ -7,9 +7,17 @@ import { State } from '../reducer';
import { changeEditorTab } from '../actions';
import { Reducer } from 'modules';
-const changeEditorTabHandler: Reducer = (state, payload) => ({
- ...state,
- tabIndex: payload
-});
+const changeEditorTabHandler: Reducer = (state, payload) => {
+ const tabIndex = state.tabs.findIndex(t => t.uuid === payload);
+
+ if (-1 === tabIndex) {
+ return state;
+ }
+
+ return {
+ ...state,
+ tabIndex
+ };
+};
export default changeEditorTabHandler;
\ No newline at end of file
diff --git a/src/app/modules/editor/reducers/closeEditorTabHandler.ts b/src/app/modules/editor/reducers/closeEditorTabHandler.ts
deleted file mode 100644
index 61d0dfa88..000000000
--- a/src/app/modules/editor/reducers/closeEditorTabHandler.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) EGAAS S.A. All rights reserved.
- * See LICENSE in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import { State } from '../reducer';
-import { closeEditorTab } from '../actions';
-import { Reducer } from 'modules';
-
-const closeEditorTabHandler: Reducer = (state, payload) => ({
- ...state,
- tabIndex: state.tabIndex >= state.tabs.length - 1 ? state.tabs.length - 2 : state.tabIndex,
- tabs: [
- ...state.tabs.slice(0, payload),
- ...state.tabs.slice(payload + 1),
- ]
-});
-
-export default closeEditorTabHandler;
\ No newline at end of file
diff --git a/src/app/modules/editor/reducers/createEditorTabDoneHandler.ts b/src/app/modules/editor/reducers/createEditorTabDoneHandler.ts
index c97bc83c3..ce18e8e1c 100644
--- a/src/app/modules/editor/reducers/createEditorTabDoneHandler.ts
+++ b/src/app/modules/editor/reducers/createEditorTabDoneHandler.ts
@@ -12,15 +12,15 @@ const createEditorTabDoneHandler: Reducer =
tabs: [
...state.tabs,
{
- type: payload.params.type,
+ uuid: payload.result.uuid,
+ type: payload.params,
id: payload.result.id,
new: true,
name: payload.result.name,
tool: 'editor',
value: payload.result.value,
initialValue: payload.result.value,
- dirty: false,
- appId: payload.params.appId
+ dirty: false
}
],
tabIndex: state.tabs.length
diff --git a/src/app/modules/editor/reducers/destroyEditorTabHandler.ts b/src/app/modules/editor/reducers/destroyEditorTabHandler.ts
new file mode 100644
index 000000000..3d5796d33
--- /dev/null
+++ b/src/app/modules/editor/reducers/destroyEditorTabHandler.ts
@@ -0,0 +1,27 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) EGAAS S.A. All rights reserved.
+ * See LICENSE in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+import { State } from '../reducer';
+import { destroyEditorTab } from '../actions';
+import { Reducer } from 'modules';
+
+const destroyEditorTabHandler: Reducer = (state, payload) => {
+ const tabIndex = state.tabs.findIndex(t => t.uuid === payload);
+
+ if (-1 === tabIndex) {
+ return state;
+ }
+
+ return {
+ ...state,
+ tabIndex: state.tabIndex >= state.tabs.length - 1 ? state.tabs.length - 2 : state.tabIndex,
+ tabs: [
+ ...state.tabs.slice(0, tabIndex),
+ ...state.tabs.slice(tabIndex + 1),
+ ]
+ };
+};
+
+export default destroyEditorTabHandler;
\ No newline at end of file
diff --git a/src/app/modules/editor/reducers/resetEditorTabHandler.ts b/src/app/modules/editor/reducers/resetEditorTabHandler.ts
new file mode 100644
index 000000000..d0a6d6b8c
--- /dev/null
+++ b/src/app/modules/editor/reducers/resetEditorTabHandler.ts
@@ -0,0 +1,31 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) EGAAS S.A. All rights reserved.
+ * See LICENSE in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+import { State } from '../reducer';
+import { resetEditorTab } from '../actions';
+import { Reducer } from 'modules';
+
+const resetEditorTabHandler: Reducer = (state, payload) => {
+ const tabIndex = state.tabs.findIndex(t => t.uuid === payload);
+
+ if (-1 === tabIndex) {
+ return state;
+ }
+
+ return {
+ ...state,
+ tabs: [
+ ...state.tabs.slice(0, tabIndex),
+ {
+ ...state.tabs[tabIndex],
+ value: state.tabs[tabIndex].initialValue,
+ dirty: false
+ },
+ ...state.tabs.slice(tabIndex + 1),
+ ]
+ };
+};
+
+export default resetEditorTabHandler;
\ No newline at end of file
diff --git a/src/app/modules/editor/reducers/revertEditorTabHandler.ts b/src/app/modules/editor/reducers/revertEditorTabHandler.ts
deleted file mode 100644
index da1672395..000000000
--- a/src/app/modules/editor/reducers/revertEditorTabHandler.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) EGAAS S.A. All rights reserved.
- * See LICENSE in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import { State } from '../reducer';
-import { revertEditorTab } from '../actions';
-import { Reducer } from 'modules';
-
-const revertEditorTabHandler: Reducer = (state, payload) => ({
- ...state,
- tabs: [
- ...state.tabs.slice(0, payload),
- {
- ...state.tabs[payload],
- value: state.tabs[payload].initialValue,
- dirty: false
- },
- ...state.tabs.slice(payload + 1),
- ]
-});
-
-export default revertEditorTabHandler;
\ No newline at end of file
diff --git a/src/app/modules/engine/actions.ts b/src/app/modules/engine/actions.ts
index 281d8638f..cd18a342a 100644
--- a/src/app/modules/engine/actions.ts
+++ b/src/app/modules/engine/actions.ts
@@ -14,5 +14,4 @@ export const navigate = (url: string) => push(url);
export const initialize = actionCreator.async<{}, { defaultNetwork: string, preconfiguredNetworks: INetwork[], locales: ILocale[] }, IFatalError>('INITIALIZE');
export const discoverNetwork = actionCreator.async<{ uuid: string }, { session: ISession }, NetworkError>('DISCOVER_NETWORK');
export const addNetwork = actionCreator.async<{ name: string, networkID?: number, apiHost: string }, void>('ADD_NETWORK');
-export const setCollapsed = actionCreator('SET_COLLAPSED');
export const setLocale = actionCreator.async('SET_LOCALE');
\ No newline at end of file
diff --git a/src/app/modules/engine/epics/discoverNetworkEpic.ts b/src/app/modules/engine/epics/discoverNetworkEpic.ts
index 0238d36d9..481ca23ec 100644
--- a/src/app/modules/engine/epics/discoverNetworkEpic.ts
+++ b/src/app/modules/engine/epics/discoverNetworkEpic.ts
@@ -11,45 +11,47 @@ import { discover } from 'services/network';
import { mergeFullNodes } from 'modules/storage/actions';
import NetworkError from 'services/network/errors';
-const setNetworkEpic: Epic = (action$, store, { api, defaultKey }) => action$.ofAction(discoverNetwork.started)
+const discoverNetworkEpic: Epic = (action$, store, { api, defaultKey }) => action$.ofAction(discoverNetwork.started)
.flatMap(action => {
const network = store.getState().storage.networks.find(l => l.uuid === action.payload.uuid);
return NodeObservable({
nodes: network.fullNodes,
count: 1,
- timeout: 5000,
+ timeout: 10000,
concurrency: 10,
api
- }).flatMap(node =>
- Observable.from(discover({ uuid: network.uuid, apiHost: node }, defaultKey, network.id))
- .flatMap(result => Observable.concat(
- Observable.of(discoverNetwork.done({
- params: action.payload,
- result: {
- session: {
- network: {
- uuid: network.uuid,
- apiHost: node
- },
- sessionToken: result.loginResult.token
+ }).defaultIfEmpty(null).flatMap(node =>
+ Observable.if(
+ () => null !== node,
+ Observable.defer(() => Observable.from(discover({ uuid: network.uuid, apiHost: node }, defaultKey, network.id))
+ .flatMap(result => Observable.concat(
+ Observable.of(discoverNetwork.done({
+ params: action.payload,
+ result: {
+ session: {
+ network: {
+ uuid: network.uuid,
+ apiHost: node
+ },
+ sessionToken: result.loginResult.token
+ }
}
- }
- })),
- Observable.of(mergeFullNodes({
- uuid: network.uuid,
- fullNodes: result.fullNodes
- }))
- ))
+ })),
+ Observable.of(mergeFullNodes({
+ uuid: network.uuid,
+ fullNodes: result.fullNodes
+ }))
+ ))),
+ Observable.defer(() => Observable.throw(NetworkError.Offline))
+ )
).catch((error: NetworkError) => Observable.of(discoverNetwork.failed({
params: action.payload,
error
- }))).timeout(10000).catch(timeout => Observable.of(discoverNetwork.failed({
- params: action.payload,
- error: NetworkError.Offline
+
})));
});
-export default setNetworkEpic;
+export default discoverNetworkEpic;
\ No newline at end of file
diff --git a/src/app/modules/engine/epics/initializeEpic.ts b/src/app/modules/engine/epics/initializeEpic.ts
index c40ab6f0d..4812c8b40 100644
--- a/src/app/modules/engine/epics/initializeEpic.ts
+++ b/src/app/modules/engine/epics/initializeEpic.ts
@@ -14,6 +14,8 @@ import { INetwork } from 'apla/auth';
import webConfig from 'lib/settings/webConfig';
import localeConfig from 'lib/settings/localeConfig';
import ConfigObservable from '../util/ConfigObservable';
+import { acquireSession } from 'modules/auth/actions';
+import { Action } from 'redux';
const DEFAULT_NETWORK = '__DEFAULT';
@@ -64,7 +66,7 @@ const initializeEpic: Epic = (action$, store, { defaultPassword }) => action$.of
demoEnabled: network.enableDemoMode
}));
- return Observable.concat(
+ return Observable.concat(
Observable.if(
() => !!preconfiguredKey,
Observable.of(saveWallet(preconfiguredKey)),
@@ -79,7 +81,12 @@ const initializeEpic: Epic = (action$, store, { defaultPassword }) => action$.of
locales: locales.locales
}
})),
- Observable.of(setLocale.started(state.storage.locale || config.defaultLocale))
+ Observable.of(setLocale.started(state.storage.locale || config.defaultLocale)),
+ Observable.if(
+ () => store.getState().auth.isAuthenticated && !!store.getState().auth.session,
+ Observable.of(acquireSession.started(store.getState().auth.session)),
+ Observable.empty()
+ )
);
}).catch(e => Observable.of(initialize.failed({
params: action.payload,
diff --git a/src/app/modules/engine/reducer.ts b/src/app/modules/engine/reducer.ts
index c8f5d2187..61a006fb3 100644
--- a/src/app/modules/engine/reducer.ts
+++ b/src/app/modules/engine/reducer.ts
@@ -10,7 +10,6 @@ import { IFatalError, ILocale } from 'apla';
import { reducerWithInitialState } from 'typescript-fsa-reducers/dist';
import initializeDoneHandler from './reducers/initializeDoneHandler';
import setLocaleDoneHandler from './reducers/setLocaleDoneHandler';
-import setCollapsedHandler from './reducers/setCollapsedHandler';
import discoverNetworkHandler from './reducers/discoverNetworkHandler';
import discoverNetworkDoneHandler from './reducers/discoverNetworkDoneHandler';
import discoverNetworkFailedHandler from './reducers/discoverNetworkFailedHandler';
@@ -24,12 +23,12 @@ export type State = {
readonly fatalError?: IFatalError;
readonly guestSession: ISession;
readonly localeMessages: { [key: string]: string };
- readonly isCollapsed: boolean;
readonly isLoaded: boolean;
readonly isConnecting: boolean;
readonly preconfiguredNetworks: INetwork[];
readonly locales: ILocale[];
readonly locale: string;
+ readonly panel?: string;
};
export const initialState: State = {
@@ -37,18 +36,17 @@ export const initialState: State = {
fatalError: null,
guestSession: null,
localeMessages: {},
- isCollapsed: true,
isLoaded: false,
isConnecting: false,
preconfiguredNetworks: [],
locales: [],
- locale: null
+ locale: null,
+ panel: null
};
export default reducerWithInitialState(initialState)
.case(actions.initialize.done, initializeDoneHandler)
.case(actions.initialize.failed, initializeFailedHandler)
- .case(actions.setCollapsed, setCollapsedHandler)
.case(actions.setLocale.done, setLocaleDoneHandler)
.case(actions.discoverNetwork.started, discoverNetworkHandler)
.case(actions.discoverNetwork.done, discoverNetworkDoneHandler)
diff --git a/src/app/modules/gui/epic.ts b/src/app/modules/gui/epic.ts
deleted file mode 100644
index 22bee1456..000000000
--- a/src/app/modules/gui/epic.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) EGAAS S.A. All rights reserved.
- * See LICENSE in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import { combineEpics } from 'redux-observable';
-import switchWindowEpic from './epics/switchWindowEpic';
-import setBadgeCountEpic from './epics/setBadgeCountEpic';
-import switchWindowOnLoginEpic from './epics/switchWindowOnLoginEpic';
-import setBadgeCountOnLogoutEpic from './epics/setBadgeCountOnLogoutEpic';
-
-export default combineEpics(
- setBadgeCountEpic,
- switchWindowEpic,
- switchWindowOnLoginEpic,
- setBadgeCountOnLogoutEpic
-);
\ No newline at end of file
diff --git a/src/app/modules/gui/epics/setBadgeCountEpic.ts b/src/app/modules/gui/epics/setBadgeCountEpic.ts
deleted file mode 100644
index 8ccccde98..000000000
--- a/src/app/modules/gui/epics/setBadgeCountEpic.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) EGAAS S.A. All rights reserved.
- * See LICENSE in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import { Action } from 'redux';
-import { Epic } from 'redux-observable';
-import { IRootState } from 'modules';
-import { setBadgeCount } from '../actions';
-import { Observable } from 'rxjs/Observable';
-import platform from 'lib/platform';
-
-const setBadgeCountEpic: Epic =
- (action$, store) => action$.ofAction(setBadgeCount)
- .flatMap(action => {
- platform.on('desktop', () => {
- const Electron = require('electron');
- Electron.remote.app.setBadgeCount(action.payload);
- });
-
- return Observable.empty();
- });
-
-export default setBadgeCountEpic;
\ No newline at end of file
diff --git a/src/app/modules/gui/epics/setBadgeCountOnLogoutEpic.ts b/src/app/modules/gui/epics/setBadgeCountOnLogoutEpic.ts
deleted file mode 100644
index 7818460a8..000000000
--- a/src/app/modules/gui/epics/setBadgeCountOnLogoutEpic.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) EGAAS S.A. All rights reserved.
- * See LICENSE in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import { Action } from 'redux';
-import { Epic } from 'redux-observable';
-import { IRootState } from 'modules';
-import { setBadgeCount } from '../actions';
-import { login, loginGuest } from 'modules/auth/actions';
-import { isType } from 'typescript-fsa';
-
-const setBadgeCountOnLogoutEpic: Epic =
- (action$, store) => action$.filter(action => isType(action, login.done) || isType(action, loginGuest.done))
- .map(action =>
- setBadgeCount(0)
- );
-
-export default setBadgeCountOnLogoutEpic;
\ No newline at end of file
diff --git a/src/app/modules/gui/epics/switchWindowEpic.ts b/src/app/modules/gui/epics/switchWindowEpic.ts
deleted file mode 100644
index c679bc07e..000000000
--- a/src/app/modules/gui/epics/switchWindowEpic.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) EGAAS S.A. All rights reserved.
- * See LICENSE in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import { Action } from 'redux';
-import { Epic } from 'redux-observable';
-import { IRootState } from 'modules';
-import { switchWindow } from '../actions';
-import platform from 'lib/platform';
-
-const switchWindowEpic: Epic =
- (action$, store) => action$.ofAction(switchWindow.started)
- .map(action => {
- platform.on('desktop', () => {
- const Electron = require('electron');
- Electron.ipcRenderer.sendSync('switchWindow', action.payload);
- });
-
- return switchWindow.done({
- params: action.payload,
- result: action.payload
- });
- });
-
-export default switchWindowEpic;
\ No newline at end of file
diff --git a/src/app/modules/gui/reducer.ts b/src/app/modules/gui/reducer.ts
deleted file mode 100644
index da78f3a26..000000000
--- a/src/app/modules/gui/reducer.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) EGAAS S.A. All rights reserved.
- * See LICENSE in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import * as actions from './actions';
-import { reducerWithInitialState } from 'typescript-fsa-reducers';
-import { TWindowType } from 'apla/gui';
-import switchWindowDoneHandler from './reducers/switchWindowDoneHandler';
-
-export type State = {
- readonly window: TWindowType;
-};
-
-export const initialState: State = {
- window: 'general'
-};
-
-export default reducerWithInitialState(initialState)
- .case(actions.switchWindow.done, switchWindowDoneHandler);
\ No newline at end of file
diff --git a/src/app/modules/gui/reducers/switchWindowDoneHandler.ts b/src/app/modules/gui/reducers/switchWindowDoneHandler.ts
deleted file mode 100644
index 2d732f7b6..000000000
--- a/src/app/modules/gui/reducers/switchWindowDoneHandler.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) EGAAS S.A. All rights reserved.
- * See LICENSE in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import { State } from '../reducer';
-import { switchWindow } from '../actions';
-import { Reducer } from 'modules';
-
-const switchWindowDoneHandler: Reducer = (state, payload) => ({
- ...state,
- window: payload.result
-});
-
-export default switchWindowDoneHandler;
\ No newline at end of file
diff --git a/src/app/modules/index.ts b/src/app/modules/index.ts
index 8abf9664e..2a042b2d4 100644
--- a/src/app/modules/index.ts
+++ b/src/app/modules/index.ts
@@ -8,8 +8,6 @@ import { Epic as NativeEpic } from 'redux-observable';
import { IStoreDependencies } from './dependencies';
import { combineReducers } from 'redux';
import { combineEpics } from 'redux-observable';
-import { RouterState } from 'connected-react-router';
-import { loadingBarReducer } from 'react-redux-loading-bar';
import * as auth from './auth';
import * as content from './content';
import * as sections from './sections';
@@ -17,11 +15,11 @@ import * as modal from './modal';
import * as engine from './engine';
import * as editor from './editor';
import * as tx from './tx';
-import * as gui from './gui';
import * as io from './io';
import * as notifications from './notifications';
import * as storage from './storage';
import * as socket from './socket';
+import * as router from './router';
import { ActionCreator, Failure, Success } from 'typescript-fsa';
export type Epic = NativeEpic;
@@ -39,13 +37,11 @@ export interface IRootState {
engine: engine.State;
editor: editor.State;
tx: tx.State;
- gui: gui.State;
io: io.State;
notifications: notifications.State;
storage: storage.State;
socket: socket.State;
- loadingBar: number;
- router: RouterState;
+ router: router.State;
}
export const rootEpic = combineEpics(
@@ -56,11 +52,11 @@ export const rootEpic = combineEpics(
engine.epic,
editor.epic,
tx.epic,
- gui.epic,
io.epic,
notifications.epic,
storage.epic,
- socket.epic
+ socket.epic,
+ router.epic
);
export default combineReducers({
@@ -71,9 +67,8 @@ export default combineReducers({
engine: engine.reducer,
editor: editor.reducer,
tx: tx.reducer,
- gui: gui.reducer,
notifications: notifications.reducer,
storage: storage.reducer,
socket: socket.reducer,
- loadingBar: loadingBarReducer
+ router: router.reducer
});
\ No newline at end of file
diff --git a/src/app/modules/modal/actions.ts b/src/app/modules/modal/actions.ts
index ffaf8f694..620137985 100644
--- a/src/app/modules/modal/actions.ts
+++ b/src/app/modules/modal/actions.ts
@@ -4,10 +4,9 @@
*--------------------------------------------------------------------------------------------*/
import actionCreatorFactory from 'typescript-fsa';
-import { IModalCall, IModalCloseCall, IModalPageCall } from 'apla/modal';
+import { IModalCall, IModalCloseCall } from 'apla/modal';
const actionCreator = actionCreatorFactory('modal');
export const modalShow = actionCreator('MODAL_SHOW');
-export const modalClose = actionCreator('MODAL_CLOSE');
-export const modalPage = actionCreator('MODAL_PAGE');
\ No newline at end of file
+export const modalClose = actionCreator('MODAL_CLOSE');
\ No newline at end of file
diff --git a/src/app/modules/modal/epic.ts b/src/app/modules/modal/epic.ts
index 40a8c7348..e5dc800f5 100644
--- a/src/app/modules/modal/epic.ts
+++ b/src/app/modules/modal/epic.ts
@@ -4,12 +4,10 @@
*--------------------------------------------------------------------------------------------*/
import { combineEpics } from 'redux-observable';
-import modalPageEpic from './epics/modalPageEpic';
import closeModalOnInteractionEpic from './epics/closeModalOnInteractionEpic';
import removeNetworkEpic from './epics/removeNetworkEpic';
export default combineEpics(
- modalPageEpic,
closeModalOnInteractionEpic,
removeNetworkEpic
);
\ No newline at end of file
diff --git a/src/app/modules/modal/epics/closeModalOnInteractionEpic.ts b/src/app/modules/modal/epics/closeModalOnInteractionEpic.ts
index 5ce6a13e6..ad2aae875 100644
--- a/src/app/modules/modal/epics/closeModalOnInteractionEpic.ts
+++ b/src/app/modules/modal/epics/closeModalOnInteractionEpic.ts
@@ -7,10 +7,10 @@ import { Epic } from 'modules';
import { isType } from 'typescript-fsa';
import { Observable } from 'rxjs/Observable';
import { modalClose } from '../actions';
-import { navigatePage } from 'modules/sections/actions';
import { logout } from 'modules/auth/actions';
+import { locationChange } from 'modules/router/actions';
-const closeModalOnInteractionEpic: Epic = (action$, store, { api }) => action$.filter(action => isType(action, navigatePage.started) || isType(action, logout.started))
+const closeModalOnInteractionEpic: Epic = (action$, store) => action$.filter(action => isType(action, locationChange) || isType(action, logout.started))
.flatMap(() => {
const state = store.getState();
diff --git a/src/app/modules/modal/epics/modalPageEpic.ts b/src/app/modules/modal/epics/modalPageEpic.ts
deleted file mode 100644
index d848b57ec..000000000
--- a/src/app/modules/modal/epics/modalPageEpic.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) EGAAS S.A. All rights reserved.
- * See LICENSE in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import { Epic } from 'modules';
-import { modalPage, modalShow } from '../actions';
-import { Observable } from 'rxjs/Observable';
-
-const modalPageEpic: Epic = (action$, store, { api }) => action$.ofAction(modalPage)
- .flatMap(action => {
- const state = store.getState();
- const client = api({
- apiHost: state.auth.session.network.apiHost,
- sessionToken: state.auth.session.sessionToken
- });
-
- return Observable.fromPromise(client.content({
- type: 'page',
- name: action.payload.name,
- params: action.payload.params,
- locale: state.storage.locale
-
- })).map(payload =>
- modalShow({
- id: 'PAGE_MODAL:' + action.payload.name,
- type: 'PAGE_MODAL',
- params: {
- name: action.payload.name,
- title: action.payload.title || action.payload.name,
- width: action.payload.width,
- tree: payload.tree
- }
-
- })
-
- ).catch(e =>
- Observable.empty()
- );
- });
-
-export default modalPageEpic;
\ No newline at end of file
diff --git a/src/app/modules/gui/actions.ts b/src/app/modules/router/actions.ts
similarity index 57%
rename from src/app/modules/gui/actions.ts
rename to src/app/modules/router/actions.ts
index 3413457e3..9cee7a40d 100644
--- a/src/app/modules/gui/actions.ts
+++ b/src/app/modules/router/actions.ts
@@ -4,8 +4,8 @@
*--------------------------------------------------------------------------------------------*/
import actionCreatorFactory from 'typescript-fsa';
-import { TWindowType } from 'apla/gui';
+import { RouterState } from 'connected-react-router';
-const actionCreator = actionCreatorFactory('gui');
-export const switchWindow = actionCreator.async('SWITCH_WINDOW');
-export const setBadgeCount = actionCreator('SET_BADGE_COUNT');
\ No newline at end of file
+const actionCreator = actionCreatorFactory('@@router');
+
+export const locationChange = actionCreator('LOCATION_CHANGE');
\ No newline at end of file
diff --git a/src/app/modules/router/epic.ts b/src/app/modules/router/epic.ts
new file mode 100644
index 000000000..5b9d050f1
--- /dev/null
+++ b/src/app/modules/router/epic.ts
@@ -0,0 +1,11 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) EGAAS S.A. All rights reserved.
+ * See LICENSE in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+import { combineEpics } from 'redux-observable';
+import sectionLoadEpic from './epics/sectionLoadEpic';
+
+export default combineEpics(
+ sectionLoadEpic
+);
\ No newline at end of file
diff --git a/src/app/modules/router/epics/sectionLoadEpic.ts b/src/app/modules/router/epics/sectionLoadEpic.ts
new file mode 100644
index 000000000..197329760
--- /dev/null
+++ b/src/app/modules/router/epics/sectionLoadEpic.ts
@@ -0,0 +1,93 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) EGAAS S.A. All rights reserved.
+ * See LICENSE in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+import { Epic } from 'modules';
+import { locationChange } from '../actions';
+import { renderPage } from 'modules/sections/actions';
+import { Observable } from 'rxjs';
+import { state$ } from 'store';
+import { initialize } from 'modules/engine/actions';
+import { isType, Action } from 'typescript-fsa';
+import { RouterState, replace } from 'connected-react-router';
+import { createEditorTab, loadEditorTab } from 'modules/editor/actions';
+
+const sectionLoadEpic: Epic = (action$, store, { routerService }) => action$
+ .filter(action => isType(action, initialize.started) || isType(action, locationChange))
+ .map((action: Action) => {
+ if (isType(action, initialize.started)) {
+ return store.getState().router;
+ }
+
+ return action.payload;
+ })
+ .delayWhen(() => state$.filter(l => l.auth.isAcquired).take(1))
+ .flatMap((routerState: RouterState) => {
+ const match = routerService.matchRoute('/browse(/:section)(/:page)', routerState.location.pathname + routerState.location.search);
+ const state = store.getState();
+
+ if (state.auth.isAuthenticated && match) {
+ const section = state.sections.sections[match.parts.section || state.sections.mainSection];
+
+ if (!section) {
+ return Observable.of(replace(
+ routerService.routeToBrowser(state.sections.mainSection, state.sections.sections[state.sections.mainSection].defaultPage)
+ ));
+ }
+
+ const pageName = match.parts.page || section.defaultPage;
+
+ // TODO: OLD EDITOR API COMPAT
+ if ('editor' === pageName) {
+ if (match.query.create) {
+ return Observable.of(
+ createEditorTab.started(match.query.create),
+ replace('/editor')
+ );
+ }
+ else if (match.query.open) {
+ return Observable.of(
+ loadEditorTab.started({ type: match.query.open, name: match.query.name }),
+ replace('/editor')
+ );
+ }
+ }
+
+ // TODO: refactoring
+ // must ignore navigation when page and params are equal
+ // if ('POP' === action.payload.action) {
+ // const pageIndex = findPage(section, pageName);
+ // if (-1 !== pageIndex) {
+ // const page = store.value.navigator.sections[section.name].pages[pageIndex];
+ // if (page.content || page.error) {
+ // return of(popPage({
+ // location: action.payload.location,
+ // section: section.name,
+ // name: pageName
+ // }));
+ // }
+ // }
+ // }
+
+ return Observable.of(renderPage.started({
+ location: {
+ state: {},
+ ...routerState.location
+ },
+ section: section.name,
+ name: pageName,
+ params: match.query
+ }));
+ }
+ else {
+ return Observable.empty();
+ }
+
+ }).catch(e => {
+ // tslint:disable-next-line: no-console
+ console.log(e);
+ return Observable.of(e);
+ });
+
+export default sectionLoadEpic;
\ No newline at end of file
diff --git a/src/app/modules/gui/index.ts b/src/app/modules/router/index.ts
similarity index 100%
rename from src/app/modules/gui/index.ts
rename to src/app/modules/router/index.ts
diff --git a/src/app/modules/router/reducer.ts b/src/app/modules/router/reducer.ts
new file mode 100644
index 000000000..830efd0c8
--- /dev/null
+++ b/src/app/modules/router/reducer.ts
@@ -0,0 +1,22 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) EGAAS S.A. All rights reserved.
+ * See LICENSE in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+import { reducerWithInitialState } from 'typescript-fsa-reducers';
+import { RouterState } from 'connected-react-router';
+
+export type State =
+ RouterState;
+
+export const initialState: RouterState = {
+ location: {
+ key: '',
+ pathname: '',
+ search: '',
+ hash: ''
+ },
+ action: 'PUSH'
+};
+
+export default reducerWithInitialState(initialState);
\ No newline at end of file
diff --git a/src/app/modules/sections/actions.ts b/src/app/modules/sections/actions.ts
index 8c7c03432..8abd05ad0 100644
--- a/src/app/modules/sections/actions.ts
+++ b/src/app/modules/sections/actions.ts
@@ -4,21 +4,15 @@
*--------------------------------------------------------------------------------------------*/
import actionCreatorFactory from 'typescript-fsa';
-import { TMenu, TPage, TSection } from 'apla/content';
+import { IMenu, ISection } from 'apla/content';
+import { TProtypoElement } from 'apla/protypo';
+import { Location } from 'history';
-const actionCreator = actionCreatorFactory('section');
+const actionCreator = actionCreatorFactory('sections');
-// Navigation
-export const renderSection = actionCreator('RENDER_SECTION');
-export const updateSection = actionCreator('UPDATE_SECTION');
-export const closeSection = actionCreator('CLOSE_SECTION');
-export const switchSection = actionCreator('SWITCH_SECTION');
-export const reset = actionCreator('RESET');
-export const menuPop = actionCreator('MENU_POP');
-export const menuPush = actionCreator('MENU_PUSH');
-export const navigatePage = actionCreator.async<{ name?: string, section?: string, force?: boolean, params: { [key: string]: any } }, { section: string }, undefined>('NAVIGATE_PAGE');
-export const navigationToggle = actionCreator('NAVIGATION_TOGGLE');
-export const renderPage = actionCreator.async<{ key: string, section: string, name: string, params?: { [key: string]: any } }, { defaultMenu: TMenu, menu: TMenu, page: TPage }, string>('RENDER_PAGE');
-export const renderLegacyPage = actionCreator.async<{ section: string, name: string, menu: string, params?: { [key: string]: any } }, { menu: TMenu, page: TPage }>('RENDER_LEGACY_PAGE');
-export const reloadPage = actionCreator.async<{}, { params: { [key: string]: any }, menu: TMenu, page: TPage }, string>('RELOAD_PAGE');
-export const sectionsInit = actionCreator.async('SECTIONS_INIT');
+export const updateSection = actionCreator('UPDATE_SECTION');
+export const menuPop = actionCreator('MENU_POP');
+export const menuPush = actionCreator<{ section: string, menu: IMenu }>('MENU_PUSH');
+export const renderPage = actionCreator.async<{ section: string, name: string, popup?: { title?: string, width?: number }, params: { [key: string]: string }, location: Location }, { tree: TProtypoElement[], menu: string, menuTree: TProtypoElement[], static: boolean }, string>('RENDER_PAGE');
+export const reloadPage = actionCreator<{ section: string }>('RELOAD_PAGE');
+export const sectionsInit = actionCreator<{ mainSection: string, sections: { [name: string]: ISection } }>('SECTIONS_INIT');
diff --git a/src/app/modules/sections/epic.ts b/src/app/modules/sections/epic.ts
index 7416cea75..bb3a61f57 100644
--- a/src/app/modules/sections/epic.ts
+++ b/src/app/modules/sections/epic.ts
@@ -4,22 +4,10 @@
*--------------------------------------------------------------------------------------------*/
import { combineEpics } from 'redux-observable';
-import closeSectionEpic from './epics/closeSectionEpic';
-import renderSectionEpic from './epics/renderSectionEpic';
-import resetOnLoginEpic from './epics/resetOnLoginEpic';
-import navigatePageEpic from './epics/navigatePageEpic';
-import reloadPageEpic from './epics/reloadPageEpic';
-import renderLegacyPageEpic from './epics/renderLegacyPageEpic';
import renderPageEpic from './epics/renderPageEpic';
-import sectionsInitEpic from './epics/sectionsInitEpic';
+import reloadPageEpic from './epics/reloadPageEpic';
export default combineEpics(
- closeSectionEpic,
- renderSectionEpic,
- resetOnLoginEpic,
- navigatePageEpic,
- reloadPageEpic,
- renderLegacyPageEpic,
renderPageEpic,
- sectionsInitEpic
+ reloadPageEpic
);
\ No newline at end of file
diff --git a/src/app/modules/sections/epics/closeSectionEpic.ts b/src/app/modules/sections/epics/closeSectionEpic.ts
deleted file mode 100644
index 3f36d2187..000000000
--- a/src/app/modules/sections/epics/closeSectionEpic.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) EGAAS S.A. All rights reserved.
- * See LICENSE in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import { Epic } from 'modules';
-import { closeSection, renderSection } from '..//actions';
-import { Observable } from 'rxjs/Observable';
-
-const closeSectionEpic: Epic = (action$, store) => action$.ofAction(closeSection)
- .flatMap(action => {
- const state = store.getState();
- if (action.payload === state.sections.section) {
- return Observable.of(renderSection('home'));
- }
- else {
- return Observable.empty();
- }
- });
-
-export default closeSectionEpic;
\ No newline at end of file
diff --git a/src/app/modules/sections/epics/navigatePageEpic.ts b/src/app/modules/sections/epics/navigatePageEpic.ts
deleted file mode 100644
index 8062d11e1..000000000
--- a/src/app/modules/sections/epics/navigatePageEpic.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) EGAAS S.A. All rights reserved.
- * See LICENSE in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import queryString from 'query-string';
-import { Action } from 'redux';
-import { push } from 'connected-react-router';
-import { Epic } from 'modules';
-import { Observable } from 'rxjs/Observable';
-import { navigatePage } from '../actions';
-import { LEGACY_PAGES } from 'lib/legacyPages';
-
-const navigatePageEpic: Epic = (action$, store) => action$.ofAction(navigatePage.started)
- .flatMap(action => {
- const state = store.getState();
- const sectionName = (LEGACY_PAGES[action.payload.name] && LEGACY_PAGES[action.payload.name].section) || action.payload.section || state.sections.section;
- const section = state.sections.sections[sectionName];
- const params = queryString.stringify(action.payload.params);
-
- return Observable.of(
- push(`/${sectionName}/${action.payload.name || section.defaultPage}${params ? '?' + params : ''}`),
- navigatePage.done({
- params: action.payload,
- result: {
- section: sectionName
- }
- })
- );
- });
-
-export default navigatePageEpic;
\ No newline at end of file
diff --git a/src/app/modules/sections/epics/reloadPageEpic.ts b/src/app/modules/sections/epics/reloadPageEpic.ts
index 4827b2e1b..a535d176b 100644
--- a/src/app/modules/sections/epics/reloadPageEpic.ts
+++ b/src/app/modules/sections/epics/reloadPageEpic.ts
@@ -4,47 +4,23 @@
*--------------------------------------------------------------------------------------------*/
import { Epic } from 'modules';
-import { Observable } from 'rxjs/Observable';
-import { reloadPage } from '../actions';
+import { reloadPage, renderPage } from '../actions';
+import { Observable } from 'rxjs';
-const reloadPageEpic: Epic = (action$, store, { api }) => action$.ofAction(reloadPage.started)
- .flatMap(action => {
- const state = store.getState();
- const section = state.sections.sections[state.sections.section];
- const client = api({
- apiHost: state.auth.session.network.apiHost,
- sessionToken: state.auth.session.sessionToken
- });
+const reloadPageEpic: Epic = (action$, store) => action$.ofAction(reloadPage)
+ .switchMap(action => {
+ const section = store.getState().sections.sections[action.payload.section];
- return Observable.fromPromise(client.content({
- type: 'page',
+ if (!section || !section.page) {
+ return Observable.empty();
+ }
+
+ return Observable.of(renderPage.started({
+ section: section.name,
name: section.page.name,
params: section.page.params,
- locale: state.storage.locale,
-
- })).map(payload =>
- reloadPage.done({
- params: action.payload,
- result: {
- params: section.page.params,
- menu: {
- name: payload.menu,
- content: payload.menutree
- },
- page: {
- params: section.page.params,
- name: section.page.name,
- content: payload.tree
- }
- }
- })
-
- ).catch(e =>
- Observable.of(reloadPage.failed({
- params: action.payload,
- error: e.error
- }))
- );
+ location: section.page.location
+ }));
});
export default reloadPageEpic;
\ No newline at end of file
diff --git a/src/app/modules/sections/epics/renderLegacyPageEpic.ts b/src/app/modules/sections/epics/renderLegacyPageEpic.ts
deleted file mode 100644
index fbc2ae56f..000000000
--- a/src/app/modules/sections/epics/renderLegacyPageEpic.ts
+++ /dev/null
@@ -1,78 +0,0 @@
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) EGAAS S.A. All rights reserved.
- * See LICENSE in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import { Epic } from 'modules';
-import { Observable } from 'rxjs/Observable';
-import { renderLegacyPage } from '../actions';
-import { LEGACY_PAGES } from 'lib/legacyPages';
-import { IContentResponse } from 'apla/api';
-
-const renderLegacyPageEpic: Epic = (action$, store, { api }) => action$.ofAction(renderLegacyPage.started)
- .flatMap(action => {
- const state = store.getState();
- const client = api({
- apiHost: state.auth.session.network.apiHost,
- sessionToken: state.auth.session.sessionToken
- });
-
- const LEGACY_PAGE = LEGACY_PAGES[action.payload.name];
- const substitute = LEGACY_PAGE.renderSubstitute && LEGACY_PAGE.renderSubstitute(action.payload.params);
-
- return Observable.zip(
- Observable.if(
- () => !!action.payload.menu,
- Observable.defer(() => client.content({
- type: 'menu',
- name: action.payload.menu,
- params: {},
- locale: state.storage.locale
- })),
- Observable.of(null)
- ),
- Observable.if(
- () => !!substitute,
- Observable.defer(() => client.content({
- type: 'page',
- name: substitute.name,
- params: substitute.params,
- locale: state.storage.locale
- })),
- Observable.of(null)
- )
-
- ).map(([menu, page]) => renderLegacyPage.done({
- params: action.payload,
- result: {
- menu: {
- name: action.payload.menu,
- content: menu ? menu.tree : []
- },
- page: page ?
- {
- name: substitute.name,
- params: substitute.params,
- content: page.tree
- } :
- {
- name: '',
- params: {},
- content: []
- }
- }
-
- })).catch(e => Observable.of(renderLegacyPage.done({
- params: action.payload,
- result: {
- menu: null,
- page: {
- name: '',
- params: {},
- content: []
- }
- }
- })));
- });
-
-export default renderLegacyPageEpic;
\ No newline at end of file
diff --git a/src/app/modules/sections/epics/renderPageEpic.ts b/src/app/modules/sections/epics/renderPageEpic.ts
index 9ec5396d6..999ffb8ff 100644
--- a/src/app/modules/sections/epics/renderPageEpic.ts
+++ b/src/app/modules/sections/epics/renderPageEpic.ts
@@ -6,60 +6,63 @@
import { Epic } from 'modules';
import { Observable } from 'rxjs/Observable';
import { renderPage } from '../actions';
+import { STATIC_PAGES } from 'lib/staticPages';
+import { modalShow } from 'modules/modal/actions';
+import { Action } from 'redux';
const renderPageEpic: Epic = (action$, store, { api }) => action$.ofAction(renderPage.started)
- .flatMap(action => {
+ .switchMap(action => {
const state = store.getState();
const client = api({
apiHost: state.auth.session.network.apiHost,
sessionToken: state.auth.session.sessionToken
});
- const section = state.sections.sections[action.payload.section || state.sections.section];
- return Observable.from(Promise.all([
- client.content({
- type: 'page',
- name: action.payload.name,
- params: action.payload.params,
- locale: state.storage.locale
+ const staticPage = STATIC_PAGES[action.payload.name];
+ const substitute = staticPage && staticPage.renderSubstitute && staticPage.renderSubstitute(action.payload.params);
+ const requestPage = staticPage ? substitute : {
+ name: action.payload.name,
+ params: action.payload.params
+ };
- }),
- (!section.menus.length && section.defaultPage !== action.payload.name) ? client.content({
- type: 'page',
- name: section.defaultPage,
- params: {},
- locale: state.storage.locale
- }) : Promise.resolve(null)
+ return Observable.from(client.content({
+ type: 'page',
+ locale: state.storage.locale,
+ ...requestPage
- ])).map(payload => {
- const page = payload[0];
- const defaultPage = payload[1];
-
- return renderPage.done({
- params: action.payload,
- result: {
- defaultMenu: defaultPage && defaultPage.menu !== page.menu && {
- name: defaultPage.menu,
- content: defaultPage.menutree
- },
- menu: {
- name: page.menu,
- content: page.menutree
- },
- page: {
- params: action.payload.params,
- name: action.payload.name,
- content: page.tree
+ })).flatMap(content => {
+ return Observable.concat(
+ Observable.of(renderPage.done({
+ params: action.payload,
+ result: {
+ tree: content.tree,
+ menu: content.menu,
+ menuTree: content ? content.menutree : [],
+ static: !!staticPage
}
- }
- });
+ })),
+ Observable.if(
+ () => !!action.payload.popup,
+ Observable.defer(() => Observable.of(modalShow({
+ id: 'PAGE_MODAL' + action.payload.name,
+ type: 'PAGE_MODAL',
+ params: {
+ name: action.payload.name,
+ section: action.payload.section,
+ title: action.payload.popup.title || action.payload.name,
+ width: action.payload.popup.width,
+ tree: content.tree,
+ params: action.payload.params,
+ static: !!staticPage
+ }
+ })))
+ ),
+ );
- }).catch(e =>
- Observable.of(renderPage.failed({
- params: action.payload,
- error: e.error
- }))
- );
+ }).catch(e => Observable.of(renderPage.failed({
+ params: action.payload,
+ error: e.error
+ })));
});
export default renderPageEpic;
\ No newline at end of file
diff --git a/src/app/modules/sections/epics/renderSectionEpic.ts b/src/app/modules/sections/epics/renderSectionEpic.ts
deleted file mode 100644
index db83a3a87..000000000
--- a/src/app/modules/sections/epics/renderSectionEpic.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) EGAAS S.A. All rights reserved.
- * See LICENSE in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import queryString from 'query-string';
-import { Epic } from 'modules';
-import { push } from 'connected-react-router';
-import { renderSection } from '../actions';
-
-const renderSectionEpic: Epic = (action$, store) => action$.ofAction(renderSection)
- .map(action => {
- const state = store.getState();
- const section = state.sections.sections[action.payload];
- const params = section.page ? queryString.stringify(section.page.params) : '';
- return push(`/${section.name}/${section.page ? section.page.name : ''}${params ? '?' + params : ''}`);
- });
-
-export default renderSectionEpic;
\ No newline at end of file
diff --git a/src/app/modules/sections/epics/resetOnLoginEpic.ts b/src/app/modules/sections/epics/resetOnLoginEpic.ts
deleted file mode 100644
index 20e0ea944..000000000
--- a/src/app/modules/sections/epics/resetOnLoginEpic.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) EGAAS S.A. All rights reserved.
- * See LICENSE in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import { Action } from 'redux';
-import { Epic } from 'redux-observable';
-import { IRootState } from 'modules';
-import { reset } from '../actions';
-import { login, loginGuest } from 'modules/auth/actions';
-import { isType } from 'typescript-fsa';
-
-const resetOnWalletSelectEpic: Epic =
- (action$, store) => action$.filter(action => isType(action, login.done) || isType(action, loginGuest.done))
- .map(action =>
- reset()
- );
-
-export default resetOnWalletSelectEpic;
\ No newline at end of file
diff --git a/src/app/modules/sections/epics/sectionsInitEpic.ts b/src/app/modules/sections/epics/sectionsInitEpic.ts
deleted file mode 100644
index a79caecbe..000000000
--- a/src/app/modules/sections/epics/sectionsInitEpic.ts
+++ /dev/null
@@ -1,93 +0,0 @@
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) EGAAS S.A. All rights reserved.
- * See LICENSE in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import { Epic } from 'modules';
-import { Observable } from 'rxjs/Observable';
-import { sectionsInit, navigatePage } from 'modules/sections/actions';
-
-enum RemoteSectionStatus {
- Removed = '0',
- Default = '1',
- Main = '2'
-}
-
-interface IRemoteSectionProto {
- id: string;
- title: string;
- urlname: string;
- page: string;
- roles_access: string;
- status: RemoteSectionStatus;
- order: string;
-}
-
-const sectionsInitEpic: Epic = (action$, store, { api }) => action$.ofAction(sectionsInit.started)
- .flatMap(action => {
- const state = store.getState();
- const client = api({
- apiHost: state.auth.session.network.apiHost,
- sessionToken: state.auth.session.sessionToken
- });
- const roleID = state.auth.wallet.role && state.auth.wallet.role.id;
-
- return Observable.from(Promise.all([
- client.sections({
- locale: state.storage.locale
- }),
- client.getRow({
- table: 'roles',
- id: (roleID && roleID.toString()) || null,
- }).then(row => row.value.default_page).catch(e => null)
-
- ])).flatMap(payload => {
- const remoteSections = (payload[0].list as object as IRemoteSectionProto[]).filter(l =>
- RemoteSectionStatus.Removed !== l.status
- );
-
- const mainSection = remoteSections.find(l => RemoteSectionStatus.Main === l.status) || remoteSections[0];
- const sections = [
- {
- ...mainSection,
- page: payload[1] || mainSection.page
- },
- ...remoteSections.filter(l => l.id !== mainSection.id)
- ].sort((a, b) =>
- Number(a.order) - Number(b.order) || Number(a.id) - Number(b.id)
- );
-
- return Observable.concat(
- Observable.of(sectionsInit.done({
- params: action.payload,
- result: {
- mainSection: mainSection.urlname,
- section: action.payload,
- sections: [
- ...sections.map(l => ({
- key: null,
- name: l.urlname,
- title: l.title,
- visible: true,
- defaultPage: l.page,
- pending: false,
- force: false,
- menus: [],
- menuVisible: true,
- page: null
- }))
- ]
- },
- })),
- action.payload ? Observable.empty() : Observable.of(navigatePage.started({
- section: mainSection.urlname,
- params: {}
- }))
- );
- }).catch(e => Observable.of(sectionsInit.failed({
- params: action.payload,
- error: e
- })));
- }).catch(e => Observable.empty());
-
-export default sectionsInitEpic;
\ No newline at end of file
diff --git a/src/app/modules/sections/reducer.ts b/src/app/modules/sections/reducer.ts
index 3571ba74d..bbc350431 100644
--- a/src/app/modules/sections/reducer.ts
+++ b/src/app/modules/sections/reducer.ts
@@ -5,67 +5,32 @@
import * as actions from './actions';
import { reducerWithInitialState } from 'typescript-fsa-reducers';
-import { TSection } from 'apla/content';
-import closeSectionHandler from './reducers/closeSectionHandler';
-import renderSectionHandler from './reducers/renderSectionHandler';
-import switchSectionHandler from './reducers/switchSectionHandler';
+import { ISection } from 'apla/content';
import updateSectionHandler from './reducers/updateSectionHandler';
-import resetHandler from './reducers/resetHandler';
-import sectionsInitDoneHandler from './reducers/sectionsInitDoneHandler';
+import sectionsInitHandler from './reducers/sectionsInitHandler';
import menuPopHandler from './reducers/menuPopHandler';
import menuPushHandler from './reducers/menuPushHandler';
-import navigatePageDoneHandler from './reducers/navigatePageDoneHandler';
-import navigationToggleHandler from './reducers/navigationToggleHandler';
-import renderLegacyPageDoneHandler from './reducers/renderLegacyPageDoneHandler';
-import renderLegacyPageHandler from './reducers/renderLegacyPageHandler';
import renderPageDoneHandler from './reducers/renderPageDoneHandler';
import renderPageFailedHandler from './reducers/renderPageFailedHandler';
import renderPageHandler from './reducers/renderPageHandler';
export type State = {
readonly mainSection: string;
- readonly section: string;
readonly sections: {
- readonly [name: string]: TSection;
+ readonly [name: string]: ISection;
};
- readonly systemSections: TSection[];
- readonly inited: boolean;
};
export const initialState: State = {
- mainSection: null,
- section: null,
- sections: {},
- systemSections: [{
- key: 'editor',
- name: 'editor',
- title: 'Editor',
- visible: false,
- closeable: true,
- defaultPage: 'editor',
- pending: false,
- force: false,
- menus: [],
- menuDisabled: true,
- menuVisible: true,
- page: null
- }],
- inited: false
+ mainSection: 'home',
+ sections: {}
};
export default reducerWithInitialState(initialState)
- .case(actions.closeSection, closeSectionHandler)
- .case(actions.renderSection, renderSectionHandler)
- .case(actions.switchSection, switchSectionHandler)
.case(actions.updateSection, updateSectionHandler)
- .case(actions.reset, resetHandler)
.case(actions.menuPop, menuPopHandler)
.case(actions.menuPush, menuPushHandler)
- .case(actions.navigatePage.done, navigatePageDoneHandler)
- .case(actions.navigationToggle, navigationToggleHandler)
- .case(actions.renderLegacyPage.done, renderLegacyPageDoneHandler)
- .case(actions.renderLegacyPage.started, renderLegacyPageHandler)
.case(actions.renderPage.done, renderPageDoneHandler)
.case(actions.renderPage.failed, renderPageFailedHandler)
.case(actions.renderPage.started, renderPageHandler)
- .case(actions.sectionsInit.done, sectionsInitDoneHandler);
+ .case(actions.sectionsInit, sectionsInitHandler);
\ No newline at end of file
diff --git a/src/app/modules/sections/reducers/closeSectionHandler.ts b/src/app/modules/sections/reducers/closeSectionHandler.ts
deleted file mode 100644
index 46554ebbd..000000000
--- a/src/app/modules/sections/reducers/closeSectionHandler.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) EGAAS S.A. All rights reserved.
- * See LICENSE in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import { State } from '../reducer';
-import { renderSection } from '../actions';
-import { Reducer } from 'modules';
-
-const closeSectionHandler: Reducer = (state, payload) => {
- return state.sections[payload] ? {
- ...state,
- sections: {
- ...state.sections,
- [payload]: {
- ...state.sections[payload],
- visible: false
- }
- }
- } : state;
-};
-
-export default closeSectionHandler;
\ No newline at end of file
diff --git a/src/app/modules/sections/reducers/menuPopHandler.ts b/src/app/modules/sections/reducers/menuPopHandler.ts
index c5f498199..ac832c116 100644
--- a/src/app/modules/sections/reducers/menuPopHandler.ts
+++ b/src/app/modules/sections/reducers/menuPopHandler.ts
@@ -7,22 +7,21 @@ import { State } from '../reducer';
import { menuPop } from '../actions';
import { Reducer } from 'modules';
-const menuPopHandler: Reducer = (state, payload) => {
- if (1 >= state.sections[state.section].menus.length) {
+const menuPopHandler: Reducer = (state, section): State => {
+ if (1 >= state.sections[section].menus.length) {
return state;
}
- else {
- return {
- ...state,
- sections: {
- ...state.sections,
- [state.section]: {
- ...state.sections[state.section],
- menus: state.sections[state.section].menus.slice(0, -1)
- }
+
+ return {
+ ...state,
+ sections: {
+ ...state.sections,
+ [section]: {
+ ...state.sections[section],
+ menus: state.sections[section].menus.slice(0, -1)
}
- };
- }
+ }
+ };
};
export default menuPopHandler;
\ No newline at end of file
diff --git a/src/app/modules/sections/reducers/menuPushHandler.ts b/src/app/modules/sections/reducers/menuPushHandler.ts
index 97dbeefc0..bc9559a0c 100644
--- a/src/app/modules/sections/reducers/menuPushHandler.ts
+++ b/src/app/modules/sections/reducers/menuPushHandler.ts
@@ -6,25 +6,14 @@
import { State } from '../reducer';
import { menuPush } from '../actions';
import { Reducer } from 'modules';
+import upsertSectionMenu from '../util/upsertSectionMenu';
-const menuPushHandler: Reducer = (state, payload) => {
- const menuIndex = state.sections[state.section].menus.findIndex(l =>
- l.name === payload.name);
-
- return {
- ...state,
- sections: {
- ...state.sections,
- [state.section]: {
- ...state.sections[state.section],
- menus: -1 === menuIndex ? [...state.sections[state.section].menus, payload] : [
- ...state.sections[state.section].menus.slice(0, menuIndex),
- payload,
- ...state.sections[state.section].menus.slice(menuIndex + 1)
- ]
- }
- }
- };
-};
+const menuPushHandler: Reducer = (state, payload): State => ({
+ ...state,
+ sections: {
+ ...state.sections,
+ [payload.section]: upsertSectionMenu(state.sections[payload.section], payload.menu)
+ }
+});
export default menuPushHandler;
\ No newline at end of file
diff --git a/src/app/modules/sections/reducers/navigatePageDoneHandler.ts b/src/app/modules/sections/reducers/navigatePageDoneHandler.ts
deleted file mode 100644
index 8ce80fced..000000000
--- a/src/app/modules/sections/reducers/navigatePageDoneHandler.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) EGAAS S.A. All rights reserved.
- * See LICENSE in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import { State } from '../reducer';
-import { navigatePage } from '../actions';
-import { Reducer } from 'modules';
-
-const navigatePageDoneHandler: Reducer = (state, payload) => ({
- ...state,
- section: payload.result.section,
- sections: {
- ...state.sections,
- [payload.result.section]: {
- ...state.sections[payload.result.section],
- page: state.sections[payload.result.section].page,
- force: payload.params.force,
- pending: false
- }
- }
-});
-
-export default navigatePageDoneHandler;
\ No newline at end of file
diff --git a/src/app/modules/sections/reducers/navigationToggleHandler.ts b/src/app/modules/sections/reducers/navigationToggleHandler.ts
deleted file mode 100644
index fce1f9bc1..000000000
--- a/src/app/modules/sections/reducers/navigationToggleHandler.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) EGAAS S.A. All rights reserved.
- * See LICENSE in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import { State } from '../reducer';
-import { navigationToggle } from '../actions';
-import { Reducer } from 'modules';
-
-const navigationToggleHandler: Reducer = (state, payload) => ({
- ...state,
- sections: {
- ...state.sections,
- [state.section]: {
- ...state.sections[state.section],
- menuVisible: !state.sections[state.section].menuVisible
- }
- }
-});
-
-export default navigationToggleHandler;
\ No newline at end of file
diff --git a/src/app/modules/sections/reducers/renderLegacyPageDoneHandler.ts b/src/app/modules/sections/reducers/renderLegacyPageDoneHandler.ts
deleted file mode 100644
index 9345922a4..000000000
--- a/src/app/modules/sections/reducers/renderLegacyPageDoneHandler.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) EGAAS S.A. All rights reserved.
- * See LICENSE in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import { State } from '../reducer';
-import { renderLegacyPage } from '../actions';
-import { Reducer } from 'modules';
-
-const renderLegacyPageDoneHandler: Reducer = (state, payload) => {
- const section = payload.params.section;
- const menuIndex = payload.result.menu ? state.sections[section].menus.findIndex(l =>
- l.name === payload.result.menu.name) : -1;
-
- return {
- ...state,
- sections: {
- ...state.sections,
- [section]: {
- ...state.sections[section],
- menus: -1 === menuIndex ?
- (payload.params.menu ? [
- ...state.sections[section].menus,
- payload.result.menu
- ] : state.sections[section].menus) : [
- ...state.sections[section].menus.slice(0, menuIndex),
- payload.result.menu,
- ...state.sections[section].menus.slice(menuIndex + 1),
- ],
- page: {
- name: payload.params.name,
- content: payload.result.page.content,
- legacy: true,
- params: payload.params.params
- },
- pending: false
- }
- }
- };
-};
-
-export default renderLegacyPageDoneHandler;
\ No newline at end of file
diff --git a/src/app/modules/sections/reducers/renderLegacyPageHandler.ts b/src/app/modules/sections/reducers/renderLegacyPageHandler.ts
deleted file mode 100644
index cec8bc7b5..000000000
--- a/src/app/modules/sections/reducers/renderLegacyPageHandler.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) EGAAS S.A. All rights reserved.
- * See LICENSE in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import { State } from '../reducer';
-import { renderLegacyPage } from '../actions';
-import { Reducer } from 'modules';
-
-const renderLegacyPageHandler: Reducer = (state, payload) => ({
- ...state,
- sections: {
- ...state.sections,
- [payload.section]: {
- ...state.sections[payload.section],
- force: false,
- pending: true
- }
- }
-});
-
-export default renderLegacyPageHandler;
\ No newline at end of file
diff --git a/src/app/modules/sections/reducers/renderPageDoneHandler.ts b/src/app/modules/sections/reducers/renderPageDoneHandler.ts
index 5802dd9cc..79e8995ea 100644
--- a/src/app/modules/sections/reducers/renderPageDoneHandler.ts
+++ b/src/app/modules/sections/reducers/renderPageDoneHandler.ts
@@ -6,54 +6,31 @@
import { State } from '../reducer';
import { renderPage } from '../actions';
import { Reducer } from 'modules';
-import { TMenu } from 'apla/content';
-const renderPageDoneHandler: Reducer = (state, payload) => {
- const section = payload.params.section;
- const menuIndex = state.sections[section].menus.findIndex(l =>
- l.name === payload.result.menu.name);
-
- let menus: TMenu[] = [];
-
- if (state.sections[section].menus.length) {
- if (-1 === menuIndex) {
- menus = [
- ...state.sections[section].menus,
- payload.result.menu
- ];
- }
- else {
- menus = [
- ...state.sections[section].menus.slice(0, menuIndex),
- payload.result.menu,
- ...state.sections[section].menus.slice(menuIndex + 1),
- ];
- }
- }
- else if (payload.result.defaultMenu) {
- menus = [
- payload.result.defaultMenu,
- payload.result.menu
- ];
- }
- else {
- menus = [
- payload.result.menu
- ];
+const renderPageDoneHandler: Reducer = (state, payload): State => {
+ if (payload.params.popup) {
+ return state;
}
return {
...state,
sections: {
...state.sections,
- [section]: {
- ...state.sections[section],
- menus,
+ [payload.params.section]: {
+ ...state.sections[payload.params.section],
page: {
- ...payload.result.page,
- params: payload.params.params
+ name: payload.params.name,
+ status: 'LOADED',
+ content: payload.result.tree,
+ static: payload.result.static,
+ params: payload.params.params,
+ error: undefined,
+ location: payload.params.location,
},
- pending: false
+ menus: [{
+ name: payload.result.menu,
+ content: payload.result.menuTree
+ }]
}
}
};
diff --git a/src/app/modules/sections/reducers/renderPageFailedHandler.ts b/src/app/modules/sections/reducers/renderPageFailedHandler.ts
index 028bfa27e..bbb2a4895 100644
--- a/src/app/modules/sections/reducers/renderPageFailedHandler.ts
+++ b/src/app/modules/sections/reducers/renderPageFailedHandler.ts
@@ -6,22 +6,32 @@
import { State } from '../reducer';
import { renderPage } from '../actions';
import { Reducer } from 'modules';
+import changeBreadcrumbType from '../util/changeBreadcrumbType';
-const renderPageFailedHandler: Reducer = (state, payload) => ({
- ...state,
- sections: {
- ...state.sections,
- [payload.params.section]: {
- ...state.sections[payload.params.section],
- page: {
- params: payload.params.params,
- name: payload.params.name,
- content: null,
- error: payload.error
- },
- pending: false
- }
+const renderPageFailedHandler: Reducer = (state, payload): State => {
+ if (payload.params.popup) {
+ return state;
}
-});
+
+ return {
+ ...state,
+ sections: {
+ ...state.sections,
+ [payload.params.section]: {
+ ...state.sections[payload.params.section],
+ page: {
+ name: payload.params.name,
+ status: 'ERROR',
+ content: [],
+ static: false,
+ params: payload.params.params,
+ error: payload.error,
+ location: payload.params.location,
+ },
+ breadcrumbs: changeBreadcrumbType(state.sections[payload.params.section], payload.params.name, 'IGNORE')
+ }
+ }
+ };
+};
export default renderPageFailedHandler;
\ No newline at end of file
diff --git a/src/app/modules/sections/reducers/renderPageHandler.ts b/src/app/modules/sections/reducers/renderPageHandler.ts
index 7f28cf42f..8b8e8a4d4 100644
--- a/src/app/modules/sections/reducers/renderPageHandler.ts
+++ b/src/app/modules/sections/reducers/renderPageHandler.ts
@@ -6,18 +6,42 @@
import { State } from '../reducer';
import { renderPage } from '../actions';
import { Reducer } from 'modules';
+import upsertSectionBreadcrumb from '../util/upsertSectionBreadcrumb';
-const renderPageHandler: Reducer = (state, payload) => ({
- ...state,
- sections: {
- ...state.sections,
- [payload.section]: {
- ...state.sections[payload.section],
- force: false,
- pending: true,
- visible: true
- }
+const renderPageHandler: Reducer = (state, payload): State => {
+ if (payload.popup) {
+ return state;
}
-});
+
+ return {
+ ...state,
+ sections: {
+ ...state.sections,
+ [payload.section]: {
+ ...state.sections[payload.section],
+ page: {
+ name: payload.name,
+ status: 'PENDING',
+ content: [],
+ static: false,
+ params: payload.params,
+ error: undefined,
+ location: payload.location,
+ },
+ breadcrumbs: upsertSectionBreadcrumb(
+ state.sections[payload.section],
+ {
+ caller: payload.location.state && payload.location.state.from && payload.location.state.from.name,
+ type: (payload.location.state && payload.location.state.from) ? payload.location.state.from.type : 'IGNORE',
+ title: payload.location.state && payload.location.state.from && payload.location.state.from.title,
+ section: payload.section,
+ page: payload.name,
+ params: payload.params
+ }
+ )
+ }
+ }
+ };
+};
export default renderPageHandler;
\ No newline at end of file
diff --git a/src/app/modules/sections/reducers/renderSectionHandler.ts b/src/app/modules/sections/reducers/renderSectionHandler.ts
deleted file mode 100644
index 8d9310da7..000000000
--- a/src/app/modules/sections/reducers/renderSectionHandler.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) EGAAS S.A. All rights reserved.
- * See LICENSE in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import { State } from '../reducer';
-import { renderSection } from '../actions';
-import { Reducer } from 'modules';
-
-const renderSectionHandler: Reducer = (state, payload) => {
- return state.sections[payload] ? {
- ...state,
- section: payload
- } : state;
-};
-
-export default renderSectionHandler;
\ No newline at end of file
diff --git a/src/app/modules/sections/reducers/sectionsInitDoneHandler.ts b/src/app/modules/sections/reducers/sectionsInitDoneHandler.ts
deleted file mode 100644
index f693df0e3..000000000
--- a/src/app/modules/sections/reducers/sectionsInitDoneHandler.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) EGAAS S.A. All rights reserved.
- * See LICENSE in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import { State } from '../reducer';
-import { sectionsInit } from '../actions';
-import { Reducer } from 'modules';
-import { TSection } from 'apla/content';
-
-const sectionsInitDoneHandler: Reducer = (state, payload) => {
- const sections: { [key: string]: TSection } = {};
- payload.result.sections.forEach(section => {
- sections[section.name] = section;
- });
-
- state.systemSections.forEach(section => {
- sections[section.name] = section;
- });
-
- return {
- ...state,
- inited: true,
- mainSection: payload.result.mainSection,
- section: payload.result.section,
- sections
- };
-};
-
-export default sectionsInitDoneHandler;
\ No newline at end of file
diff --git a/src/app/modules/auth/reducers/changeSeedConfirmation.ts b/src/app/modules/sections/reducers/sectionsInitHandler.ts
similarity index 62%
rename from src/app/modules/auth/reducers/changeSeedConfirmation.ts
rename to src/app/modules/sections/reducers/sectionsInitHandler.ts
index 6a5ef902e..37ce5ef89 100644
--- a/src/app/modules/auth/reducers/changeSeedConfirmation.ts
+++ b/src/app/modules/sections/reducers/sectionsInitHandler.ts
@@ -4,12 +4,13 @@
*--------------------------------------------------------------------------------------------*/
import { State } from '../reducer';
-import { changeSeed } from '../actions';
+import { sectionsInit } from '../actions';
import { Reducer } from 'modules';
-const changeSeedConfirmationHandler: Reducer = (state, payload) => ({
+const sectionsInitHandler: Reducer = (state, payload): State => ({
...state,
- seedConfirm: payload
+ mainSection: payload.mainSection,
+ sections: payload.sections
});
-export default changeSeedConfirmationHandler;
\ No newline at end of file
+export default sectionsInitHandler;
\ No newline at end of file
diff --git a/src/app/modules/sections/reducers/switchSectionHandler.ts b/src/app/modules/sections/reducers/switchSectionHandler.ts
deleted file mode 100644
index d8e937010..000000000
--- a/src/app/modules/sections/reducers/switchSectionHandler.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) EGAAS S.A. All rights reserved.
- * See LICENSE in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import { State } from '../reducer';
-import { renderSection } from '../actions';
-import { Reducer } from 'modules';
-
-const switchSectionHandler: Reducer = (state, payload) => {
- return state.sections[payload] ? {
- ...state,
- section: payload
- } : state;
-};
-
-export default switchSectionHandler;
\ No newline at end of file
diff --git a/src/app/modules/sections/reducers/updateSectionHandler.ts b/src/app/modules/sections/reducers/updateSectionHandler.ts
index ac2fef714..dcf1dfc33 100644
--- a/src/app/modules/sections/reducers/updateSectionHandler.ts
+++ b/src/app/modules/sections/reducers/updateSectionHandler.ts
@@ -7,7 +7,7 @@ import { State } from '../reducer';
import { updateSection } from '../actions';
import { Reducer } from 'modules';
-const updateSectionHandler: Reducer = (state, payload) => ({
+const updateSectionHandler: Reducer = (state, payload): State => ({
...state,
sections: {
...state.sections,
diff --git a/src/app/modules/sections/util/changeBreadcrumbType.ts b/src/app/modules/sections/util/changeBreadcrumbType.ts
new file mode 100644
index 000000000..bc5a9a024
--- /dev/null
+++ b/src/app/modules/sections/util/changeBreadcrumbType.ts
@@ -0,0 +1,22 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) EGAAS S.A. All rights reserved.
+ * See LICENSE in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+import { ISection, TBreadcrumbType } from 'apla/content';
+
+const changeBreadcrumbType = (section: ISection, page: string, type: TBreadcrumbType) => {
+ return section.breadcrumbs.map(b => {
+ if (page === b.page) {
+ return {
+ ...b,
+ type
+ };
+ }
+ else {
+ return b;
+ }
+ });
+};
+
+export default changeBreadcrumbType;
\ No newline at end of file
diff --git a/src/app/modules/sections/util/findBreadcrumb.ts b/src/app/modules/sections/util/findBreadcrumb.ts
new file mode 100644
index 000000000..c181b0c9e
--- /dev/null
+++ b/src/app/modules/sections/util/findBreadcrumb.ts
@@ -0,0 +1,24 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) EGAAS S.A. All rights reserved.
+ * See LICENSE in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+import { ISection, IBreadcrumb } from 'apla/content';
+
+const findBreadcrumb = (section: ISection, breadcrumb: IBreadcrumb) => {
+ const pageIndex = section.breadcrumbs.findIndex(m =>
+ m.page === breadcrumb.page
+ );
+
+ if (-1 !== pageIndex) {
+ return pageIndex;
+ }
+
+ const callerIndex = section.breadcrumbs.findIndex(m =>
+ m.caller === breadcrumb.caller && m.type === breadcrumb.type
+ );
+
+ return callerIndex;
+};
+
+export default findBreadcrumb;
\ No newline at end of file
diff --git a/src/app/modules/sections/reducers/resetHandler.ts b/src/app/modules/sections/util/findMenu.ts
similarity index 55%
rename from src/app/modules/sections/reducers/resetHandler.ts
rename to src/app/modules/sections/util/findMenu.ts
index 16900d1e2..afd09817d 100644
--- a/src/app/modules/sections/reducers/resetHandler.ts
+++ b/src/app/modules/sections/util/findMenu.ts
@@ -3,13 +3,9 @@
* See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
-import { State } from '../reducer';
-import { reset } from '../actions';
-import { Reducer } from 'modules';
+import { ISection } from 'apla/content';
-const resetHandler: Reducer = (state, payload) => ({
- ...state,
- inited: false
-});
+const findMenu = (section: ISection, name: string) =>
+ section.menus.findIndex(m => m.name === name);
-export default resetHandler;
\ No newline at end of file
+export default findMenu;
\ No newline at end of file
diff --git a/src/app/modules/sections/util/upsertSectionBreadcrumb.ts b/src/app/modules/sections/util/upsertSectionBreadcrumb.ts
new file mode 100644
index 000000000..eeae4b3e9
--- /dev/null
+++ b/src/app/modules/sections/util/upsertSectionBreadcrumb.ts
@@ -0,0 +1,36 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) EGAAS S.A. All rights reserved.
+ * See LICENSE in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+import { ISection, IBreadcrumb } from 'apla/content';
+import findBreadcrumb from './findBreadcrumb';
+
+const upsertSectionBreadcrumb = (section: ISection, crumb: IBreadcrumb) => {
+ const crumbIndex = findBreadcrumb(section, crumb);
+ let breadcrumbs: IBreadcrumb[];
+
+ if (-1 !== crumbIndex) {
+ const oldValue = section.breadcrumbs[crumbIndex];
+
+ breadcrumbs = [
+ ...section.breadcrumbs.slice(0, crumbIndex).filter(l => 'IGNORE' !== l.type),
+ {
+ ...section.breadcrumbs[crumbIndex],
+ page: crumb.page,
+ title: crumb.title || oldValue.title,
+ params: crumb.params
+ }
+ ];
+ }
+ else {
+ breadcrumbs = [
+ ...section.breadcrumbs.filter(l => 'IGNORE' !== l.type),
+ crumb
+ ];
+ }
+
+ return breadcrumbs;
+};
+
+export default upsertSectionBreadcrumb;
\ No newline at end of file
diff --git a/src/app/modules/sections/util/upsertSectionMenu.ts b/src/app/modules/sections/util/upsertSectionMenu.ts
new file mode 100644
index 000000000..477461857
--- /dev/null
+++ b/src/app/modules/sections/util/upsertSectionMenu.ts
@@ -0,0 +1,35 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) EGAAS S.A. All rights reserved.
+ * See LICENSE in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+import { IMenu, ISection } from 'apla/content';
+import findMenu from './findMenu';
+
+const upsertSectionMenu = (section: ISection, menu: IMenu): ISection => {
+ const menuIndex = findMenu(section, menu.name);
+ let menus: IMenu[];
+
+ if (-1 !== menuIndex) {
+ menus = [
+ ...section.menus.slice(0, menuIndex),
+ {
+ ...section.menus[menuIndex],
+ ...menu
+ }
+ ];
+ }
+ else {
+ menus = [
+ ...section.menus,
+ menu
+ ];
+ }
+
+ return {
+ ...section,
+ menus
+ };
+};
+
+export default upsertSectionMenu;
\ No newline at end of file
diff --git a/src/app/modules/socket/epics/subscribeEpic.ts b/src/app/modules/socket/epics/subscribeEpic.ts
index 28cfc81df..159a5a71d 100644
--- a/src/app/modules/socket/epics/subscribeEpic.ts
+++ b/src/app/modules/socket/epics/subscribeEpic.ts
@@ -7,8 +7,10 @@ import { Action } from 'redux';
import { Observable } from 'rxjs/Observable';
import { Epic } from 'modules';
import { Observer } from 'rxjs';
-import { setBadgeCount } from 'modules/gui/actions';
import { subscribe, setNotificationsCount } from '../actions';
+import { fetchNotifications } from 'modules/content/actions';
+import findNotificationsCount from '../util/findNotificationsCount';
+import platform from 'lib/platform';
const subscribeEpic: Epic = (action$, store) => action$.ofAction(subscribe.started)
.flatMap(action => {
@@ -32,6 +34,8 @@ const subscribeEpic: Epic = (action$, store) => action$.ofAction(subscribe.start
message.data.forEach(n => {
const subState = store.getState();
+ const notifications = findNotificationsCount(subState.socket, subState.auth.wallet);
+
if (subState.auth.isAuthenticated &&
(
subState.auth.wallet.role && subState.auth.wallet.role.id === n.role_id ||
@@ -50,9 +54,17 @@ const subscribeEpic: Epic = (action$, store) => action$.ofAction(subscribe.start
role: n.role_id,
count: n.count
}));
+
+ const notificationsNew = findNotificationsCount(subState.socket, subState.auth.wallet);
+ if (notifications !== notificationsNew) {
+ observer.next(fetchNotifications.started(undefined));
+ }
});
- observer.next(setBadgeCount(count));
+ platform.on('desktop', () => {
+ const Electron = require('electron');
+ Electron.remote.app.setBadgeCount(count);
+ });
});
observer.next(subscribe.done({
diff --git a/src/app/modules/socket/util/findNotifications.ts b/src/app/modules/socket/util/findNotifications.ts
new file mode 100644
index 000000000..1979655eb
--- /dev/null
+++ b/src/app/modules/socket/util/findNotifications.ts
@@ -0,0 +1,29 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) EGAAS S.A. All rights reserved.
+ * See LICENSE in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+import { State } from 'modules/socket';
+import { IAccountContext } from 'apla/auth';
+
+const findNotifications = (state: State, session: IAccountContext) => {
+ if (!session) {
+ return [];
+ }
+
+ if (!session.access) {
+ return [];
+ }
+
+ if (!session.wallet) {
+ return [];
+ }
+
+ return state.notifications.filter(notification =>
+ notification.id === session.wallet.id &&
+ notification.ecosystem === session.access.ecosystem &&
+ (session.role && notification.role === session.role.id || notification.role === '0')
+ );
+};
+
+export default findNotifications;
\ No newline at end of file
diff --git a/src/app/modules/socket/util/findNotificationsCount.ts b/src/app/modules/socket/util/findNotificationsCount.ts
new file mode 100644
index 000000000..1bc57de05
--- /dev/null
+++ b/src/app/modules/socket/util/findNotificationsCount.ts
@@ -0,0 +1,22 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) EGAAS S.A. All rights reserved.
+ * See LICENSE in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+import { State } from 'modules/socket';
+import { IAccountContext } from 'apla/auth';
+import findNotifications from './findNotifications';
+
+const findNotificationsCount = (state: State, session: IAccountContext) => {
+ const notifications = findNotifications(state, session);
+
+ if (!notifications.length) {
+ return 0;
+ }
+
+ return notifications
+ .map(notification => notification.count)
+ .reduce((a, b) => a + b);
+};
+
+export default findNotificationsCount;
\ No newline at end of file
diff --git a/src/app/modules/storage/actions.ts b/src/app/modules/storage/actions.ts
index 7a4e2416e..a0f6a4eae 100644
--- a/src/app/modules/storage/actions.ts
+++ b/src/app/modules/storage/actions.ts
@@ -16,7 +16,7 @@ export const savePreconfiguredNetworks = actionCreator('SAVE_PRECONF
export const removeNetwork = actionCreator('REMOVE_NETWORK');
export const saveWallet = actionCreator