From 8f0ac2cf4092dac40b6c5ab01c7130aa6312b0b4 Mon Sep 17 00:00:00 2001 From: Chika Date: Tue, 24 May 2022 11:47:17 +0300 Subject: [PATCH] elements: add render props --- .eslintrc.json | 3 +- .../Calculation/builders/build-action.tsx | 16 ++- .../Calculation/builders/build-computed.tsx | 18 ++- .../Calculation/builders/build-options.tsx | 15 ++- .../Calculation/builders/build-readonly.tsx | 18 ++- .../Calculation/builders/build-value.tsx | 15 ++- Components/Calculation/builders/types.ts | 8 -- .../Calculation/config/elements-render.tsx | 103 ++++++++++++++++++ Components/Calculation/config/map-values.ts | 3 + .../Calculation/types/elements-props.ts | 3 + Elements/Button.tsx | 4 +- Elements/Checkbox.tsx | 6 +- Elements/Link.tsx | 11 +- Elements/Select.tsx | 4 +- Elements/Tooltip.js | 3 + 15 files changed, 185 insertions(+), 45 deletions(-) delete mode 100644 Components/Calculation/builders/types.ts create mode 100644 Components/Calculation/config/elements-render.tsx create mode 100644 Elements/Tooltip.js diff --git a/.eslintrc.json b/.eslintrc.json index 6f44ae8..5b25ddd 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -48,6 +48,7 @@ } ], "newline-before-return": "warn", - "@typescript-eslint/consistent-type-imports": "error" + "@typescript-eslint/consistent-type-imports": "error", + "react/prop-types": "off" } } diff --git a/Components/Calculation/builders/build-action.tsx b/Components/Calculation/builders/build-action.tsx index 9419338..08b1012 100644 --- a/Components/Calculation/builders/build-action.tsx +++ b/Components/Calculation/builders/build-action.tsx @@ -1,20 +1,24 @@ /* eslint-disable react/jsx-no-bind */ import { observer } from 'mobx-react-lite'; +import type { FC } from 'react'; import { useStatus } from 'stores/calculation/statuses/hooks'; -import { getAction } from '../config/map-actions'; -import type { BuilderProps } from './types'; +import type { Elements } from '../config/map-actions'; +import type { ElementsProps } from '../types/elements-props'; -export default function buildAction({ elementName, Component, ...props }: BuilderProps) { - const actionName = getAction(elementName); +type BuilderProps = { + elementName: Elements; + actionName: string; +}; - return observer(() => { +export default function buildAction(Component: FC, { elementName, actionName }: BuilderProps) { + return observer((props) => { const status = useStatus(elementName); return ( import(`process/${actionName}`).then((m) => m.default())} + {...props} /> ); }); diff --git a/Components/Calculation/builders/build-computed.tsx b/Components/Calculation/builders/build-computed.tsx index c0b7f3c..4c3c915 100644 --- a/Components/Calculation/builders/build-computed.tsx +++ b/Components/Calculation/builders/build-computed.tsx @@ -1,13 +1,21 @@ import { observer } from 'mobx-react-lite'; +import type { FC } from 'react'; import { useStatus } from 'stores/calculation/statuses/hooks'; +import type { ComputedValues } from 'stores/calculation/values/computed'; import { useComputedValue } from 'stores/calculation/values/hooks'; -import { getComputedValueName } from '../config/map-computed'; -import type { BuilderProps } from './types'; +import type { Elements } from '../config/map-computed'; +import type { ElementsProps } from '../types/elements-props'; -export default function buildComputedValue({ elementName, Component, ...props }: BuilderProps) { - const computedValueName = getComputedValueName(elementName); +type BuilderProps = { + elementName: Elements; + computedValueName: ComputedValues; +}; - return observer(() => { +export default function buildComputedValue( + Component: FC, + { elementName, computedValueName }: BuilderProps +) { + return observer((props) => { const computedValue = useComputedValue(computedValueName); const status = useStatus(elementName); diff --git a/Components/Calculation/builders/build-options.tsx b/Components/Calculation/builders/build-options.tsx index 7a4e245..d205162 100644 --- a/Components/Calculation/builders/build-options.tsx +++ b/Components/Calculation/builders/build-options.tsx @@ -1,15 +1,20 @@ import { observer } from 'mobx-react-lite'; +import type { FC } from 'react'; import { useOptions } from 'stores/calculation/options/hooks'; import { useStatus } from 'stores/calculation/statuses/hooks'; import { useValidation } from 'stores/calculation/validation/hooks'; import { useSetValue, useValue } from 'stores/calculation/values/hooks'; -import { getValueName } from '../config/map-values'; -import type { BuilderProps } from './types'; +import type { Values } from 'stores/calculation/values/types'; +import type { Elements } from '../config/map-values'; +import type { ElementsProps } from '../types/elements-props'; -export default function buildOptions({ elementName, Component, ...props }: BuilderProps) { - const valueName = getValueName(elementName); +type BuilderProps = { + elementName: Elements; + valueName: Values; +}; - return observer(() => { +export default function buildOptions(Component: FC, { elementName, valueName }: BuilderProps) { + return observer((props) => { const value = useValue(valueName); const setValue = useSetValue(valueName); const status = useStatus(elementName); diff --git a/Components/Calculation/builders/build-readonly.tsx b/Components/Calculation/builders/build-readonly.tsx index f38b42b..b89ee91 100644 --- a/Components/Calculation/builders/build-readonly.tsx +++ b/Components/Calculation/builders/build-readonly.tsx @@ -1,12 +1,20 @@ import { observer } from 'mobx-react-lite'; +import type { FC } from 'react'; import { useValue } from 'stores/calculation/values/hooks'; -import { getValueName } from '../config/map-values'; -import type { BuilderProps } from './types'; +import type { Values } from 'stores/calculation/values/types'; +import type { Elements } from '../config/map-values'; +import type { ElementsProps } from '../types/elements-props'; -export default function buildReadonly({ elementName, Component, ...props }: BuilderProps) { - const valueName = getValueName(elementName); +type BuilderProps = { + elementName: Elements; + valueName: Values; +}; - return observer(() => { +export default function buildReadonly( + Component: FC, + { elementName, valueName }: BuilderProps +) { + return observer((props) => { const value = useValue(valueName); return ; diff --git a/Components/Calculation/builders/build-value.tsx b/Components/Calculation/builders/build-value.tsx index d214b4d..06677d0 100644 --- a/Components/Calculation/builders/build-value.tsx +++ b/Components/Calculation/builders/build-value.tsx @@ -1,14 +1,19 @@ import { observer } from 'mobx-react-lite'; +import type { FC } from 'react'; import { useStatus } from 'stores/calculation/statuses/hooks'; import { useValidation } from 'stores/calculation/validation/hooks'; import { useSetValue, useValue } from 'stores/calculation/values/hooks'; -import { getValueName } from '../config/map-values'; -import type { BuilderProps } from './types'; +import type { Values } from 'stores/calculation/values/types'; +import type { Elements } from '../config/map-values'; +import type { ElementsProps } from '../types/elements-props'; -export default function buildValue({ elementName, Component, ...props }: BuilderProps) { - const valueName = getValueName(elementName); +type BuilderProps = { + elementName: Elements; + valueName: Values; +}; - return observer(() => { +export default function buildValue(Component: FC, { elementName, valueName }: BuilderProps) { + return observer((props) => { const value = useValue(valueName); const setValue = useSetValue(valueName); const status = useStatus(elementName); diff --git a/Components/Calculation/builders/types.ts b/Components/Calculation/builders/types.ts deleted file mode 100644 index c1d8743..0000000 --- a/Components/Calculation/builders/types.ts +++ /dev/null @@ -1,8 +0,0 @@ -import type { FC } from 'react'; -import type { Elements } from '../config/map-values'; - -export interface BuilderProps { - elementName: Elements; - Component: FC; - style: React.CSSProperties; -} diff --git a/Components/Calculation/config/elements-render.tsx b/Components/Calculation/config/elements-render.tsx new file mode 100644 index 0000000..049ab92 --- /dev/null +++ b/Components/Calculation/config/elements-render.tsx @@ -0,0 +1,103 @@ +import Link from 'Elements/Link'; +import Tooltip from 'Elements/Tooltip'; +import type { FC, ReactNode } from 'react'; +import { Flex } from 'UIKit/grid'; +import buildReadonly from '../builders/build-readonly'; +import type { Elements } from './map-values'; + +function Head({ children }: { children: ReactNode }) { + return ( + + {children} + + ); +} + +type RenderProps = { render: (Title: FC, Element: FC) => JSX.Element }; + +const render: Partial> = { + selectLead: { + render: (Title, Element) => { + const LinkComponent = buildReadonly(Link, { + elementName: 'linkLeadUrl', + valueName: 'leadUrl', + }); + + return ( + + + + <LinkComponent text="Открыть в CRM" /> + </Head> + <Element /> + </Flex> + ); + }, + }, + + selectOpportunity: { + render: (Title, Element) => { + const LinkComponent = buildReadonly(Link, { + elementName: 'linkOpportunityUrl', + valueName: 'opportunityUrl', + }); + + return ( + <Flex flexDirection="column"> + <Head> + <Title /> + <LinkComponent text="Открыть в CRM" /> + </Head> + <Element /> + </Flex> + ); + }, + }, + + selectQuote: { + render: (Title, Element) => { + const LinkComponent = buildReadonly(Link, { + elementName: 'linkQuoteUrl', + valueName: 'quoteUrl', + }); + + return ( + <Flex flexDirection="column"> + <Head> + <Title /> + <LinkComponent text="Открыть в CRM" /> + </Head> + <Element /> + </Flex> + ); + }, + }, + + tbxVehicleTaxInYear: { + render: (Title, Component) => ( + <Tooltip title="Без учета налога на роскошь" placement="topLeft"> + <Flex flexDirection="column"> + <Title /> + <Component /> + </Flex> + </Tooltip> + ), + }, + + selectHighSeasonStart: { + render: (Title, Component) => ( + <Tooltip title="С какого платежа начинается полный высокий сезон" placement="topLeft"> + <Flex flexDirection="column"> + <Title /> + <Component /> + </Flex> + </Tooltip> + ), + }, +}; + +export default render; diff --git a/Components/Calculation/config/map-values.ts b/Components/Calculation/config/map-values.ts index 34ca75a..acb4a4f 100644 --- a/Components/Calculation/config/map-values.ts +++ b/Components/Calculation/config/map-values.ts @@ -148,6 +148,9 @@ const elementsToValues = wrapElementsMap({ /** Link Elements */ linkDownloadKp: 'kpUrl', + linkLeadUrl: 'leadUrl', + linkOpportunityUrl: 'opportunityUrl', + linkQuoteUrl: 'quoteUrl', }); type ElementsValues = typeof elementsToValues; diff --git a/Components/Calculation/types/elements-props.ts b/Components/Calculation/types/elements-props.ts index f3a8b30..e97fd61 100644 --- a/Components/Calculation/types/elements-props.ts +++ b/Components/Calculation/types/elements-props.ts @@ -162,4 +162,7 @@ export interface ElementsProps { /** Link Elements */ linkDownloadKp: LinkProps; + linkLeadUrl: LinkProps; + linkOpportunityUrl: LinkProps; + linkQuoteUrl: LinkProps; } diff --git a/Elements/Button.tsx b/Elements/Button.tsx index ee25b55..a3a2d58 100644 --- a/Elements/Button.tsx +++ b/Elements/Button.tsx @@ -3,12 +3,12 @@ import type { BaseButtonProps } from 'antd/lib/button/button'; import { throttle } from 'lodash'; import type { BaseElementProps } from './types'; -type ElementProps = BaseElementProps<never> & { +type ElementProps = { action: () => void; text: string; }; -export default function Button({ status, action, text }: ElementProps) { +export default function Button({ status, action, text }: BaseElementProps<never> & ElementProps) { const throttledAction = throttle(action, 1200, { trailing: false, }); diff --git a/Elements/Checkbox.tsx b/Elements/Checkbox.tsx index 0acff79..9a8ed4e 100644 --- a/Elements/Checkbox.tsx +++ b/Elements/Checkbox.tsx @@ -5,7 +5,7 @@ import type { BaseElementProps } from './types'; const { Item: FormItem } = Form; -type ElementProps = BaseElementProps<boolean> & { +type ElementProps = { text: string; }; @@ -17,7 +17,7 @@ export default function Checkbox({ help, text, ...props -}: ElementProps) { +}: BaseElementProps<boolean> & ElementProps) { function handleChange(e: CheckboxChangeEvent) { setValue(e.target.checked); } @@ -36,6 +36,6 @@ export default function Checkbox({ ); } -type CheckboxProps = AntCheckboxProps & Pick<ElementProps, 'text'>; +type CheckboxProps = AntCheckboxProps & ElementProps; export type { CheckboxProps }; diff --git a/Elements/Link.tsx b/Elements/Link.tsx index 8acb1c7..8641267 100644 --- a/Elements/Link.tsx +++ b/Elements/Link.tsx @@ -3,11 +3,16 @@ import { Button as AntButton } from 'antd'; import type { BaseButtonProps } from 'antd/lib/button/button'; import type { BaseElementProps } from './types'; -type ElementProps = BaseElementProps<string> & { +type ElementProps = { text: string; }; -export default function Link({ value, status, text, ...props }: ElementProps) { +export default function Link({ + value, + status, + text, + ...props +}: BaseElementProps<string> & ElementProps) { return ( <AntButton rel="noopener" @@ -23,6 +28,6 @@ export default function Link({ value, status, text, ...props }: ElementProps) { ); } -type LinkProps = BaseButtonProps & Pick<ElementProps, 'text'>; +type LinkProps = BaseButtonProps & ElementProps; export type { LinkProps }; diff --git a/Elements/Select.tsx b/Elements/Select.tsx index 8dce972..077ac4c 100644 --- a/Elements/Select.tsx +++ b/Elements/Select.tsx @@ -5,7 +5,7 @@ import type { BaseElementProps, BaseOption } from './types'; const { Item: FormItem } = Form; -type ElementProps = BaseElementProps<string | null> & { +type ElementProps = { options: BaseOption[]; }; @@ -17,7 +17,7 @@ export default function Select({ isValid, help, ...props -}: ElementProps) { +}: BaseElementProps<string | null> & ElementProps) { const optionsWithNull = useMemo( () => [ { diff --git a/Elements/Tooltip.js b/Elements/Tooltip.js new file mode 100644 index 0000000..98fa122 --- /dev/null +++ b/Elements/Tooltip.js @@ -0,0 +1,3 @@ +import { Tooltip } from 'antd'; + +export default Tooltip;