partial success!
This commit is contained in:
parent
4745d0cfd6
commit
0a7a543934
26
src/client/Containers/Calculation/Sections/index.ts
Normal file
26
src/client/Containers/Calculation/Sections/index.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import { TitledInput } from "client/Elements/Input";
|
||||
import { testEffectForPrice, testEffectForOne } from "client/Effects";
|
||||
|
||||
export default [
|
||||
{
|
||||
title: "FirstSection",
|
||||
elements: [
|
||||
{
|
||||
name: "tbxPrice",
|
||||
title: "Цена",
|
||||
Component: TitledInput,
|
||||
// getValue: undefined,
|
||||
sourceValueName: "price",
|
||||
Effects: [testEffectForPrice],
|
||||
},
|
||||
{
|
||||
name: "tbxOne",
|
||||
title: "One",
|
||||
Component: TitledInput,
|
||||
// getValue: undefined,
|
||||
sourceValueName: "one",
|
||||
Effects: [testEffectForOne],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
@ -1,73 +1,22 @@
|
||||
import Background from "client/Elements/Background";
|
||||
import { useStores } from "client/hooks/useStores";
|
||||
import Elements from "core/config/elements";
|
||||
import { useObserver } from "mobx-react";
|
||||
import React from "react";
|
||||
|
||||
function buildElement(
|
||||
elementName,
|
||||
Element,
|
||||
title,
|
||||
sourceValueName,
|
||||
getValue,
|
||||
action,
|
||||
actionAsync,
|
||||
|
||||
valuesStore
|
||||
) {
|
||||
if (sourceValueName) {
|
||||
return (
|
||||
<Element
|
||||
title={title}
|
||||
value={valuesStore.getValue(sourceValueName)}
|
||||
onChange={(e) => {
|
||||
valuesStore.setValue(sourceValueName, e.target.value);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
if (getValue) {
|
||||
return (
|
||||
<Element
|
||||
title={title}
|
||||
value={getValue(valuesStore)}
|
||||
onChange={(e) => {
|
||||
valuesStore.setValue(sourceValueName, e.target.value);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
import Sections from "./Sections";
|
||||
import buildElement from "client/hocs/buildElement";
|
||||
|
||||
const Calculation = () => {
|
||||
const {
|
||||
calculationStore: { valuesStore, statusStore },
|
||||
} = useStores();
|
||||
return useObserver(() => (
|
||||
return (
|
||||
<Background>
|
||||
{Object.keys(Elements).map((elementName) => {
|
||||
const { Element, title, sourceValueName, getValue } = Elements[
|
||||
elementName
|
||||
];
|
||||
return buildElement(
|
||||
elementName,
|
||||
Element,
|
||||
title,
|
||||
sourceValueName,
|
||||
getValue,
|
||||
undefined,
|
||||
undefined,
|
||||
valuesStore
|
||||
);
|
||||
})}
|
||||
{Sections.map(({ title, elements }, i) => (
|
||||
<div key={i}>
|
||||
<p>{title}</p>
|
||||
{elements.map((element, ie) => {
|
||||
const Element = buildElement(element);
|
||||
return <Element />;
|
||||
})}
|
||||
</div>
|
||||
))}
|
||||
</Background>
|
||||
));
|
||||
};
|
||||
|
||||
const styles = {
|
||||
root: {},
|
||||
contentWrapper: { flex: 2 },
|
||||
resultsWrapper: { flex: 1 },
|
||||
);
|
||||
};
|
||||
|
||||
// export default observer(Calculation);
|
||||
|
||||
20
src/client/Effects/index.ts
Normal file
20
src/client/Effects/index.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import CalculationStore from "client/stores/CalculationStore";
|
||||
import { TEffect } from "core/types/effect";
|
||||
|
||||
export const testEffectForPrice: TEffect = async (
|
||||
calculationStore: CalculationStore
|
||||
) => {
|
||||
const price = calculationStore.getValue("price");
|
||||
if (price > 5000) {
|
||||
calculationStore.setValue("one", 500);
|
||||
}
|
||||
};
|
||||
|
||||
export const testEffectForOne: TEffect = async (
|
||||
calculationStore: CalculationStore
|
||||
) => {
|
||||
const one = calculationStore.getValue("one");
|
||||
if (one > 1000) {
|
||||
calculationStore.setValue("price", 100500);
|
||||
}
|
||||
};
|
||||
@ -1,6 +1,7 @@
|
||||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
import { Flex } from "client/UIKit/grid";
|
||||
import { IElementProps } from "core/types/elements";
|
||||
|
||||
export const TextInput = styled.input`
|
||||
width: 200px;
|
||||
@ -11,11 +12,16 @@ const Title = styled.div`
|
||||
`;
|
||||
|
||||
export const TitledInput = (props) => {
|
||||
const { title } = props;
|
||||
const { title, value, onChange } = props;
|
||||
return (
|
||||
<Flex flexDirection="column" mx="10px" my="5px">
|
||||
{title && <Title>{title}</Title>}
|
||||
<TextInput {...props} />
|
||||
<TextInput
|
||||
onChange={(e) => {
|
||||
onChange(e);
|
||||
}}
|
||||
value={value}
|
||||
/>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
18
src/client/Elements/Select.jsx
Normal file
18
src/client/Elements/Select.jsx
Normal file
@ -0,0 +1,18 @@
|
||||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
|
||||
const Select = (props) => {
|
||||
const { options } = props;
|
||||
if (!options || options.length === 0) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<select {...props}>
|
||||
{options.map(({ value, text }) => (
|
||||
<option value={value}>{text}</option>
|
||||
))}
|
||||
</select>
|
||||
);
|
||||
};
|
||||
|
||||
export { Select };
|
||||
@ -3,8 +3,8 @@ import RootStore from "client/stores";
|
||||
|
||||
export const StoreContext = createContext();
|
||||
|
||||
const rootStore = new RootStore();
|
||||
|
||||
export const StoreProvider = ({ children }) => (
|
||||
<StoreContext.Provider value={new RootStore()}>
|
||||
{children}
|
||||
</StoreContext.Provider>
|
||||
<StoreContext.Provider value={rootStore}>{children}</StoreContext.Provider>
|
||||
);
|
||||
|
||||
47
src/client/hocs/buildElement.tsx
Normal file
47
src/client/hocs/buildElement.tsx
Normal file
@ -0,0 +1,47 @@
|
||||
import { withStore } from "client/hocs/withStore";
|
||||
import CalculationStore from "client/stores/CalculationStore";
|
||||
import CommonStore from "client/stores/CommonStore";
|
||||
import { SourceValueNames } from "core/types/values";
|
||||
import { useObserver } from "mobx-react";
|
||||
import React, { ComponentType } from "react";
|
||||
import { useStores } from "client/hooks/useStores";
|
||||
|
||||
type TElementBuilder = <P extends unknown>(data: {
|
||||
name: string;
|
||||
title: string;
|
||||
Component: ComponentType<P>;
|
||||
sourceValueName: SourceValueNames;
|
||||
getValue: () => any;
|
||||
Effects: Promise<void>[];
|
||||
calculationStore: CalculationStore;
|
||||
commonStore: CommonStore;
|
||||
}) => (props: P) => JSX.Element;
|
||||
|
||||
const buildElement: TElementBuilder = ({
|
||||
name,
|
||||
title,
|
||||
Component,
|
||||
sourceValueName,
|
||||
getValue,
|
||||
Effects,
|
||||
calculationStore,
|
||||
commonStore,
|
||||
}) => (props) => {
|
||||
const { calculationStore } = useStores();
|
||||
|
||||
return useObserver(() => (
|
||||
<Component
|
||||
{...props}
|
||||
title={title}
|
||||
value={calculationStore.getValue(sourceValueName)}
|
||||
onChange={(e: any) => {
|
||||
calculationStore.setValue(sourceValueName, e.target.value);
|
||||
var effect = Effects[0];
|
||||
//@ts-ignore
|
||||
effect(calculationStore);
|
||||
}}
|
||||
/>
|
||||
));
|
||||
};
|
||||
|
||||
export default buildElement;
|
||||
@ -1,6 +1,7 @@
|
||||
import React, { ComponentType } from "react";
|
||||
// import hoistNonReactStatics from "hoist-non-react-statics";
|
||||
import { useStores } from "../hooks/useStores";
|
||||
import { useObserver } from "mobx-react";
|
||||
|
||||
export type TWithStoreHOC = <P extends unknown>(
|
||||
Component: ComponentType<P>
|
||||
@ -8,9 +9,9 @@ export type TWithStoreHOC = <P extends unknown>(
|
||||
|
||||
export const withStore: TWithStoreHOC = (WrappedComponent) => (props) => {
|
||||
const ComponentWithStore = () => {
|
||||
const store = useStores();
|
||||
const stores = useStores();
|
||||
|
||||
return <WrappedComponent {...props} store={store} />;
|
||||
return <WrappedComponent {...props} stores={stores} />;
|
||||
};
|
||||
|
||||
ComponentWithStore.defaultProps = { ...WrappedComponent.defaultProps };
|
||||
|
||||
24
src/client/stores/CalculationStore/CalculationStore.ts
Normal file
24
src/client/stores/CalculationStore/CalculationStore.ts
Normal file
@ -0,0 +1,24 @@
|
||||
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;
|
||||
@ -1,13 +0,0 @@
|
||||
import { action, observable } from "mobx";
|
||||
import { Status } from "core/types/elements";
|
||||
import initialStatuses from "core/config/initialStatuses";
|
||||
|
||||
class StatusStore {
|
||||
statuses = observable(initialStatuses);
|
||||
|
||||
setStatus = action((elementName: string, status: Status) => {
|
||||
this.statuses[elementName] = status;
|
||||
});
|
||||
}
|
||||
|
||||
export default StatusStore;
|
||||
@ -1,17 +0,0 @@
|
||||
import initialValues from "core/config/initialValues";
|
||||
import { SourceValuesNames } from "core/types/values";
|
||||
import { action, observable } from "mobx";
|
||||
|
||||
class ValuesStore {
|
||||
values = observable(initialValues);
|
||||
|
||||
setValue = action((sourceValueName: SourceValuesNames, newValue: any) => {
|
||||
//@ts-ignore
|
||||
this.values[sourceValueName] = newValue;
|
||||
});
|
||||
|
||||
getValue = (sourceValueName: SourceValuesNames) =>
|
||||
this.values[sourceValueName];
|
||||
}
|
||||
|
||||
export default ValuesStore;
|
||||
@ -1,16 +1,3 @@
|
||||
import Elements from "core/config/elements";
|
||||
import { action, observable } from "mobx";
|
||||
import StatusStore from "./StatusStore";
|
||||
import ValuesStore from "./ValuesStore";
|
||||
|
||||
class CalculationStore {
|
||||
statusStore: StatusStore;
|
||||
valuesStore: ValuesStore;
|
||||
|
||||
constructor() {
|
||||
this.statusStore = new StatusStore();
|
||||
this.valuesStore = new ValuesStore();
|
||||
}
|
||||
}
|
||||
import CalculationStore from "./CalculationStore";
|
||||
|
||||
export default CalculationStore;
|
||||
|
||||
@ -1 +1,3 @@
|
||||
export default {};
|
||||
class CommonStore {}
|
||||
|
||||
export default CommonStore;
|
||||
|
||||
@ -1,10 +1,13 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,35 +0,0 @@
|
||||
import { IElement } from "core/types/elements";
|
||||
import React from "react";
|
||||
import { TitledInput } from "client/Elements/Input";
|
||||
|
||||
const elements: {
|
||||
[element: string]: IElement;
|
||||
} = {
|
||||
tbx1: {
|
||||
// title: "Такса",
|
||||
Element: (props: any) => <TitledInput {...props} />,
|
||||
sourceValueName: "tax",
|
||||
},
|
||||
tbx2: {
|
||||
Element: (props: any) => <TitledInput {...props} />,
|
||||
sourceValueName: "price",
|
||||
},
|
||||
tbx3: {
|
||||
Element: (props: any) => <TitledInput {...props} />,
|
||||
getValue: (valuesStore) => {
|
||||
const { tax, price } = valuesStore.values;
|
||||
if (tax && price) {
|
||||
{
|
||||
if (typeof tax === "string" && typeof price === "string") {
|
||||
return parseInt(tax) + parseInt(price);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
// getStatus:(elementName,statusesStore)=>{
|
||||
|
||||
// }
|
||||
},
|
||||
};
|
||||
|
||||
export default elements;
|
||||
@ -2,8 +2,6 @@ import { ValuesMap } from "core/types/values";
|
||||
|
||||
const initialValues: ValuesMap = {
|
||||
price: 10000,
|
||||
tax: 151515,
|
||||
test: 999999,
|
||||
};
|
||||
|
||||
export default initialValues;
|
||||
|
||||
3
src/core/types/effect.ts
Normal file
3
src/core/types/effect.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import CalculationStore from "client/stores/CalculationStore";
|
||||
|
||||
export type TEffect = (calculationStore: CalculationStore) => Promise<void>;
|
||||
@ -1,52 +1,7 @@
|
||||
import { ReactNode } from "react";
|
||||
import ValuesStore from "client/stores/CalculationStore/ValuesStore";
|
||||
import StatusStore from "client/stores/CalculationStore/StatusStore";
|
||||
import { Value, SourceValuesNames } from "./values";
|
||||
|
||||
type Action = { (): void };
|
||||
type Trigger = { (): Action[] };
|
||||
import CalculationStore from "client/stores/CalculationStore";
|
||||
import { SourceValueNames } from "core/types/values";
|
||||
|
||||
export enum Status {
|
||||
Default,
|
||||
Disabled,
|
||||
Hidden,
|
||||
Fetching,
|
||||
}
|
||||
export interface IBaseElement {
|
||||
title?: string;
|
||||
Element: React.Component | ReactNode | JSX.IntrinsicElements | JSX.Element;
|
||||
|
||||
getInitialValue?: () => Value;
|
||||
getInitialStatus?: () => Status | undefined;
|
||||
|
||||
getStatus?: (
|
||||
elementName: string,
|
||||
statusStore: StatusStore
|
||||
) => Status | undefined;
|
||||
}
|
||||
|
||||
export interface IBindedElement extends IBaseElement {
|
||||
sourceValueName?: SourceValuesNames;
|
||||
}
|
||||
|
||||
export interface IComputedElement extends IBaseElement {
|
||||
getValue?: (valuesStore: ValuesStore) => Value;
|
||||
getValueAsync?: (
|
||||
elementName: string,
|
||||
valuesStore: ValuesStore
|
||||
) => Promise<Value>;
|
||||
}
|
||||
|
||||
export interface ITriggerElement extends IComputedElement, IBindedElement {
|
||||
action?: (
|
||||
e: React.ChangeEvent,
|
||||
valuesStore: ValuesStore,
|
||||
statusStore: StatusStore
|
||||
) => void;
|
||||
actionAsync?: (
|
||||
e: React.ChangeEvent,
|
||||
valuesStore: ValuesStore,
|
||||
statusStore: StatusStore
|
||||
) => Promise<void>;
|
||||
}
|
||||
|
||||
export type IElement = IBindedElement & IComputedElement & ITriggerElement;
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
export type SourceValuesNames = "price" | "tax" | "test";
|
||||
export type SourceValueNames = "one" | "two" | "three" | "price";
|
||||
|
||||
export type Value = string | number | boolean | undefined;
|
||||
export type ValuesMap = {
|
||||
[sourceValueName in SourceValuesNames]?: Value;
|
||||
[valueName in SourceValueNames]?: any;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user