diff --git a/package.json b/package.json
index 8076fe8..3adbdcb 100644
--- a/package.json
+++ b/package.json
@@ -29,7 +29,6 @@
"normalize.css": "^8.0.1",
"react": "^16.13.1",
"react-dom": "^16.13.1",
- "react-redux": "^7.2.1",
"react-router": "^5.2.0",
"react-router-dom": "^5.2.0",
"react-scripts": "3.4.3",
diff --git a/public/index.html b/public/index.html
index 70ec97a..9ced9cc 100644
--- a/public/index.html
+++ b/public/index.html
@@ -36,7 +36,7 @@
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
-
React App
+ Evo Calculator
diff --git a/src/client/Containers/Calculation/Sections/index.ts b/src/client/Containers/Calculation/Sections/index.ts
index 572b8e4..7003d4a 100644
--- a/src/client/Containers/Calculation/Sections/index.ts
+++ b/src/client/Containers/Calculation/Sections/index.ts
@@ -1,54 +1,46 @@
-import CalculationStore from "client/stores/CalculationStore";
-import withTitle from "client/hocs/withTitle";
-import { testEffectForPrice, testEffectForOne } from "client/Effects";
-import Input from "client/Elements/Input";
+import CalculationStore from 'client/stores/CalculationStore';
+import withTitle from 'client/hocs/withTitle';
+import Input from 'client/Elements/Input';
export default [
{
- title: "FirstSection",
+ title: 'FirstSection',
elements: [
{
- name: "tbxPrice",
- Component: withTitle("Price")(Input),
+ name: 'tbxPrice',
+ Component: withTitle('Price')(Input),
props: {
- placeholder: "Enter price",
- sourceValueName: "price",
- Effects: [testEffectForPrice],
- },
+ placeholder: 'Enter price',
+ sourceValueName: 'price'
+ }
},
{
- name: "tbxOne",
- Component: withTitle("One")(Input),
+ name: 'tbxOne',
+ Component: withTitle('One')(Input),
props: {
- placeholder: "Enter one",
- sourceValueName: "one",
- Effects: [testEffectForOne],
- },
+ placeholder: 'Enter one',
+ sourceValueName: 'one'
+ }
},
{
- name: "tbxSecond",
- Component: withTitle("Sum")(Input),
+ name: 'total',
+ Component: withTitle('Total')(Input),
props: {
- readonly: true,
- getValue: (calculationStore: CalculationStore) => {
- const price = calculationStore.getValue("price");
- const one = calculationStore.getValue("one");
- return parseInt(price) + parseInt(one);
- },
- },
- },
- ],
+ computed: 'total'
+ }
+ }
+ ]
},
{
- title: "SecondSection",
+ title: 'SecondSection',
elements: [
{
- name: "priceonAnotherTab",
- Component: withTitle("Price on another tab")(Input),
+ name: 'priceonAnotherTab',
+ Component: withTitle('Price on another tab')(Input),
props: {
- sourceValueName: "price",
- },
- },
- ],
- },
+ sourceValueName: 'price'
+ }
+ }
+ ]
+ }
];
diff --git a/src/client/Containers/Calculation/index.jsx b/src/client/Containers/Calculation/index.jsx
index d12b1cd..ae73e4c 100644
--- a/src/client/Containers/Calculation/index.jsx
+++ b/src/client/Containers/Calculation/index.jsx
@@ -1,9 +1,9 @@
-import Background from "client/Elements/Background";
-import React, { useState } from "react";
-import Sections from "./Sections";
+import Background from 'client/Elements/Background';
+import React, { useState } from 'react';
+import Sections from './Sections';
-import { Tabs } from "antd";
-import { Box } from "client/UIKit/grid";
+import { Tabs } from 'antd';
+import { Box } from 'client/UIKit/grid';
const { TabPane } = Tabs;
const Calculation = () => {
@@ -14,8 +14,8 @@ const Calculation = () => {
{elements.map(({ Component, props }, ie) => {
return (
-
-
+
+
);
})}
diff --git a/src/client/Effects/index.ts b/src/client/Effects/index.ts
deleted file mode 100644
index fa9e4ff..0000000
--- a/src/client/Effects/index.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-import CalculationStore from "client/stores/CalculationStore";
-import { TEffect } from "core/types/effect";
-
-export const testEffectForPrice: TEffect = async (
- calculationStore: CalculationStore
-) => {
- console.log("priceEffect");
- const price = calculationStore.getValue("price");
- if (parseInt(price) > 5000) {
- calculationStore.setValue("one", 200);
- }
-};
-
-export const testEffectForOne: TEffect = async (
- calculationStore: CalculationStore
-) => {
- const one = calculationStore.getValue("one");
- if (parseInt(one) > 1000) {
- calculationStore.setValue("price", 100500);
- }
-};
diff --git a/src/client/Elements/Input.jsx b/src/client/Elements/Input.jsx
index 022d60b..f4fb370 100644
--- a/src/client/Elements/Input.jsx
+++ b/src/client/Elements/Input.jsx
@@ -1,47 +1,35 @@
-import { Input as AntInput } from "antd";
-import { useStores } from "client/hooks/useStores";
-import runEffects from "client/tools/runEffects";
-import { observer } from "mobx-react";
-import React, { useEffect, useState } from "react";
-import { useDebounce } from "use-debounce";
+import { Input as AntInput } from 'antd';
+import { useStores } from 'client/hooks/useStores';
+import { observer } from 'mobx-react';
+import React, { useEffect, useState } from 'react';
+import { useDebounce } from 'use-debounce';
-const Input = ({
- readonly,
- placeholder,
- sourceValueName,
- getValue,
- Effects,
-}) => {
+const Input = ({ readonly, placeholder, sourceValueName, computed }) => {
const { calculationStore } = useStores();
- const sourceValue = calculationStore.getValue(sourceValueName);
const [currentValue, setCurrentValue] = useState(undefined);
const [debouncedValue] = useDebounce(currentValue, 850);
- // get Values
- useEffect(() => {
- if (sourceValueName) {
- if (sourceValue) {
- setCurrentValue(sourceValue);
- }
- }
- }, [sourceValue, sourceValueName]);
+ const sourceValue = calculationStore.values[sourceValueName];
- // set Value to global store and run Effects
+ // get value from store
useEffect(() => {
- if (sourceValueName && debouncedValue) {
+ if (!computed) {
+ setCurrentValue(sourceValue);
+ }
+ }, [computed, sourceValue]);
+
+ // set value to store
+ useEffect(() => {
+ if (!computed) {
calculationStore.setValue(sourceValueName, debouncedValue);
}
-
- if (Effects && Effects.length > 0) {
- runEffects(Effects, calculationStore);
- }
- }, [debouncedValue]);
+ }, [calculationStore, computed, debouncedValue, sourceValueName]);
return (
{
+ value={computed ? calculationStore[computed]() : currentValue}
+ onChange={e => {
if (!readonly) {
setCurrentValue(e.target.value);
}
diff --git a/src/client/Layout/index.jsx b/src/client/Layout/index.jsx
index 08be2e8..d039693 100644
--- a/src/client/Layout/index.jsx
+++ b/src/client/Layout/index.jsx
@@ -1,9 +1,9 @@
-import paths from "client/common/paths";
-import { LogoText } from "client/Elements/Text";
-import colors from "client/UIKit/colors";
-import { Box, Flex } from "client/UIKit/grid";
-import React from "react";
-import { Route, Switch } from "react-router-dom";
+import paths from 'client/common/paths';
+import { LogoText } from 'client/Elements/Text';
+import colors from 'client/UIKit/colors';
+import { Box, Flex } from 'client/UIKit/grid';
+import React from 'react';
+import { Route, Switch } from 'react-router-dom';
const Header = () => (
@@ -43,18 +43,17 @@ const Layout = () => (
const styles = {
root: {
- height: "100%",
+ height: '100%'
},
- flex: { width: "100%" },
+ flex: { width: '100%' },
header: {
// backgroundColor: colors.violet.shades[700],
- background:
- "linear-gradient(90deg, rgba(69,0,198,1) 0%, rgba(205,0,231,1) 60%, rgba(163,2,184,1) 100%)",
- height: "50px",
- padding: "10px 12px",
- paddingLeft: "20px",
+ background: 'linear-gradient(90deg, #1C01A9 0%, #3A0185 50%, #580161 100%)',
+ height: '50px',
+ padding: '10px 12px',
+ paddingLeft: '20px'
// borderRadius: "0 0 10px 10px",
- },
+ }
};
export default Layout;
diff --git a/src/client/stores/CalculationStore/CalculationStore.ts b/src/client/stores/CalculationStore/CalculationStore.ts
deleted file mode 100644
index 6304330..0000000
--- a/src/client/stores/CalculationStore/CalculationStore.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-import initialStatuses from "core/config/initialStatuses";
-import initialValues from "core/config/initialValues";
-import { SourceValueNames } from "core/types/values";
-import { action, observable } from "mobx";
-import { Status } from "core/types/elements";
-
-class CalculationStore {
- values = observable(initialValues);
- statuses = observable(initialStatuses);
-
- getValue = (sourceValueName: SourceValueNames) =>
- this.values[sourceValueName];
- setValue = action((sourceValueName: SourceValueNames, newValue: any) => {
- this.values[sourceValueName] = newValue;
- // TODO: Run effect here
- });
-
- getStatus = (elementName: string) => this.statuses[elementName];
- setStatus = action((elementName: string, status: Status) => {
- this.statuses[elementName] = status;
- });
-}
-
-export default CalculationStore;
diff --git a/src/client/stores/CalculationStore/Effects/autorun.ts b/src/client/stores/CalculationStore/Effects/autorun.ts
new file mode 100644
index 0000000..2fba7d5
--- /dev/null
+++ b/src/client/stores/CalculationStore/Effects/autorun.ts
@@ -0,0 +1,11 @@
+import { IAutorunEffect } from 'core/types/effect';
+
+const autorunEffects: IAutorunEffect[] = [
+ // calculationStore => () => {
+ // if (parseInt(calculationStore.values.price) > 25) {
+ // calculationStore.setValue('one', 100500);
+ // }
+ // }
+];
+
+export default autorunEffects;
diff --git a/src/client/stores/CalculationStore/Effects/computed.js b/src/client/stores/CalculationStore/Effects/computed.js
new file mode 100644
index 0000000..4810d71
--- /dev/null
+++ b/src/client/stores/CalculationStore/Effects/computed.js
@@ -0,0 +1,9 @@
+const computedEffects = {
+ total() {
+ const one = parseInt(this.values.one || 0);
+ const price = parseInt(this.values.price || 0);
+ return one + price;
+ }
+};
+
+export default computedEffects;
diff --git a/src/client/stores/CalculationStore/Effects/index.js b/src/client/stores/CalculationStore/Effects/index.js
new file mode 100644
index 0000000..949c0ab
--- /dev/null
+++ b/src/client/stores/CalculationStore/Effects/index.js
@@ -0,0 +1,20 @@
+import CommonStore from '../../CommonStore';
+import { autorun, reaction, when } from 'mobx';
+import CalculationStore from '..';
+import autorunEffects from './autorun';
+import reactionEffects from './reaction';
+import whenEffects from './when';
+
+autorunEffects.map(autorunEffect =>
+ autorun(autorunEffect(CalculationStore, CommonStore))
+);
+
+reactionEffects.map(reactionEffectBuilder => {
+ const reactionEffect = reactionEffectBuilder(CalculationStore);
+ return reaction(reactionEffect.expression, reactionEffect.effect);
+});
+
+whenEffects.map(whenEffectBuilder => {
+ const whenEffect = whenEffectBuilder(CalculationStore);
+ return when(whenEffect.predicate, whenEffect.effect);
+});
diff --git a/src/client/stores/CalculationStore/Effects/reaction.ts b/src/client/stores/CalculationStore/Effects/reaction.ts
new file mode 100644
index 0000000..cca65f4
--- /dev/null
+++ b/src/client/stores/CalculationStore/Effects/reaction.ts
@@ -0,0 +1,10 @@
+import { IReactionEffect } from 'core/types/effect';
+
+const reactionEffects: IReactionEffect[] = [
+ calculationStore => ({
+ expression: () => calculationStore.values.one,
+ effect: value => console.log(value)
+ })
+];
+
+export default reactionEffects;
diff --git a/src/client/stores/CalculationStore/Effects/when.ts b/src/client/stores/CalculationStore/Effects/when.ts
new file mode 100644
index 0000000..ff4f613
--- /dev/null
+++ b/src/client/stores/CalculationStore/Effects/when.ts
@@ -0,0 +1,10 @@
+import { IWhenEffect } from 'core/types/effect';
+
+const whenEffects: IWhenEffect[] = [
+ calculationStore => ({
+ predicate: () => parseInt(calculationStore.values.one) === 5,
+ effect: () => console.log(calculationStore.values.one)
+ })
+];
+
+export default whenEffects;
diff --git a/src/client/stores/CalculationStore/index.ts b/src/client/stores/CalculationStore/index.ts
index 977e648..30c8a9a 100644
--- a/src/client/stores/CalculationStore/index.ts
+++ b/src/client/stores/CalculationStore/index.ts
@@ -1,3 +1,35 @@
-import CalculationStore from "./CalculationStore";
+import assignProperties from 'client/tools/assignProps';
+import initialStatuses from 'core/config/initialStatuses';
+import initialValues from 'core/config/initialValues';
+import { Status } from 'core/types/elements';
+import { SourceValueNames } from 'core/types/values';
+import { observable } from 'mobx';
+import computedEffects from './Effects/computed';
+
+const CalculationStore = observable(
+ assignProperties(
+ {
+ values: initialValues,
+ statuses: initialStatuses,
+
+ getValue(sourceValueName: SourceValueNames) {
+ return this.values[sourceValueName];
+ },
+ getStatus(elementName: string) {
+ return this.statuses[elementName];
+ },
+
+ setValue(sourceValueName: SourceValueNames, newValue: any) {
+ this.values[sourceValueName] = newValue;
+ },
+ setStatus(elementName: string, status: Status) {
+ this.statuses[elementName] = status;
+ }
+ },
+ computedEffects
+ )
+);
+
+console.log(CalculationStore);
export default CalculationStore;
diff --git a/src/client/stores/CommonStore.ts b/src/client/stores/CommonStore.ts
index db2fdeb..a42b08f 100644
--- a/src/client/stores/CommonStore.ts
+++ b/src/client/stores/CommonStore.ts
@@ -1,3 +1,5 @@
-class CommonStore {}
+import { observable } from 'mobx';
+
+const CommonStore = observable({});
export default CommonStore;
diff --git a/src/client/stores/index.js b/src/client/stores/index.js
new file mode 100644
index 0000000..db8157c
--- /dev/null
+++ b/src/client/stores/index.js
@@ -0,0 +1,12 @@
+import CalculationStore from './CalculationStore';
+import CommonStore from './CommonStore';
+import './CalculationStore/Effects';
+
+class RootStore {
+ constructor() {
+ this.calculationStore = CalculationStore;
+ this.commonStore = CommonStore;
+ }
+}
+
+export default RootStore;
diff --git a/src/client/stores/index.ts b/src/client/stores/index.ts
deleted file mode 100644
index e6d4fb6..0000000
--- a/src/client/stores/index.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import CalculationStore from "./CalculationStore";
-import CommonStore from "client/stores/CommonStore";
-
-class RootStore {
- calculationStore: CalculationStore;
- commonStore: CommonStore;
-
- constructor() {
- this.calculationStore = new CalculationStore();
- this.commonStore = new CommonStore();
- }
-}
-
-export default RootStore;
diff --git a/src/client/tools/assignProps.js b/src/client/tools/assignProps.js
new file mode 100644
index 0000000..d0def4c
--- /dev/null
+++ b/src/client/tools/assignProps.js
@@ -0,0 +1,14 @@
+function assignProperties(target, ...sources) {
+ sources.forEach(source => {
+ Object.defineProperties(
+ target,
+ Object.keys(source).reduce((descriptors, key) => {
+ descriptors[key] = Object.getOwnPropertyDescriptor(source, key);
+ return descriptors;
+ }, {})
+ );
+ });
+ return target;
+}
+
+export default assignProperties;
diff --git a/src/client/tools/runEffects.js b/src/client/tools/runEffects.js
deleted file mode 100644
index 1f685e2..0000000
--- a/src/client/tools/runEffects.js
+++ /dev/null
@@ -1,13 +0,0 @@
-async function runEffects(effects, calculationStore) {
- if (effects && effects.length > 0) {
- for (let effect of effects) {
- try {
- await effect(calculationStore);
- } catch (error) {
- throw error;
- }
- }
- }
-}
-
-export default runEffects;
diff --git a/src/core/types/effect.ts b/src/core/types/effect.ts
index 705bd9f..d2585e9 100644
--- a/src/core/types/effect.ts
+++ b/src/core/types/effect.ts
@@ -1,3 +1,24 @@
-import CalculationStore from "client/stores/CalculationStore";
+import CalculationStore from 'client/stores/CalculationStore';
+import CommonStore from 'client/stores/CommonStore';
+import { IReactionPublic, Lambda } from 'mobx';
-export type TEffect = (calculationStore: CalculationStore) => Promise;
+type TCalculationStore = typeof CalculationStore;
+type TCommonStore = typeof CommonStore;
+
+export interface IAutorunEffect {
+ (CalculationStore: TCalculationStore, CommonStore?: TCommonStore): () => void;
+}
+
+export interface IReactionEffect {
+ (CalculationStore: TCalculationStore): {
+ expression: (r: IReactionPublic) => any;
+ effect: (arg: any, r: IReactionPublic) => void;
+ };
+}
+
+export interface IWhenEffect {
+ (CalculationStore: TCalculationStore): {
+ predicate: () => boolean;
+ effect: Lambda;
+ };
+}
diff --git a/src/core/types/elements.ts b/src/core/types/elements.ts
index c894735..aaa55c0 100644
--- a/src/core/types/elements.ts
+++ b/src/core/types/elements.ts
@@ -1,7 +1,4 @@
-import CalculationStore from "client/stores/CalculationStore";
-import { SourceValueNames } from "core/types/values";
-
export enum Status {
Default,
- Disabled,
+ Disabled
}