refactor elements connection to store

This commit is contained in:
Chika 2020-09-14 14:39:02 +03:00
parent 9a299ba8cc
commit 0dc196fab3
14 changed files with 126 additions and 235 deletions

View File

@ -9,7 +9,7 @@
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.3.2",
"@testing-library/user-event": "^7.1.2",
"antd": "^4.6.2",
"antd": "^4.6.4",
"axios": "^0.20.0",
"body-parser": "^1.19.0",
"class-validator": "^0.12.2",
@ -22,7 +22,7 @@
"http-errors": "^1.8.0",
"lodash": "^4.17.20",
"mobx": "^5.15.6",
"mobx-react": "^6.2.5",
"mobx-react": "^6.3.0",
"morgan": "^1.10.0",
"mssql": "^6.2.1",
"nodemon": "^2.0.4",

View File

@ -1,12 +1,13 @@
import { Divider as AntDivider, Tabs } from 'antd';
import Background from 'client/Elements/Background';
import { SecondaryText, SecondaryColoredText } from 'client/Elements/Text';
import { Flex, Box } from 'client/UIKit/grid';
import { SecondaryColoredText } from 'client/Elements/Text';
import { withStoreValue } from 'client/hocs/withStore';
import colors from 'client/UIKit/colors';
import { Flex } from 'client/UIKit/grid';
import mq from 'client/UIKit/mq';
import React from 'react';
import styled from 'styled-components';
import sectionsList from './list';
import colors from 'client/UIKit/colors';
import mq from 'client/UIKit/mq';
const ElementTitle = styled.h5`
color: rgba(0, 0, 0, 0.75);
@ -20,27 +21,18 @@ const BreakLine = styled.div`
width: 100%;
`;
const VerticalDivider = styled.div`
${mq.desktop`
width: 1px;
margin: 6px 2px;
background: rgb(0,0,0);
background: linear-gradient(0deg, rgba(0,0,0,0) 0%, rgba(0,0,0,0.08) 20%, rgba(0,0,0,0.08) 80%, rgba(0,0,0,0) 100%);
// background: rgba(0,0,0,0.12);
`}
`;
const BlockWrapper = styled.div`
border: 1px solid black;
`;
const renderElements = ({ elements }) => {
return elements.map((element, ie) => {
const { title: elementTitle, Component, props: elementProps } = element;
const {
title: elementTitle,
Component: Element,
props: elementProps,
} = element;
const Component = withStoreValue(Element)(elementProps);
return (
<Flex flexDirection="column" key={ie}>
<ElementTitle>{elementTitle}</ElementTitle>
<Component {...elementProps} />
<Component />
</Flex>
);
});
@ -91,7 +83,7 @@ const renderGroups = ({ groups }) => {
return (
<React.Fragment key={ig}>
{blocksTitle && (
<AntDivider style={{ margin: '8px 0', color: colors.blueTemp[200] }}>
<AntDivider style={{ margin: '16px 0', color: colors.blueTemp[200] }}>
{blocksTitle}
</AntDivider>
)}
@ -103,7 +95,7 @@ const renderGroups = ({ groups }) => {
});
};
const Sections = (props) => (
const Sections = props => (
<Background {...props}>
<Tabs type="line">
{sectionsList.map((section, is) => {

View File

@ -1,15 +1,11 @@
import { Button as AntButton } from 'antd';
import { useStatus } from 'client/hooks/useStatus';
import { Status } from 'core/types/statuses';
import React from 'react';
const Button = ({ type, size, name, text, onClick }) => {
const { status } = useStatus(name);
const Button = ({ status, onClick, text, ...props }) => {
return (
<AntButton
type={type}
size={size}
{...props}
disabled={status === Status.Disabled}
onClick={onClick}
>

View File

@ -1,24 +1,13 @@
import { Checkbox as AntCheckbox, Form } from 'antd';
import { useStatus } from 'client/hooks/useStatus';
import { useStoreValue } from 'client/hooks/useStoreValue';
import { DEFAULT_DEBOUNCE_DELAY } from 'core/constants/debounce';
import { Status } from 'core/types/statuses';
import { observer } from 'mobx-react';
import React from 'react';
const Checkbox = ({ name, readonly, valueName, computedValue }) => {
const { value, setCurrentValue } = useStoreValue({
computedValue,
valueName,
debounceDelay: DEFAULT_DEBOUNCE_DELAY,
});
const { status } = useStatus(name);
const Checkbox = ({ value, setCurrentValue, status, ...props }) => {
return (
<Form.Item>
<AntCheckbox
{...props}
disabled={status === Status.Disabled}
readonly={readonly}
checked={value}
onChange={e => setCurrentValue(e.target.checked)}
/>
@ -26,4 +15,4 @@ const Checkbox = ({ name, readonly, valueName, computedValue }) => {
);
};
export default observer(Checkbox);
export default Checkbox;

View File

@ -1,60 +1,20 @@
import { Form, Input as AntInput } from 'antd';
import { useStatus } from 'client/hooks/useStatus';
import { useStoreValue } from 'client/hooks/useStoreValue';
import { TEXT_INPUT_DEBOUNCE_DELAY } from 'core/constants/debounce';
import { Status } from 'core/types/statuses';
import { observer } from 'mobx-react';
import React from 'react';
import { useValidation } from 'client/hooks/useValidation';
const Input = ({
name,
readonly,
type,
validation,
rules,
pattern,
prefix,
suffix,
placeholder,
addonBefore,
addonAfter,
valueName,
computedValue,
value,
setCurrentValue,
status,
validateStatus,
message,
...props
}) => {
const { value, setCurrentValue, debouncedValue } = useStoreValue({
computedValue,
valueName,
debounceDelay: TEXT_INPUT_DEBOUNCE_DELAY,
});
const { status } = useStatus(name);
const { isValid, validateStatus, message } = useValidation({
elementName: name,
value: debouncedValue,
validation: validation || {
errorMessage: '',
validator: () => {},
},
});
return (
<Form.Item
hasFeedback
validateStatus={validateStatus}
help={message}
rules={rules}
>
<Form.Item hasFeedback validateStatus={validateStatus} help={message}>
<AntInput
prefix={prefix}
suffix={suffix}
{...props}
disabled={status === Status.Disabled}
readOnly={readonly}
type={type}
placeholder={placeholder}
pattern={pattern}
addonBefore={addonBefore}
addonAfter={addonAfter}
value={value}
onChange={e => setCurrentValue(e.target.value)}
/>
@ -62,4 +22,4 @@ const Input = ({
);
};
export default observer(Input);
export default Input;

View File

@ -1,44 +1,14 @@
import { InputNumber as AntInputNumber, Form } from 'antd';
import { useStatus } from 'client/hooks/useStatus';
import { useStoreValue } from 'client/hooks/useStoreValue';
import { Form, InputNumber as AntInputNumber } from 'antd';
import { Status } from 'core/types/statuses';
import { observer } from 'mobx-react';
import React from 'react';
import { TEXT_INPUT_DEBOUNCE_DELAY } from 'core/constants/debounce';
const InputNumber = ({
name,
readonly,
min,
max,
step,
formatter,
parser,
placeholder,
valueName,
computedValue,
}) => {
const { value, setCurrentValue } = useStoreValue({
computedValue,
valueName,
debounceDelay: TEXT_INPUT_DEBOUNCE_DELAY,
});
const { status } = useStatus(name);
const InputNumber = ({ value, setCurrentValue, status, ...props }) => {
return (
<Form.Item>
<AntInputNumber
{...props}
disabled={status === Status.Disabled}
readOnly={readonly}
placeholder={placeholder}
style={{
width: '100%',
}}
min={min}
max={max}
step={step}
formatter={formatter}
parser={parser}
style={styles}
onChange={value => setCurrentValue(value)}
value={value}
/>
@ -46,4 +16,8 @@ const InputNumber = ({
);
};
export default observer(InputNumber);
const styles = {
width: '100%',
};
export default InputNumber;

View File

@ -1,16 +1,12 @@
import React from 'react';
import styled from 'styled-components';
import { useStoreValue } from 'client/hooks/useStoreValue';
import { observer } from 'mobx-react';
const TextWrapper = styled.div``;
const Text = styled.span`
font-size: 0.85rem;
`;
const Label = ({ name, computedValue, valueName }) => {
const { value } = useStoreValue({ computedValue, valueName });
const Label = ({ value }) => {
//TODO: Hide if no value
return (
@ -20,4 +16,4 @@ const Label = ({ name, computedValue, valueName }) => {
);
};
export default observer(Label);
export default Label;

View File

@ -1,24 +1,19 @@
import { Radio as AntRadio, Form } from 'antd';
import { useOptions } from 'client/hooks/useOptions';
import { useStatus } from 'client/hooks/useStatus';
import { useStoreValue } from 'client/hooks/useStoreValue';
import { DEFAULT_DEBOUNCE_DELAY } from 'core/constants/debounce';
import { Form, Radio as AntRadio } from 'antd';
import { Status } from 'core/types/statuses';
import { observer } from 'mobx-react';
import React from 'react';
const Radio = ({ name, style, computedValue, valueName }) => {
const { value, setCurrentValue } = useStoreValue({
computedValue,
valueName,
debounceDelay: DEFAULT_DEBOUNCE_DELAY,
});
const { status } = useStatus(name);
const { options } = useOptions(name);
const Radio = ({
value,
setCurrentValue,
status,
options,
style,
...props
}) => {
return (
<Form.Item>
<AntRadio.Group
{...props}
disabled={status === Status.Disabled}
buttonStyle={style === 'button' && 'solid'}
value={value}
@ -51,4 +46,4 @@ const styles = {
},
};
export default observer(Radio);
export default Radio;

View File

@ -1,26 +1,20 @@
import { Select as AntSelect, Form } from 'antd';
import { useStatus } from 'client/hooks/useStatus';
import { useStoreValue } from 'client/hooks/useStoreValue';
import { Form, Select as AntSelect } from 'antd';
import { Status } from 'core/types/statuses';
import { observer } from 'mobx-react';
import React from 'react';
import { useOptions } from 'client/hooks/useOptions';
import { DEFAULT_DEBOUNCE_DELAY } from 'core/constants/debounce';
const Select = ({ name, showSearch, computedValue, valueName }) => {
const { value, setCurrentValue } = useStoreValue({
computedValue,
valueName,
debounceDelay: DEFAULT_DEBOUNCE_DELAY,
});
const { status } = useStatus(name);
const { options, filter } = useOptions(name);
const Select = ({
value,
setCurrentValue,
status,
options,
filter,
...props
}) => {
return (
<Form.Item>
<AntSelect
{...props}
disabled={status === Status.Disabled}
showSearch={showSearch}
optionFilterProp="children"
filterOption={filter}
value={value}
@ -40,4 +34,4 @@ const Select = ({ name, showSearch, computedValue, valueName }) => {
);
};
export default observer(Select);
export default Select;

View File

@ -1,22 +1,12 @@
import { Form, Switch as AntSwitch } from 'antd';
import { useStatus } from 'client/hooks/useStatus';
import { useStoreValue } from 'client/hooks/useStoreValue';
import { DEFAULT_DEBOUNCE_DELAY } from 'core/constants/debounce';
import { Status } from 'core/types/statuses';
import { observer } from 'mobx-react';
import React from 'react';
const Switch = ({ name, valueName, computedValue }) => {
const { value, setCurrentValue } = useStoreValue({
computedValue,
valueName,
debounceDelay: DEFAULT_DEBOUNCE_DELAY,
});
const { status } = useStatus(name);
const Switch = ({ value, setCurrentValue, status, ...props }) => {
return (
<Form.Item>
<AntSwitch
{...props}
disabled={status === Status.Disabled}
checked={value}
onChange={(checked, event) => {
@ -27,4 +17,4 @@ const Switch = ({ name, valueName, computedValue }) => {
);
};
export default observer(Switch);
export default Switch;

View File

@ -1,35 +1,19 @@
import { Input as AntInput } from 'antd';
import { useStatus } from 'client/hooks/useStatus';
import { useStoreValue } from 'client/hooks/useStoreValue';
import { Form, Input as AntInput } from 'antd';
import { Status } from 'core/types/statuses';
import { observer } from 'mobx-react';
import React from 'react';
import { TEXT_INPUT_DEBOUNCE_DELAY } from 'core/constants/debounce';
const TextArea = ({
name,
readonly,
placeholder,
valueName,
computedValue,
}) => {
const { value, setCurrentValue } = useStoreValue({
computedValue,
valueName,
debounceDelay: TEXT_INPUT_DEBOUNCE_DELAY,
});
const { status } = useStatus(name);
const TextArea = ({ value, setCurrentValue, status, ...props }) => {
return (
<AntInput.TextArea
autoSize={{ minRows: 5, maxRows: 8 }}
disabled={status === Status.Disabled}
readOnly={readonly}
placeholder={placeholder}
value={value}
onChange={e => setCurrentValue(e.target.value)}
/>
<Form.Item>
<AntInput.TextArea
{...props}
autoSize={{ minRows: 5, maxRows: 8 }}
disabled={status === Status.Disabled}
value={value}
onChange={e => setCurrentValue(e.target.value)}
/>
</Form.Item>
);
};
export default observer(TextArea);
export default TextArea;

View File

@ -0,0 +1,47 @@
import { useOptions } from 'client/hooks/useOptions';
import { useStatus } from 'client/hooks/useStatus';
import { useStoreValue } from 'client/hooks/useStoreValue';
import { useValidation } from 'client/hooks/useValidation';
import { DEFAULT_DEBOUNCE_DELAY } from 'core/constants/debounce';
import { observer } from 'mobx-react';
import React from 'react';
export const withStoreValue = Component => ({
name,
valueName,
computedValue,
validation,
...params
}) => {
const ComponentWithStore = () => {
const { value, setCurrentValue, debouncedValue } = useStoreValue({
computedValue,
valueName,
debounceDelay: DEFAULT_DEBOUNCE_DELAY,
});
const { status } = useStatus(name);
const { isValid, validateStatus, message } = useValidation({
elementName: name,
value: debouncedValue,
validation: validation || {
errorMessage: '',
validator: () => {},
},
});
const { options, filter } = useOptions(name);
return (
<Component
value={value}
setCurrentValue={setCurrentValue}
status={status}
validateStatus={validateStatus}
message={message}
options={options}
filter={filter}
{...params}
/>
);
};
return observer(ComponentWithStore);
};

View File

@ -1,25 +0,0 @@
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>
) => (props: P) => JSX.Element;
export const withStore: TWithStoreHOC = (WrappedComponent) => (props) => {
const ComponentWithStore = () => {
const stores = useStores();
return <WrappedComponent {...props} stores={stores} />;
};
ComponentWithStore.defaultProps = { ...WrappedComponent.defaultProps };
ComponentWithStore.displayName = `WithStores(${
WrappedComponent.name || WrappedComponent.displayName
})`;
// hoistNonReactStatics(ComponentWithStore, WrappedComponent);
return <ComponentWithStore />;
};

View File

@ -1,2 +1 @@
export const TEXT_INPUT_DEBOUNCE_DELAY = 650;
export const DEFAULT_DEBOUNCE_DELAY = 0;
export const DEFAULT_DEBOUNCE_DELAY = 250;