elements: add render props

This commit is contained in:
Chika 2022-05-24 11:47:17 +03:00
parent ffa2731e0e
commit 8f0ac2cf40
15 changed files with 185 additions and 45 deletions

View File

@ -48,6 +48,7 @@
}
],
"newline-before-return": "warn",
"@typescript-eslint/consistent-type-imports": "error"
"@typescript-eslint/consistent-type-imports": "error",
"react/prop-types": "off"
}
}

View File

@ -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<any>, { elementName, actionName }: BuilderProps) {
return observer<ElementsProps[typeof elementName]>((props) => {
const status = useStatus(elementName);
return (
<Component
status={status}
{...props}
action={() => import(`process/${actionName}`).then((m) => m.default())}
{...props}
/>
);
});

View File

@ -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<any>,
{ elementName, computedValueName }: BuilderProps
) {
return observer<ElementsProps[typeof elementName]>((props) => {
const computedValue = useComputedValue(computedValueName);
const status = useStatus(elementName);

View File

@ -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<any>, { elementName, valueName }: BuilderProps) {
return observer<ElementsProps[typeof elementName]>((props) => {
const value = useValue(valueName);
const setValue = useSetValue(valueName);
const status = useStatus(elementName);

View File

@ -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<any>,
{ elementName, valueName }: BuilderProps
) {
return observer<ElementsProps[typeof elementName]>((props) => {
const value = useValue(valueName);
return <Component value={value} readOnly {...props} />;

View File

@ -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<any>, { elementName, valueName }: BuilderProps) {
return observer<ElementsProps[typeof elementName]>((props) => {
const value = useValue(valueName);
const setValue = useSetValue(valueName);
const status = useStatus(elementName);

View File

@ -1,8 +0,0 @@
import type { FC } from 'react';
import type { Elements } from '../config/map-values';
export interface BuilderProps {
elementName: Elements;
Component: FC<any>;
style: React.CSSProperties;
}

View File

@ -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 (
<Flex
flexDirection={['column', 'row']}
justifyContent={['', 'space-between']}
alignItems={['', 'center']}
>
{children}
</Flex>
);
}
type RenderProps = { render: (Title: FC, Element: FC) => JSX.Element };
const render: Partial<Record<Elements, RenderProps>> = {
selectLead: {
render: (Title, Element) => {
const LinkComponent = buildReadonly(Link, {
elementName: 'linkLeadUrl',
valueName: 'leadUrl',
});
return (
<Flex flexDirection="column">
<Head>
<Title />
<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;

View File

@ -148,6 +148,9 @@ const elementsToValues = wrapElementsMap({
/** Link Elements */
linkDownloadKp: 'kpUrl',
linkLeadUrl: 'leadUrl',
linkOpportunityUrl: 'opportunityUrl',
linkQuoteUrl: 'quoteUrl',
});
type ElementsValues = typeof elementsToValues;

View File

@ -162,4 +162,7 @@ export interface ElementsProps {
/** Link Elements */
linkDownloadKp: LinkProps;
linkLeadUrl: LinkProps;
linkOpportunityUrl: LinkProps;
linkQuoteUrl: LinkProps;
}

View File

@ -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,
});

View File

@ -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 };

View File

@ -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 };

View File

@ -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(
() => [
{

3
Elements/Tooltip.js Normal file
View File

@ -0,0 +1,3 @@
import { Tooltip } from 'antd';
export default Tooltip;