Components: render Form/Leasing

This commit is contained in:
Chika 2022-05-31 15:28:14 +03:00
parent 6c6c55b433
commit c565c9286d
19 changed files with 257 additions and 77 deletions

View File

@ -72,6 +72,7 @@
"case": "kebabCase",
"ignore": ["^.*.(jsx|tsx)$"]
}
]
],
"import/no-unresolved": "warn"
}
}

View File

@ -0,0 +1,14 @@
/* eslint-disable object-curly-newline */
import type { SectionsConfig } from 'Components/Calculation/types/sections';
const config: SectionsConfig = [
[['selectProduct'], { gridTemplateColumns: '1fr' }],
[['tbxLeaseObjectPrice', 'tbxVATInLeaseObjectPrice', 'tbxLeaseObjectPriceWthtVAT']],
[['selectSupplierCurrency', 'tbxSupplierDiscountRub', 'tbxSupplierDiscountPerc']],
[['tbxFirstPaymentPerc', 'tbxFirstPaymentRub']],
[['tbxLeasingPeriod', 'tbxSaleBonus', 'tbxRedemptionPaymentSum']],
[['selectSubsidy', 'labelSubsidySum']],
[['tbxLastPaymentPerc', 'tbxLastPaymentRub', 'radioLastPaymentRule']],
];
export default config;

View File

@ -0,0 +1,8 @@
import renderSections from 'Components/Calculation/layout/renderSections';
import config from './config';
function Leasing() {
return renderSections(config);
}
export default Leasing;

View File

