add tabled elements Component

This commit is contained in:
Chika 2020-09-14 18:27:10 +03:00
parent 0dc196fab3
commit 8abc0bfc03
10 changed files with 212 additions and 51 deletions

View File

@ -1,10 +1,9 @@
import { Divider as AntDivider, Tabs } from 'antd';
import Background from 'client/Elements/Background';
import { SecondaryColoredText } from 'client/Elements/Text';
import { withStoreValue } from 'client/hocs/withStore';
import { withStoreValue, withTableData } 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';
@ -21,14 +20,16 @@ const BreakLine = styled.div`
width: 100%;
`;
function buildElement({ isTable, Component: Element, props: elementProps }) {
if (isTable) {
return withTableData(Element)(elementProps);
}
return withStoreValue(Element)(elementProps);
}
const renderElements = ({ elements }) => {
return elements.map((element, ie) => {
const {
title: elementTitle,
Component: Element,
props: elementProps,
} = element;
const Component = withStoreValue(Element)(elementProps);
return elements.map(({ title: elementTitle, ...element }, ie) => {
const Component = buildElement(element);
return (
<Flex flexDirection="column" key={ie}>
<ElementTitle>{elementTitle}</ElementTitle>

View File

@ -6,12 +6,13 @@ import Label from 'client/Elements/Label';
import Radio from 'client/Elements/Radio';
import Select from 'client/Elements/Select';
import Switch from 'client/Elements/Switch';
import Table from 'client/Elements/Table';
import TextArea from 'client/Elements/TextArea';
import {
validateEmail,
validateInn,
validateKpp,
validatePhone,
validateEmail,
} from 'client/tools/validate';
export default [
@ -1354,10 +1355,24 @@ export default [
blocks: [
{
elements: [
// TODO groups
{
title: 'Here will be content',
Component: Label,
isTable: true,
Component: Table,
props: {
name: 'fruitTable',
columns: [
{
name: 'fruit',
title: 'Fruit',
Component: Input,
},
{
name: 'number',
title: 'Number',
Component: InputNumber,
},
],
},
},
],
},

View File

@ -0,0 +1,41 @@
import { withTableValue } from 'client/hocs/withStore';
import React from 'react';
const Table = ({ name: tableName, columns, values }) => {
return (
<table>
<thead>
<tr>
{columns.map(({ name, title }, ci) => {
return <th key={ci}>{title}</th>;
})}
</tr>
</thead>
<tbody>
{values.map((row, ri) => {
const keys = Object.keys(row);
return (
<tr key={ri}>
{keys.map((key, ki) => {
const columnIndex = columns.findIndex(c => c.name === key);
const Component = columns[columnIndex].Component;
const Element = withTableValue(Component)({
tableName,
rowIndex: ri,
propName: key,
});
return (
<td key={ki}>
<Element />
</td>
);
})}
</tr>
);
})}
</tbody>
</table>
);
};
export default Table;

View File

@ -1,10 +1,10 @@
import { useOptions } from 'client/hooks/useOptions';
import { useStatus } from 'client/hooks/useStatus';
import { useStoreValue } from 'client/hooks/useStoreValue';
import { useStoreValue, useTableValue } from 'client/hooks/useValue';
import { useValidation } from 'client/hooks/useValidation';
import { DEFAULT_DEBOUNCE_DELAY } from 'core/constants/debounce';
import { observer } from 'mobx-react';
import React from 'react';
import { useStores } from 'client/hooks/useStores';
export const withStoreValue = Component => ({
name,
@ -17,7 +17,6 @@ export const withStoreValue = Component => ({
const { value, setCurrentValue, debouncedValue } = useStoreValue({
computedValue,
valueName,
debounceDelay: DEFAULT_DEBOUNCE_DELAY,
});
const { status } = useStatus(name);
const { isValid, validateStatus, message } = useValidation({
@ -45,3 +44,33 @@ export const withStoreValue = Component => ({
};
return observer(ComponentWithStore);
};
export const withTableData = Table => props => {
const { name: tableName } = props;
const TableWithStore = () => {
const { calculationStore } = useStores();
const tableData = calculationStore.tables[tableName];
return <Table {...props} {...tableData} />;
};
return TableWithStore;
};
export const withTableValue = Component => ({
tableName,
rowIndex,
propName,
...params
}) => {
const ComponentWithStore = () => {
const { value, setCurrentValue } = useTableValue({
tableName,
rowIndex,
propName,
});
return (
<Component {...params} value={value} setCurrentValue={setCurrentValue} />
);
};
return observer(ComponentWithStore);
};

View File

@ -1,33 +0,0 @@
import { useEffect, useState } from 'react';
import { useDebounce } from 'use-debounce/lib';
import { useStores } from './useStores';
export const useStoreValue = ({ computedValue, valueName, debounceDelay }) => {
const { calculationStore } = useStores();
const [currentValue, setCurrentValue] = useState(undefined);
const [debouncedValue] = useDebounce(currentValue, debounceDelay);
const sourceValue = calculationStore.values[valueName];
// get value from store
useEffect(() => {
if (!computedValue) {
if (sourceValue !== undefined) {
setCurrentValue(sourceValue);
}
}
}, [computedValue, sourceValue]);
// set value to store
useEffect(() => {
if (!computedValue) {
calculationStore.setValue(valueName, debouncedValue);
}
}, [calculationStore, computedValue, debouncedValue, valueName]);
const value = computedValue
? calculationStore[computedValue]()
: currentValue;
return { value, setCurrentValue, debouncedValue };
};

View File

@ -0,0 +1,62 @@
import { DEFAULT_DEBOUNCE_DELAY } from 'core/constants/debounce';
import { useEffect, useState } from 'react';
import { useDebounce } from 'use-debounce/lib';
import { useStores } from './useStores';
export const useStoreValue = ({ computedValue, valueName }) => {
const { calculationStore } = useStores();
const [currentValue, setCurrentValue] = useState(undefined);
const [debouncedValue] = useDebounce(currentValue, DEFAULT_DEBOUNCE_DELAY);
const sourceValue = calculationStore.values[valueName];
// get value from store
useEffect(() => {
if (!computedValue) {
if (sourceValue !== undefined) {
setCurrentValue(sourceValue);
}
}
}, [computedValue, sourceValue]);
// set value to store
useEffect(() => {
if (!computedValue) {
calculationStore.setValue(valueName, debouncedValue);
}
}, [calculationStore, computedValue, debouncedValue, valueName]);
const value = computedValue
? calculationStore[computedValue]()
: currentValue;
return { value, setCurrentValue, debouncedValue };
};
export const useTableValue = ({ tableName, rowIndex, propName }) => {
const { calculationStore } = useStores();
const [currentValue, setCurrentValue] = useState(undefined);
const [debouncedValue] = useDebounce(currentValue, DEFAULT_DEBOUNCE_DELAY);
const sourceValue =
calculationStore.tables[tableName].values[rowIndex][propName];
// get value from store
useEffect(() => {
if (sourceValue !== undefined) {
setCurrentValue(sourceValue);
}
}, [sourceValue]);
// set value to store
useEffect(() => {
calculationStore.setTableValue(
tableName,
rowIndex,
propName,
debouncedValue
);
}, [calculationStore, debouncedValue, propName, rowIndex, tableName]);
return { value: currentValue, setCurrentValue, debouncedValue };
};

View File

@ -12,6 +12,7 @@ import computedEffects from './Effects/computed';
import reactionEffects from './Effects/reaction';
import whenEffects from './Effects/when';
import { ICalculationStore } from 'core/types/stores';
import initialTables from 'core/config/initialTables';
const CalculationStore: ICalculationStore = observable(
assignProperties(
@ -43,8 +44,19 @@ const CalculationStore: ICalculationStore = observable(
options: initialOptions,
filters: {},
},
computedEffects,
),
{
tables: initialTables,
setTableValue(
tableName: string,
rowIndex: number,
propName: string,
value: any
) {
this.tables[tableName].values[rowIndex][propName] = value;
},
},
computedEffects
)
);
autorunEffects.map(autorunEffect =>

View File

@ -0,0 +1,17 @@
import { IStoreTable } from './../types/tables';
const initialTables: IStoreTable = {
fruitTable: {
values: [
{
fruit: 'apple',
number: '5',
},
{
fruit: 'orange',
number: '10',
},
],
},
};
export default initialTables;

View File

@ -1,3 +1,4 @@
import { IStoreTable } from './tables';
import { TValues, ValuesNames } from './values';
import { TElements, ElementsNames } from './elements';
import { TStatuses, Status } from './statuses';
@ -17,4 +18,12 @@ export interface ICalculationStore {
validations: TElements<boolean>;
getValidation: (elementName: ElementsNames) => boolean;
setValidation: (elementName: ElementsNames, validation: boolean) => void;
tables: IStoreTable;
setTableValue: (
tableName: string,
rowIndex: number,
propName: string,
value: any
) => void;
}

8
src/core/types/tables.ts Normal file
View File

@ -0,0 +1,8 @@
export type IStoreTable = {
[tableName: string]: {
values: Array<any>;
options?: Array<any>;
status?: Array<any>;
filter?: Array<any>;
};
};