Components: render Form/Leasing
This commit is contained in:
parent
6c6c55b433
commit
c565c9286d
@ -72,6 +72,7 @@
|
||||
"case": "kebabCase",
|
||||
"ignore": ["^.*.(jsx|tsx)$"]
|
||||
}
|
||||
]
|
||||
],
|
||||
"import/no-unresolved": "warn"
|
||||
}
|
||||
}
|
||||
|
||||
14
Components/Calculation/Form/Leasing/config.ts
Normal file
14
Components/Calculation/Form/Leasing/config.ts
Normal 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;
|
||||
8
Components/Calculation/Form/Leasing/index.jsx
Normal file
8
Components/Calculation/Form/Leasing/index.jsx
Normal file
@ -0,0 +1,8 @@
|
||||
import renderSections from 'Components/Calculation/layout/renderSections';
|
||||
import config from './config';
|
||||
|
||||
function Leasing() {
|
||||
return renderSections(config);
|
||||
}
|
||||
|
||||
export default Leasing;
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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 = {
|
||||
|
||||
@ -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 = {
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
@ -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;
|
||||
5
Components/Calculation/config/map/index.js
Normal file
5
Components/Calculation/config/map/index.js
Normal file
@ -0,0 +1,5 @@
|
||||
import actions from './actions';
|
||||
import computed from './computed';
|
||||
import values from './values';
|
||||
|
||||
export default Object.assign(values, computed, actions);
|
||||
@ -150,6 +150,8 @@ const elementsToValues = wrapElementsMap({
|
||||
linkDownloadKp: 'kpUrl',
|
||||
});
|
||||
|
||||
export default elementsToValues;
|
||||
|
||||
type ElementsValues = typeof elementsToValues;
|
||||
|
||||
export type ElementsTypes = {
|
||||
39
Components/Calculation/layout/renderSections.tsx
Normal file
39
Components/Calculation/layout/renderSections.tsx
Normal 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;
|
||||
8
Components/Calculation/types/sections.ts
Normal file
8
Components/Calculation/types/sections.ts
Normal 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']]
|
||||
>;
|
||||
@ -11,7 +11,7 @@ type ElementProps = {
|
||||
export default function Select({
|
||||
value = null,
|
||||
setValue,
|
||||
options,
|
||||
options = [],
|
||||
status,
|
||||
isValid,
|
||||
help,
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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';
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user