@ -2,15 +2,18 @@
import { observer } from 'mobx-react-lite';
import type { FC } from 'react';
import { useStatus } from 'stores/calculation/statuses/hooks';
import type { Elements } from '../config/map-actions';
import type { Elements } from '../config/map/actions';
import type { ElementsProps } from '../types/elements-props';
type BuilderProps = {
elementName: Elements;
actionName: string;
valueName: string;
};
export default function buildAction(Component: FC<any>, { elementName, actionName }: BuilderProps) {
export default function buildAction(
Component: FC<any>,
{ elementName, valueName: actionName }: BuilderProps
) {
return observer<ElementsProps[typeof elementName]>((props) => {
const status = useStatus(elementName);

View File

@ -3,17 +3,17 @@ 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 type { Elements } from '../config/map-computed';
import type { Elements } from '../config/map/computed';
import type { ElementsProps } from '../types/elements-props';
type BuilderProps = {
elementName: Elements;
computedValueName: ComputedValues;
valueName: ComputedValues;
};
export default function buildComputedValue(
Component: FC<any>,
{ elementName, computedValueName }: BuilderProps
{ elementName, valueName: computedValueName }: BuilderProps
) {
return observer<ElementsProps[typeof elementName]>((props) => {
const computedValue = useComputedValue(computedValueName);

View File

@ -5,7 +5,7 @@ import { useStatus } from 'stores/calculation/statuses/hooks';
import { useValidation } from 'stores/calculation/validation/hooks';
import { useSetValue, useValue } from 'stores/calculation/values/hooks';
import type { Values } from 'stores/calculation/values/types';
import type { Elements } from '../config/map-values';
import type { Elements } from '../config/map/values';
import type { ElementsProps } from '../types/elements-props';
type BuilderProps = {

View File

@ -4,7 +4,7 @@ import { useStatus } from 'stores/calculation/statuses/hooks';
import { useValidation } from 'stores/calculation/validation/hooks';
import { useSetValue, useValue } from 'stores/calculation/values/hooks';
import type { Values } from 'stores/calculation/values/types';
import type { Elements } from '../config/map-values';
import type { Elements } from '../config/map/values';
import type { ElementsProps } from '../types/elements-props';
type BuilderProps = {

View File

@ -7,12 +7,12 @@ import Radio from 'Elements/Radio';
import Select from 'Elements/Select';
import Switch from 'Elements/Switch';
import Text from 'Elements/Text';
import type { Elements as ActionElements } from './map-actions';
import type { Elements as ComputedElements } from './map-computed';
import type { Elements } from './map-values';
import type { Elements as ActionElements } from './map/actions';
import type { Elements as ComputedElements } from './map/computed';
import type { Elements as ValuesElements } from './map/values';
const components: Record<
Elements | ComputedElements | ActionElements,
ValuesElements | ComputedElements | ActionElements,
(props: any) => JSX.Element
> = {
selectProduct: Select,

View File

@ -1,103 +1,204 @@
/* eslint-disable object-curly-newline */
import Link from 'Elements/Link';
import Tooltip from 'Elements/Tooltip';
import type { FC, ReactNode } from 'react';
import type { ReactNode } from 'react';
import styled from 'styled-components';
import { Flex } from 'UIKit/grid';
import { min } from 'UIKit/mq';
import buildReadonly from '../builders/build-readonly';
import type { Elements } from './map-values';
import builders from './elements-builders';
import components from './elements-components';
import elementsProps from './elements-props';
import titles from './elements-titles';
import map from './map';
function Head({ children }: { children: ReactNode }) {
const ElementTitle = styled.h5`
color: rgba(0, 0, 0, 0.75);
font-weight: 600;
font-size: 13px;
line-height: 1.5;
margin: 0 8px 3px 0;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
${min('laptop')} {
font-size: 14px;
}
`;
function Head({ title, addon }: { title: string; addon?: ReactNode }) {
return (
<Flex
flexDirection={['column', 'row']}
justifyContent={['', 'space-between']}
alignItems={['', 'center']}
>
{children}
<ElementTitle>{title}</ElementTitle>
{addon}
</Flex>
);
}
type RenderProps = { render: (Title: FC, Element: FC) => JSX.Element };
function Container({ children }: { children: ReactNode }) {
return <Flex flexDirection="column">{children}</Flex>;
}
const render: Partial<Record<Elements, RenderProps>> = {
type RenderProps = { render: () => JSX.Element };
const renderElements = (Object.keys(map) as (keyof typeof map)[]).reduce((acc, elementName) => {
const title = titles[elementName];
const valueName = map[elementName];
const Component = components[elementName];
const props = elementsProps[elementName];
const builder = builders[elementName];
const Element = builder(Component, {
elementName,
valueName,
});
acc[elementName] = {
render: () => (
<Container>
<Head title={title} />
<Element {...props} style={{ width: '100%' }} />
</Container>
),
};
return acc;
}, {} as Record<keyof typeof map, RenderProps>);
const overrideRenderElements: Partial<Record<keyof typeof map, RenderProps>> = {
selectLead: {
render: (Title, Element) => {
render: () => {
const title = titles.selectLead;
const valueName = map.selectLead;
const Component = components.selectLead;
const props = elementsProps.selectLead;
const builder = builders.selectLead;
const Element = builder(Component, {
elementName: 'selectLead',
valueName,
});
const LinkComponent = buildReadonly(Link, {
elementName: 'linkLeadUrl',
valueName: 'leadUrl',
});
return (
<Flex flexDirection="column">
<Head>
<Title />
<LinkComponent text="Открыть в CRM" />
</Head>
<Element />
</Flex>
<Container>
<Head title={title} addon={<LinkComponent text="Открыть в CRM" />} />
<Element {...props} style={{ width: '100%' }} />
</Container>
);
},
},
selectOpportunity: {
render: (Title, Element) => {
render: () => {
const title = titles.selectOpportunity;
const valueName = map.selectOpportunity;
const Component = components.selectOpportunity;
const props = elementsProps.selectOpportunity;
const builder = builders.selectOpportunity;
const Element = builder(Component, {
elementName: 'selectOpportunity',
valueName,
});
const LinkComponent = buildReadonly(Link, {
elementName: 'linkOpportunityUrl',
valueName: 'opportunityUrl',
});
return (
<Flex flexDirection="column">
<Head>
<Title />
<LinkComponent text="Открыть в CRM" />
</Head>
<Element />
</Flex>
<Container>
<Head title={title} addon={<LinkComponent text="Открыть в CRM" />} />
<Element {...props} style={{ width: '100%' }} />
</Container>
);
},
},
selectQuote: {
render: (Title, Element) => {
render: () => {
const title = titles.selectQuote;
const valueName = map.selectQuote;
const Component = components.selectQuote;
const props = elementsProps.selectQuote;
const builder = builders.selectQuote;
const Element = builder(Component, {
elementName: 'selectQuote',
valueName,
});
const LinkComponent = buildReadonly(Link, {
elementName: 'linkQuoteUrl',
valueName: 'quoteUrl',
});
return (
<Flex flexDirection="column">
<Head>
<Title />
<LinkComponent text="Открыть в CRM" />
</Head>
<Element />
</Flex>
<Container>
<Head title={title} addon={<LinkComponent text="Открыть в CRM" />} />
<Element {...props} style={{ width: '100%' }} />
</Container>
);
},
},
tbxVehicleTaxInYear: {
render: (Title, Component) => (
<Tooltip title="Без учета налога на роскошь" placement="topLeft">
<Flex flexDirection="column">
<Title />
<Component />
</Flex>
</Tooltip>
),
render: () => {
const title = titles.tbxVehicleTaxInYear;
const valueName = map.tbxVehicleTaxInYear;
const Component = components.tbxVehicleTaxInYear;
const props = elementsProps.tbxVehicleTaxInYear;
const builder = builders.tbxVehicleTaxInYear;
const Element = builder(Component, {
elementName: 'tbxVehicleTaxInYear',
valueName,
});
return (
<Tooltip title="Без учета налога на роскошь" placement="topLeft">
<Container>
<Head title={title} />
<Element {...props} style={{ width: '100%' }} />
</Container>
</Tooltip>
);
},
},
selectHighSeasonStart: {
render: (Title, Component) => (
<Tooltip title="С какого платежа начинается полный высокий сезон" placement="topLeft">
<Flex flexDirection="column">
<Title />
<Component />
</Flex>
</Tooltip>
),
render: () => {
const title = titles.selectHighSeasonStart;
const valueName = map.selectHighSeasonStart;
const Component = components.selectHighSeasonStart;
const props = elementsProps.selectHighSeasonStart;
const builder = builders.selectHighSeasonStart;
const Element = builder(Component, {
elementName: 'selectHighSeasonStart',
valueName,
});
return (
<Tooltip title="С какого платежа начинается полный высокий сезон" placement="topLeft">
<Container>
<Head title={title} />
<Element {...props} style={{ width: '100%' }} />
</Container>
</Tooltip>
);
},
},
};
export default render;
export default Object.assign(renderElements, overrideRenderElements);

View File

@ -1,7 +1,8 @@
import type { Elements as ComputedElements } from './map-computed';
import type { Elements } from './map-values';
import type { Elements as ActionElements } from './map/actions';
import type { Elements as ComputedElements } from './map/computed';
import type { Elements as ValuesElements } from './map/values';
const titles: Record<Elements | ComputedElements, string> = {
const titles: Record<ValuesElements | ComputedElements | ActionElements, string> = {
selectLead: 'Интерес',
selectOpportunity: 'Лизинговая сделка',
selectQuote: 'Предложение',
@ -151,6 +152,10 @@ const titles: Record<Elements | ComputedElements, string> = {
labelLeaseObjectRisk: 'Риск ПЛ',
labelRegistrationDescription: 'Описание регистрации',
tbxInsKaskoPriceLeasePeriod: 'Стоимость страховки КАСКО на весь срок',
/** Action Elements */
btnCalculate: '',
btnCreateKP: '',
};
export default titles;

View File

@ -7,10 +7,6 @@ const elementsToActions = wrapElementsMap({
btnCreateKP: 'create-kp',
});
export default elementsToActions;
export type Elements = keyof typeof elementsToActions;
export function getAction(elementName: Elements) {
const actionName = elementsToActions[elementName];
return actionName;
}

View File

@ -11,8 +11,6 @@ const elementsToComputed = wrapElementsMap({
labelRegistrationDescription: 'registrationDescription',
});
export type Elements = keyof typeof elementsToComputed;
export default elementsToComputed;
export function getComputedValueName(elementName: Elements) {
return elementsToComputed[elementName];
}
export type Elements = keyof typeof elementsToComputed;

View File

@ -0,0 +1,5 @@
import actions from './actions';
import computed from './computed';
import values from './values';
export default Object.assign(values, computed, actions);

View File

@ -150,6 +150,8 @@ const elementsToValues = wrapElementsMap({
linkDownloadKp: 'kpUrl',
});
export default elementsToValues;
type ElementsValues = typeof elementsToValues;
export type ElementsTypes = {

View File

@ -0,0 +1,39 @@
import { Box } from 'UIKit/grid';
import elementsRender from '../config/elements-render';
import type { SectionsConfig } from '../types/sections';
function renderSections(config: SectionsConfig) {
const rows = config.map(([elements, style]) => {
const renderedElements = elements.map((elementName) => {
const render = elementsRender[elementName]?.render;
return render();
});
return (
<Box
sx={{
display: 'grid',
gridTemplateColumns: ['1fr', '1fr', 'repeat(3, 1fr)'],
gap: '10px',
...style,
}}
>
{renderedElements}
</Box>
);
});
return (
<Box
sx={{
display: 'grid',
gridAutoRows: 'auto',
}}
>
{rows}
</Box>
);
}
export default renderSections;

View File

@ -0,0 +1,8 @@
import type { BoxProps } from 'rebass/styled-components';
import type { Elements as ActionElements } from '../config/map/actions';
import type { Elements as ComputedElements } from '../config/map/computed';
import type { Elements as ValuesElements } from '../config/map/values';
export type SectionsConfig = Array<
[elements: (ValuesElements | ComputedElements | ActionElements)[], style?: BoxProps['style']]
>;

View File

@ -11,7 +11,7 @@ type ElementProps = {
export default function Select({
value = null,
setValue,
options,
options = [],
status,
isValid,
help,

View File

@ -4,7 +4,7 @@
/* eslint-disable no-confusing-arrow */
/* eslint-disable object-curly-newline */
/* eslint-disable import/no-cycle */
import type { Elements } from 'Components/Calculation/config/map-values';
import type { Elements } from 'Components/Calculation/config/map/values';
import defaultOptions from 'config/default-options';
import type { BaseOption } from 'Elements/types';
import { makeAutoObservable } from 'mobx';

View File

@ -1,8 +1,8 @@
/* eslint-disable implicit-arrow-linebreak */
/* eslint-disable object-curly-newline */
/* eslint-disable import/no-cycle */
import type { Elements, ElementsTypes } from 'Components/Calculation/config/map-values';
import { getValueName } from 'Components/Calculation/config/map-values';
import type { Elements, ElementsTypes } from 'Components/Calculation/config/map/values';
import { getValueName } from 'Components/Calculation/config/map/values';
import defaultValues from 'config/default-values';
import { makeAutoObservable } from 'mobx';
import type RootStore from '../../root';