From 8abc0bfc0338dc5bc5feefd90649ecc57b4d62a7 Mon Sep 17 00:00:00 2001 From: Chika Date: Mon, 14 Sep 2020 18:27:10 +0300 Subject: [PATCH] add tabled elements Component --- .../Containers/Calculation/Sections/index.jsx | 19 +++--- .../Containers/Calculation/Sections/list.js | 23 +++++-- src/client/Elements/Table.jsx | 41 ++++++++++++ src/client/hocs/withStore.js | 35 ++++++++++- src/client/hooks/useStoreValue.js | 33 ---------- src/client/hooks/useValue.js | 62 +++++++++++++++++++ src/client/stores/CalculationStore/index.ts | 16 ++++- src/core/config/initialTables.ts | 17 +++++ src/core/types/stores.ts | 9 +++ src/core/types/tables.ts | 8 +++ 10 files changed, 212 insertions(+), 51 deletions(-) create mode 100644 src/client/Elements/Table.jsx delete mode 100644 src/client/hooks/useStoreValue.js create mode 100644 src/client/hooks/useValue.js create mode 100644 src/core/config/initialTables.ts create mode 100644 src/core/types/tables.ts diff --git a/src/client/Containers/Calculation/Sections/index.jsx b/src/client/Containers/Calculation/Sections/index.jsx index 63a9872..b774d3e 100644 --- a/src/client/Containers/Calculation/Sections/index.jsx +++ b/src/client/Containers/Calculation/Sections/index.jsx @@ -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 ( {elementTitle} diff --git a/src/client/Containers/Calculation/Sections/list.js b/src/client/Containers/Calculation/Sections/list.js index 84770d8..83342f5 100644 --- a/src/client/Containers/Calculation/Sections/list.js +++ b/src/client/Containers/Calculation/Sections/list.js @@ -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, + }, + ], + }, }, ], }, diff --git a/src/client/Elements/Table.jsx b/src/client/Elements/Table.jsx new file mode 100644 index 0000000..8a3727c --- /dev/null +++ b/src/client/Elements/Table.jsx @@ -0,0 +1,41 @@ +import { withTableValue } from 'client/hocs/withStore'; +import React from 'react'; + +const Table = ({ name: tableName, columns, values }) => { + return ( + + + + {columns.map(({ name, title }, ci) => { + return ; + })} + + + + {values.map((row, ri) => { + const keys = Object.keys(row); + return ( + + {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 ( + + ); + })} + + ); + })} + +
{title}
+ +
+ ); +}; + +export default Table; diff --git a/src/client/hocs/withStore.js b/src/client/hocs/withStore.js index 2de13a7..17f312d 100644 --- a/src/client/hocs/withStore.js +++ b/src/client/hocs/withStore.js @@ -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 ; + }; + return TableWithStore; +}; + +export const withTableValue = Component => ({ + tableName, + rowIndex, + propName, + ...params +}) => { + const ComponentWithStore = () => { + const { value, setCurrentValue } = useTableValue({ + tableName, + rowIndex, + propName, + }); + + return ( + + ); + }; + return observer(ComponentWithStore); +}; diff --git a/src/client/hooks/useStoreValue.js b/src/client/hooks/useStoreValue.js deleted file mode 100644 index 25384a1..0000000 --- a/src/client/hooks/useStoreValue.js +++ /dev/null @@ -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 }; -}; diff --git a/src/client/hooks/useValue.js b/src/client/hooks/useValue.js new file mode 100644 index 0000000..7149275 --- /dev/null +++ b/src/client/hooks/useValue.js @@ -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 }; +}; diff --git a/src/client/stores/CalculationStore/index.ts b/src/client/stores/CalculationStore/index.ts index 6cda8a0..52b3c10 100644 --- a/src/client/stores/CalculationStore/index.ts +++ b/src/client/stores/CalculationStore/index.ts @@ -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 => diff --git a/src/core/config/initialTables.ts b/src/core/config/initialTables.ts new file mode 100644 index 0000000..c275589 --- /dev/null +++ b/src/core/config/initialTables.ts @@ -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; diff --git a/src/core/types/stores.ts b/src/core/types/stores.ts index 7cbb079..97a617f 100644 --- a/src/core/types/stores.ts +++ b/src/core/types/stores.ts @@ -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; getValidation: (elementName: ElementsNames) => boolean; setValidation: (elementName: ElementsNames, validation: boolean) => void; + + tables: IStoreTable; + setTableValue: ( + tableName: string, + rowIndex: number, + propName: string, + value: any + ) => void; } diff --git a/src/core/types/tables.ts b/src/core/types/tables.ts new file mode 100644 index 0000000..464d2aa --- /dev/null +++ b/src/core/types/tables.ts @@ -0,0 +1,8 @@ +export type IStoreTable = { + [tableName: string]: { + values: Array; + options?: Array; + status?: Array; + filter?: Array; + }; +};