diff --git a/src/client/Containers/Calculation/Sections/index.jsx b/src/client/Containers/Calculation/Sections/index.jsx index 7d469c7..4f2ae83 100644 --- a/src/client/Containers/Calculation/Sections/index.jsx +++ b/src/client/Containers/Calculation/Sections/index.jsx @@ -38,7 +38,7 @@ const renderElements = ({ elements }) => { return elements.map((element, ie) => { const { title: elementTitle, Component, props: elementProps } = element; return ( - + {elementTitle} @@ -64,7 +64,7 @@ const renderBlocks = ({ blocks }) => { '2 0 45%', '2 0 45%', '2 0 45%', - '3 0 30%' + '3 0 30%', ]} mx="10px" my="15px" diff --git a/src/client/Containers/Calculation/Sections/list.js b/src/client/Containers/Calculation/Sections/list.js index 66c4744..3e00c7c 100644 --- a/src/client/Containers/Calculation/Sections/list.js +++ b/src/client/Containers/Calculation/Sections/list.js @@ -7,7 +7,12 @@ import Radio from 'client/Elements/Radio'; import Select from 'client/Elements/Select'; import Switch from 'client/Elements/Switch'; import TextArea from 'client/Elements/TextArea'; -import { validateInn } from 'client/tools/validate'; +import { + validateInn, + validateKpp, + validatePhone, + validateEmail, +} from 'client/tools/validate'; export default [ { @@ -113,7 +118,10 @@ export default [ title: 'КПП', Component: Input, props: { - // TODO regular min: 9, max: 9 + validation: { + errorMessage: 'Некорректный КПП', + validator: validateKpp, + }, name: 'tbxKPP', valueName: 'KPP', }, @@ -156,7 +164,10 @@ export default [ type: 'tel', name: 'tbxPhoneNumber', valueName: 'phoneNumber', - pattern: undefined, + validation: { + errorMessage: 'Некорректный номер телефона', + validator: validatePhone, + }, //TODO: mask + 7(999) 999 99 99 }, }, @@ -167,8 +178,11 @@ export default [ type: 'email', name: 'tbxEmailAddress', valueName: 'emailAddress', - pattern: undefined, - //TODO check email valid + //TODO email mask + validation: { + errorMessage: 'Некорректный E-mail', + validator: validateEmail, + }, }, }, ], diff --git a/src/client/Elements/Checkbox.jsx b/src/client/Elements/Checkbox.jsx index 4f470ee..d6a35e4 100644 --- a/src/client/Elements/Checkbox.jsx +++ b/src/client/Elements/Checkbox.jsx @@ -1,29 +1,28 @@ -import { Checkbox as AntCheckbox } from 'antd'; +import { Checkbox as AntCheckbox, Form } from 'antd'; import { useStatus } from 'client/hooks/useStatus'; import { useStoreValue } from 'client/hooks/useStoreValue'; -import { Box } from 'client/UIKit/grid'; +import { DEFAULT_DEBOUNCE_DELAY } from 'core/constants/debounce'; import { Status } from 'core/types/statuses'; import { observer } from 'mobx-react'; import React from 'react'; -import { DEFAULT_DEBOUNCE_DELAY } from 'core/constants/debounce'; const Checkbox = ({ name, readonly, valueName, computedValue }) => { const { value, setCurrentValue } = useStoreValue({ computedValue, valueName, - debounceDelay: DEFAULT_DEBOUNCE_DELAY + debounceDelay: DEFAULT_DEBOUNCE_DELAY, }); const { status } = useStatus(name); return ( - + setCurrentValue(e.target.checked)} /> - + ); }; diff --git a/src/client/Elements/InputNumber.jsx b/src/client/Elements/InputNumber.jsx index baa4405..277c224 100644 --- a/src/client/Elements/InputNumber.jsx +++ b/src/client/Elements/InputNumber.jsx @@ -1,4 +1,4 @@ -import { InputNumber as AntInputNumber } from 'antd'; +import { InputNumber as AntInputNumber, Form } from 'antd'; import { useStatus } from 'client/hooks/useStatus'; import { useStoreValue } from 'client/hooks/useStoreValue'; import { Status } from 'core/types/statuses'; @@ -16,31 +16,33 @@ const InputNumber = ({ parser, placeholder, valueName, - computedValue + computedValue, }) => { const { value, setCurrentValue } = useStoreValue({ computedValue, valueName, - debounceDelay: TEXT_INPUT_DEBOUNCE_DELAY + debounceDelay: TEXT_INPUT_DEBOUNCE_DELAY, }); const { status } = useStatus(name); return ( - setCurrentValue(value)} - value={value} - /> + + setCurrentValue(value)} + value={value} + /> + ); }; diff --git a/src/client/Elements/Radio.jsx b/src/client/Elements/Radio.jsx index fede3f0..1c1541d 100644 --- a/src/client/Elements/Radio.jsx +++ b/src/client/Elements/Radio.jsx @@ -1,4 +1,4 @@ -import { Radio as AntRadio } from 'antd'; +import { Radio as AntRadio, Form } from 'antd'; import { useOptions } from 'client/hooks/useOptions'; import { useStatus } from 'client/hooks/useStatus'; import { useStoreValue } from 'client/hooks/useStoreValue'; @@ -11,54 +11,44 @@ const Radio = ({ name, style, computedValue, valueName }) => { const { value, setCurrentValue } = useStoreValue({ computedValue, valueName, - debounceDelay: DEFAULT_DEBOUNCE_DELAY + debounceDelay: DEFAULT_DEBOUNCE_DELAY, }); const { status } = useStatus(name); const { options } = useOptions(name); return ( - { - if (e && e.target) setCurrentValue(e.target.value); - }} - > - {options.map((option, i) => { - switch (style) { - case 'button': - if (option) { - return ( - - {option.name} - - ); - } - break; - - default: - if (option) - return ( - - {option.name} - - ); - break; - } - })} - + + { + if (e && e.target) setCurrentValue(e.target.value); + }} + > + {options.map((option, i) => { + if (style === 'button') { + return ( + + {option.name} + + ); + } + return ( + + {option.name} + + ); + })} + + ); }; const styles = { radio: { - display: 'block' - } + display: 'block', + }, }; export default observer(Radio); diff --git a/src/client/Elements/Select.jsx b/src/client/Elements/Select.jsx index 421429e..227ed43 100644 --- a/src/client/Elements/Select.jsx +++ b/src/client/Elements/Select.jsx @@ -1,4 +1,4 @@ -import { Select as AntSelect } from 'antd'; +import { Select as AntSelect, Form } from 'antd'; import { useStatus } from 'client/hooks/useStatus'; import { useStoreValue } from 'client/hooks/useStoreValue'; import { Status } from 'core/types/statuses'; @@ -11,29 +11,32 @@ const Select = ({ name, showSearch, computedValue, valueName }) => { const { value, setCurrentValue } = useStoreValue({ computedValue, valueName, - debounceDelay: DEFAULT_DEBOUNCE_DELAY + debounceDelay: DEFAULT_DEBOUNCE_DELAY, }); const { status } = useStatus(name); const { options, filter } = useOptions(name); return ( - setCurrentValue(val)} - > - {options.map((option, i) => { - if (option) - return ( - - {option.name} - - ); - })} - + + setCurrentValue(val)} + > + {options.map((option, i) => { + if (option) + return ( + + {option.name} + + ); + return null; + })} + + ); }; diff --git a/src/client/Elements/Switch.jsx b/src/client/Elements/Switch.jsx index 1d1ba4d..1f85cd4 100644 --- a/src/client/Elements/Switch.jsx +++ b/src/client/Elements/Switch.jsx @@ -1,22 +1,21 @@ -import { Switch as AntSwitch } from 'antd'; +import { Form, Switch as AntSwitch } from 'antd'; import { useStatus } from 'client/hooks/useStatus'; import { useStoreValue } from 'client/hooks/useStoreValue'; -import { Box } from 'client/UIKit/grid'; +import { DEFAULT_DEBOUNCE_DELAY } from 'core/constants/debounce'; import { Status } from 'core/types/statuses'; import { observer } from 'mobx-react'; import React from 'react'; -import { DEFAULT_DEBOUNCE_DELAY } from 'core/constants/debounce'; const Switch = ({ name, valueName, computedValue }) => { const { value, setCurrentValue } = useStoreValue({ computedValue, valueName, - debounceDelay: DEFAULT_DEBOUNCE_DELAY + debounceDelay: DEFAULT_DEBOUNCE_DELAY, }); const { status } = useStatus(name); return ( - + { setCurrentValue(checked); }} /> - + ); }; diff --git a/src/client/Elements/TextArea.jsx b/src/client/Elements/TextArea.jsx index 5802865..c580fcd 100644 --- a/src/client/Elements/TextArea.jsx +++ b/src/client/Elements/TextArea.jsx @@ -11,20 +11,18 @@ const TextArea = ({ readonly, placeholder, valueName, - computedValue + computedValue, }) => { const { value, setCurrentValue } = useStoreValue({ computedValue, valueName, - debounceDelay: TEXT_INPUT_DEBOUNCE_DELAY + debounceDelay: TEXT_INPUT_DEBOUNCE_DELAY, }); const { status } = useStatus(name); return ( - autorun(autorunEffect(CalculationStore, CommonStore)) + autorun(autorunEffect(CalculationStore, CommonStore)), ); reactionEffects.map(reactionEffectBuilder => { diff --git a/src/client/tools/validate.js b/src/client/tools/validate.js index a5e7e87..6a935e8 100644 --- a/src/client/tools/validate.js +++ b/src/client/tools/validate.js @@ -1,49 +1,90 @@ -export function validateInn(inn) { - if (typeof inn === 'number') { - inn = inn.toString(); - } else if (typeof inn !== 'string') { - inn = ''; +import validator from 'validator'; + +const isINNIndividual = value => { + const valueToString = value ? value.toString() : ''; + const getN = index => parseInt(valueToString[index]); + if (valueToString.length === 12) { + const dgt11 = + ((7 * getN(0) + + 2 * getN(1) + + 4 * getN(2) + + 10 * getN(3) + + 3 * getN(4) + + 5 * getN(5) + + 9 * getN(6) + + 4 * getN(7) + + 6 * getN(8) + + 8 * getN(9)) % + 11) % + 10; + + const dgt12 = + ((3 * getN(0) + + 7 * getN(1) + + 2 * getN(2) + + 4 * getN(3) + + 10 * getN(4) + + 3 * getN(5) + + 5 * getN(6) + + 9 * getN(7) + + 4 * getN(8) + + 6 * getN(9) + + 8 * getN(10)) % + 11) % + 10; + + return getN(10) === dgt11 && getN(11) === dgt12; } - var checkDigit = function (inn, coefficients) { - var n = 0; - for (var i in coefficients) { - n += coefficients[i] * inn[i]; - } - return parseInt((n % 11) % 10); - }; - switch (inn.length) { - case 10: - var n10 = checkDigit(inn, [2, 4, 10, 3, 5, 9, 4, 6, 8]); - return n10 === parseInt(inn[9]); - case 12: - var n11 = checkDigit(inn, [7, 2, 4, 10, 3, 5, 9, 4, 6, 8]); - var n12 = checkDigit(inn, [3, 7, 2, 4, 10, 3, 5, 9, 4, 6, 8]); - return n11 === parseInt(inn[10]) && n12 === parseInt(inn[11]); - default: { - return false; - } + return false; +}; + +const isINNLegalEntity = value => { + const valueToString = value ? value.toString() : ''; + const getN = index => parseInt(valueToString[index]); + if (valueToString.length === 10) { + const dgt10 = + ((2 * getN(0) + + 4 * getN(1) + + 10 * getN(2) + + 3 * getN(3) + + 5 * getN(4) + + 9 * getN(5) + + 4 * getN(6) + + 6 * getN(7) + + 8 * getN(8)) % + 11) % + 10; + return getN(9) === dgt10; } + return false; +}; + +export function validateInn(value) { + const stringValue = value ? value.toString() : ''; + + if (stringValue.length === 10) { + return isINNLegalEntity(stringValue); + } + if (stringValue.length === 12) { + return isINNIndividual(stringValue); + } + + return false; } -export function validateKpp(kpp, error) { - var result = false; - if (typeof kpp === 'number') { - kpp = kpp.toString(); - } else if (typeof kpp !== 'string') { - kpp = ''; - } - if (!kpp.length) { - error.code = 1; - error.message = 'КПП пуст'; - } else if (kpp.length !== 9) { - error.code = 2; - error.message = - 'КПП может состоять только из 9 знаков (цифр или заглавных букв латинского алфавита от A до Z)'; - } else if (!/^[0-9]{4}[0-9A-Z]{2}[0-9]{3}$/.test(kpp)) { - error.code = 3; - error.message = 'Неправильный формат КПП'; - } else { - result = true; - } - return result; +export function validateKpp(value) { + const stringValue = value ? value.toString() : ''; + if (stringValue.length !== 9) return false; + if (!stringValue.match(/\d{4}[\dA-Z][\dA-Z]\d{3}/)) return false; + return true; +} + +export function validatePhone(value) { + const stringValue = value ? value.toString() : ''; + return validator.isMobilePhone(stringValue, ['ru-RU']); +} + +export function validateEmail(value) { + const stringValue = value ? value.toString() : ''; + return validator.isEmail(stringValue); } diff --git a/src/core/config/initialOptions.ts b/src/core/config/initialOptions.ts index bd04f17..86aa500 100644 --- a/src/core/config/initialOptions.ts +++ b/src/core/config/initialOptions.ts @@ -1,6 +1,6 @@ import { TElements } from 'core/types/elements'; -const initialOptions: TElements = { +const initialOptions: TElements = { selectChannel: [ { name: 'От агента-ФЛ-сотрудника поставщика', diff --git a/src/core/constants/debounce.js b/src/core/constants/debounce.js index cfbc483..0993b7e 100644 --- a/src/core/constants/debounce.js +++ b/src/core/constants/debounce.js @@ -1,2 +1,2 @@ -export const TEXT_INPUT_DEBOUNCE_DELAY = 800; +export const TEXT_INPUT_DEBOUNCE_DELAY = 650; export const DEFAULT_DEBOUNCE_DELAY = 0; diff --git a/src/core/types/elements.ts b/src/core/types/elements.ts index a8e3b69..a3cf34b 100644 --- a/src/core/types/elements.ts +++ b/src/core/types/elements.ts @@ -133,6 +133,6 @@ export type ElementsNames = | 'tbxOpportunityNumber' | 'radioInsuranceOPF'; -export type TElements = { - [elementName in ElementsNames]?: any; +export type TElements = { + [elementName in ElementsNames]?: T; }; diff --git a/src/core/types/stores.ts b/src/core/types/stores.ts index ea4135b..aac30b9 100644 --- a/src/core/types/stores.ts +++ b/src/core/types/stores.ts @@ -3,10 +3,11 @@ import { TElements, ElementsNames } from './elements'; import { TStatuses, Status } from './statuses'; export interface ICalculationStore { - values: TValues; - options: TElements; statuses: TStatuses; - filters: any; + validations: TElements; + values: TValues; + options: TElements; + filters: TElements; getValue: (sourceValueName: ValuesNames) => any; getStatus: (elementName: ElementsNames) => Status;