add tabled elements Component
This commit is contained in:
parent
0dc196fab3
commit
8abc0bfc03
@ -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>
|
||||
|
||||
@ -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,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
41
src/client/Elements/Table.jsx
Normal file
41
src/client/Elements/Table.jsx
Normal 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;
|
||||
@ -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);
|
||||
};
|
||||
|
||||
@ -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 };
|
||||
};
|
||||
62
src/client/hooks/useValue.js
Normal file
62
src/client/hooks/useValue.js
Normal 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 };
|
||||
};
|
||||
@ -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 =>
|
||||
|
||||
17
src/core/config/initialTables.ts
Normal file
17
src/core/config/initialTables.ts
Normal 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;
|
||||
@ -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
8
src/core/types/tables.ts
Normal file
@ -0,0 +1,8 @@
|
||||
export type IStoreTable = {
|
||||
[tableName: string]: {
|
||||
values: Array<any>;
|
||||
options?: Array<any>;
|
||||
status?: Array<any>;
|
||||
filter?: Array<any>;
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user