709 lines
18 KiB
JavaScript
709 lines
18 KiB
JavaScript
import React from "react";
|
||
import { SpinnerCircular } from "spinners-react";
|
||
import moment from "moment";
|
||
import pluralize from 'pluralize-ru';
|
||
import numeral from "numeral";
|
||
|
||
import DateInput from "../../../../components/DatePicker";
|
||
|
||
import { getContractGraphicChangeOptions, getContractGraphicChangeCalculate } from "../../../../../actions";
|
||
|
||
class PaymentDate extends React.Component
|
||
{
|
||
constructor(props)
|
||
{
|
||
super(props);
|
||
this.state = {
|
||
value: null,
|
||
min: null,
|
||
max: null,
|
||
}
|
||
}
|
||
|
||
componentDidMount()
|
||
{
|
||
const { option, onOption } = this.props;
|
||
|
||
this.setState({
|
||
value: moment(option.value).toDate(),
|
||
min: moment(option.from).toDate(),
|
||
max: moment(option.to).toDate(),
|
||
}, () =>
|
||
{
|
||
onOption(this.state.value);
|
||
});
|
||
}
|
||
|
||
_handle_onChange = (value) =>
|
||
{
|
||
const { onOption } = this.props;
|
||
|
||
this.setState({ value }, () =>
|
||
{
|
||
onOption(value);
|
||
});
|
||
}
|
||
|
||
render()
|
||
{
|
||
const { option } = this.props;
|
||
const { value, min, max } = this.state;
|
||
|
||
return (
|
||
<div className="form_field">
|
||
<label>Дата платежа</label>
|
||
<DateInput
|
||
placeholder=""
|
||
value={ value }
|
||
min={ min }
|
||
max={ max }
|
||
id={"date_to"}
|
||
onChange={ this._handle_onChange }
|
||
disabled={ option.disable ? true : false }
|
||
plain={ true }
|
||
/>
|
||
</div>
|
||
)
|
||
}
|
||
}
|
||
|
||
class FixLastPayment extends React.Component
|
||
{
|
||
constructor(props)
|
||
{
|
||
super(props);
|
||
this.state = {
|
||
value: false,
|
||
};
|
||
}
|
||
|
||
componentDidMount()
|
||
{
|
||
const { option, onOption } = this.props;
|
||
|
||
this.setState({
|
||
value: option.value,
|
||
}, () =>
|
||
{
|
||
onOption(this.state.value);
|
||
});
|
||
}
|
||
|
||
_handle_onChange = () =>
|
||
{
|
||
const { onOption } = this.props;
|
||
|
||
this.setState({ value: this.state.value ? false : true }, () =>
|
||
{
|
||
onOption(this.state.value);
|
||
});
|
||
}
|
||
|
||
render()
|
||
{
|
||
const { option } = this.props;
|
||
const { value } = this.state;
|
||
|
||
return (
|
||
<div className="form_field">
|
||
<input type="checkbox" hidden id="fix_pay" name="fix_pay" checked={ value } disabled={ option.disable ? true : false } onChange={ this._handle_onChange } style={ option.disable ? { opacity: 0.5 } : {} } />
|
||
<label htmlFor="fix_pay" style={ option.disable ? { opacity: 0.5 } : {} }>
|
||
Фиксировать последний платеж
|
||
</label>
|
||
{ option.information !== undefined && option.information !== null && (
|
||
<div className="help_tooltip">
|
||
<div className="help_icon">
|
||
<svg width={ 24 } height={ 24 } fill="none" xmlns="http://www.w3.org/2000/svg">
|
||
<path d="M12 21a9 9 0 1 0 0-18 9 9 0 0 0 0 18Z" stroke="#8E94A7" strokeWidth={ 2 } strokeLinecap="round" strokeLinejoin="round" />
|
||
<path d="M11.25 11.25H12v5.25h.75" stroke="#8E94A7" strokeWidth={ 2 } strokeLinecap="round" strokeLinejoin="round" />
|
||
<path d="M12 9a1.125 1.125 0 1 0 0-2.25A1.125 1.125 0 0 0 12 9Z" fill="#8E94A7" />
|
||
</svg>
|
||
</div>
|
||
<div className="help_content ">
|
||
{" "}
|
||
{/* opened */}
|
||
<div>
|
||
<p dangerouslySetInnerHTML={{ __html: option.information }}/>
|
||
<p className="button">Закрыть</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
) }
|
||
</div>
|
||
)
|
||
}
|
||
}
|
||
|
||
class DateOffestType extends React.Component
|
||
{
|
||
constructor(props)
|
||
{
|
||
super(props);
|
||
this.state = {
|
||
value: null,
|
||
}
|
||
}
|
||
|
||
componentDidMount()
|
||
{
|
||
const { option, onOption } = this.props;
|
||
|
||
this.setState({
|
||
value: parseInt(option.value, 10),
|
||
}, () =>
|
||
{
|
||
onOption(this.state.value);
|
||
});
|
||
}
|
||
|
||
_handle_onChange = (value) =>
|
||
{
|
||
const { onOption } = this.props;
|
||
|
||
this.setState({ value: parseInt(value, 10) }, () =>
|
||
{
|
||
onOption(this.state.value);
|
||
});
|
||
}
|
||
|
||
render()
|
||
{
|
||
const { option } = this.props;
|
||
const { value } = this.state;
|
||
|
||
return (
|
||
<div className="form_field">
|
||
<label>Тип каникул</label>
|
||
<div className="form_field">
|
||
{ (!option.disable || (option.disable && value === 100000001)) && (
|
||
<>
|
||
<input type="radio" hidden id="weeekend_type_1" name="weeekend_type" checked={ value === 100000001 ? true : false } disabled={ option.disable ? true : false } onChange={ () => this._handle_onChange(100000001) }/>
|
||
<label htmlFor="weeekend_type_1">С увеличением срока</label>
|
||
</>
|
||
) }
|
||
</div>
|
||
<div className="form_field">
|
||
{ (!option.disable || (option.disable && value === 100000000)) && (
|
||
<>
|
||
<input type="radio" hidden id="weeekend_type_2" name="weeekend_type" checked={ value === 100000000 ? true : false } disabled={ option.disable ? true : false } onChange={ () => this._handle_onChange(100000000) }/>
|
||
<label htmlFor="weeekend_type_2">Без изменения срока</label>
|
||
</>
|
||
) }
|
||
</div>
|
||
</div>
|
||
)
|
||
}
|
||
}
|
||
|
||
class PeriodSelector extends React.Component
|
||
{
|
||
constructor(props)
|
||
{
|
||
super(props);
|
||
this.state = {
|
||
value: null,
|
||
periods: [],
|
||
}
|
||
}
|
||
|
||
componentDidMount()
|
||
{
|
||
const { option, onOption } = this.props;
|
||
const periods = [];
|
||
|
||
if(option.min !== undefined && option.min !== null)
|
||
{
|
||
for(let i = parseInt(option.min, 10); i <= parseInt(option.max, 10); i++)
|
||
{
|
||
periods.push(i);
|
||
}
|
||
|
||
this.setState({
|
||
value: periods[0], periods
|
||
}, () =>
|
||
{
|
||
onOption(this.state.value);
|
||
});
|
||
}
|
||
}
|
||
|
||
_handle_onChange = (event) =>
|
||
{
|
||
const { onOption } = this.props;
|
||
|
||
this.setState({ value: parseInt(event.target.value, 10) }, () =>
|
||
{
|
||
onOption(this.state.value);
|
||
});
|
||
}
|
||
|
||
render()
|
||
{
|
||
const { option } = this.props;
|
||
const { value, periods } = this.state;
|
||
|
||
if(value !== null)
|
||
{
|
||
return (
|
||
<div className="form_field" style={ option.disable ? { opacity: 0.5 } : {} }>
|
||
<label>Увеличить график на</label>
|
||
<select value={ value } onChange={ this._handle_onChange } disabled={ option.disable ? true : false }>
|
||
{ periods.map((period, index) => (
|
||
<option key={ index } value={ period }>{ index + 1 } { pluralize( index + 1, 'месяца', 'месяц', 'месяца', 'месяцев') } ({ period } { pluralize( period, 'платежа', 'платеж', 'платежа', 'платежей') })</option>
|
||
)) }
|
||
</select>
|
||
</div>
|
||
)
|
||
}
|
||
|
||
return null;
|
||
}
|
||
}
|
||
|
||
class SumSelector extends React.Component
|
||
{
|
||
constructor(props)
|
||
{
|
||
super(props);
|
||
this.state = {
|
||
value: "",
|
||
min: null,
|
||
max: null,
|
||
}
|
||
}
|
||
|
||
componentDidMount()
|
||
{
|
||
const { option, onOption } = this.props;
|
||
|
||
this.setState({
|
||
value: option.value !== null ? option.value : option.min,
|
||
min: option.min,
|
||
max: option.max,
|
||
}, () =>
|
||
{
|
||
onOption(this.state.value, false);
|
||
});
|
||
}
|
||
|
||
_handle_onChange = (event) =>
|
||
{
|
||
const { onOption } = this.props;
|
||
const { min, max } = this.state;
|
||
|
||
const value = parseFloat(event.target.value.replace(/[^\d]/mg, ''));
|
||
if(value >= min && value <= max && !isNaN(value))
|
||
{
|
||
this.setState({ value: value }, () =>
|
||
{
|
||
onOption(this.state.value, false);
|
||
});
|
||
}
|
||
else
|
||
{
|
||
onOption(this.state.value, true);
|
||
}
|
||
}
|
||
|
||
render()
|
||
{
|
||
const { option } = this.props;
|
||
const { value, min, max } = this.state;
|
||
|
||
return (
|
||
<div className="form_field">
|
||
<label style={ option.disable ? { opacity: 0.5 } : {} }>Увеличить платеж на (ЧДП)</label>
|
||
<div className="input_with_notes" style={ option.disable ? { opacity: 0.5 } : {} }>
|
||
<input type="number" placeholder="Укажите сумму" defaultValue={ value } disabled={ option.disable ? true : false } onChange={ this._handle_onChange }/>
|
||
<span>от { numeral(min).format(' ., ') } ₽</span>
|
||
<span>до { numeral(max).format(' ., ') } ₽</span>
|
||
</div>
|
||
{ option.information !== undefined && option.information !== null && (
|
||
<div className="help_tooltip">
|
||
<div className="help_icon">
|
||
<svg width={ 24 } height={ 24 } fill="none" xmlns="http://www.w3.org/2000/svg">
|
||
<path d="M12 21a9 9 0 1 0 0-18 9 9 0 0 0 0 18Z" stroke="#8E94A7" strokeWidth={ 2 } strokeLinecap="round" strokeLinejoin="round" />
|
||
<path d="M11.25 11.25H12v5.25h.75" stroke="#8E94A7" strokeWidth={ 2 } strokeLinecap="round" strokeLinejoin="round" />
|
||
<path d="M12 9a1.125 1.125 0 1 0 0-2.25A1.125 1.125 0 0 0 12 9Z" fill="#8E94A7" />
|
||
</svg>
|
||
</div>
|
||
<div className="help_content ">
|
||
{" "}
|
||
{/* opened */}
|
||
<div>
|
||
<p dangerouslySetInnerHTML={{ __html: option.information }}/>
|
||
<p className="button">Закрыть</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
) }
|
||
</div>
|
||
)
|
||
}
|
||
}
|
||
|
||
class InsurancePriceSelector extends React.Component
|
||
{
|
||
constructor(props)
|
||
{
|
||
super(props);
|
||
this.state = {
|
||
value: "",
|
||
min: null,
|
||
max: null,
|
||
}
|
||
}
|
||
|
||
componentDidMount()
|
||
{
|
||
const { option, onOption } = this.props;
|
||
|
||
this.setState({
|
||
value: option.min,
|
||
min: option.min,
|
||
max: option.max,
|
||
}, () =>
|
||
{
|
||
onOption(this.state.value, false);
|
||
});
|
||
}
|
||
|
||
_handle_onChange = (event) =>
|
||
{
|
||
const { option, onOption } = this.props;
|
||
const { min, max } = this.state;
|
||
|
||
//if(option.disable)
|
||
//{
|
||
// console.log("////", option.disable);
|
||
// this.setState({ value: this.state.value });
|
||
//}
|
||
//else
|
||
//{
|
||
const value = parseFloat(event.target.value.replace(/[^\d]/mg, ''));
|
||
if(value >= min && value <= max && !isNaN(value))
|
||
{
|
||
this.setState({ value: value }, () =>
|
||
{
|
||
onOption(this.state.value, false);
|
||
});
|
||
}
|
||
else
|
||
{
|
||
onOption(this.state.value, true);
|
||
}
|
||
//}
|
||
}
|
||
|
||
render()
|
||
{
|
||
const { option } = this.props;
|
||
const { value, min, max } = this.state;
|
||
|
||
return (
|
||
<div className="form_field">
|
||
<label>Сумма пролонгации</label>
|
||
<div className="input_with_notes">
|
||
{ option.disable ? (
|
||
<>{ numeral(value).format(' ., ') } ₽</>
|
||
) : (
|
||
<>
|
||
<input type="number" placeholder="Укажите сумму" defaultValue={ value } disabled={ option.disable ? true : false } onChange={ this._handle_onChange }/>
|
||
<span>от { numeral(min).format(' ., ') } ₽</span>
|
||
<span>до { numeral(max).format(' ., ') } ₽</span>
|
||
</>
|
||
) }
|
||
</div>
|
||
{ option.information !== undefined && option.information !== null && (
|
||
<div className="help_tooltip">
|
||
<div className="help_icon">
|
||
<svg width={ 24 } height={ 24 } fill="none" xmlns="http://www.w3.org/2000/svg">
|
||
<path d="M12 21a9 9 0 1 0 0-18 9 9 0 0 0 0 18Z" stroke="#8E94A7" strokeWidth={ 2 } strokeLinecap="round" strokeLinejoin="round" />
|
||
<path d="M11.25 11.25H12v5.25h.75" stroke="#8E94A7" strokeWidth={ 2 } strokeLinecap="round" strokeLinejoin="round" />
|
||
<path d="M12 9a1.125 1.125 0 1 0 0-2.25A1.125 1.125 0 0 0 12 9Z" fill="#8E94A7" />
|
||
</svg>
|
||
</div>
|
||
<div className="help_content ">
|
||
{" "}
|
||
{/* opened */}
|
||
<div>
|
||
<p dangerouslySetInnerHTML={{ __html: option.information }}/>
|
||
<p className="button">Закрыть</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
) }
|
||
</div>
|
||
)
|
||
}
|
||
}
|
||
|
||
class InsuranceDateFromSelector extends React.Component
|
||
{
|
||
constructor(props)
|
||
{
|
||
super(props);
|
||
this.state = {
|
||
value: null,
|
||
min: null,
|
||
max: null,
|
||
}
|
||
}
|
||
|
||
componentDidMount()
|
||
{
|
||
const { option, onOption } = this.props;
|
||
|
||
this.setState({
|
||
value: moment(option.value !== null ? option.value : option.from).toDate(),
|
||
min: moment(option.from).toDate(),
|
||
max: moment(option.to).toDate(),
|
||
}, () =>
|
||
{
|
||
onOption(this.state.value);
|
||
});
|
||
}
|
||
|
||
_handle_onChange = (value) =>
|
||
{
|
||
const { onOption } = this.props;
|
||
|
||
this.setState({ value }, () =>
|
||
{
|
||
onOption(value);
|
||
});
|
||
}
|
||
|
||
render()
|
||
{
|
||
const { option } = this.props;
|
||
const { value, min, max } = this.state;
|
||
|
||
return (
|
||
<div className="form_field">
|
||
<label>Дата начала пролонгации</label>
|
||
<DateInput
|
||
placeholder=""
|
||
value={ value }
|
||
min={ min }
|
||
max={ max }
|
||
id={"date_to"}
|
||
onChange={ this._handle_onChange }
|
||
disabled={ option.disable ? true : false }
|
||
plain={ true }
|
||
/>
|
||
</div>
|
||
)
|
||
}
|
||
}
|
||
|
||
export default class Options extends React.Component
|
||
{
|
||
constructor(props)
|
||
{
|
||
super(props);
|
||
this.state = {
|
||
loading: true,
|
||
sending: false,
|
||
date: null,
|
||
car: null,
|
||
contract_date: null,
|
||
agreement: null,
|
||
rules: null,
|
||
number_paydate: null,
|
||
period_new: null,
|
||
fix_last_payment_available: false,
|
||
date_offset_type: null,
|
||
sum: null,
|
||
insurance_price_result: null,
|
||
datefrom: null,
|
||
errors: {},
|
||
};
|
||
}
|
||
|
||
componentDidMount()
|
||
{
|
||
const { dispatch, number, variants } = this.props;
|
||
|
||
const varianst_for_options = {};
|
||
for(let i in variants.types)
|
||
{
|
||
if(variants.types[i].value)
|
||
{
|
||
varianst_for_options[variants.types[i].name] = true;
|
||
}
|
||
}
|
||
|
||
getContractGraphicChangeOptions({ dispatch, number, variants: varianst_for_options })
|
||
.then(() =>
|
||
{
|
||
this.setState({ loading: false });
|
||
})
|
||
.catch(() =>
|
||
{
|
||
|
||
});
|
||
}
|
||
|
||
_handle_onBack = (event) =>
|
||
{
|
||
event.preventDefault();
|
||
this.props.onVariants();
|
||
}
|
||
|
||
_handle_onCalculate = (event) =>
|
||
{
|
||
const { sending, number_paydate, period_new, fix_last_payment_available, date_offset_type, sum, insurance_price_result, datefrom, } = this.state;
|
||
const { number, options, variants, onCalculate } = this.props;
|
||
|
||
event.preventDefault();
|
||
console.log(this.props);
|
||
|
||
const selected = {
|
||
number_planpayment: options.number_planpayment.value,
|
||
};
|
||
|
||
if(number_paydate !== null) { selected.number_paydate = moment(number_paydate).format(); }
|
||
if(period_new !== null) { selected.period_new = period_new; }
|
||
//if(fix_last_payment_available !== null) { selected.fix_last_payment_available = fix_last_payment_available; }
|
||
if(date_offset_type !== null) { selected.date_offset_type = date_offset_type; }
|
||
if(sum !== null) { selected.sum = sum; }
|
||
if(insurance_price_result !== null) { selected.insurance_price_result = insurance_price_result; }
|
||
//if(early_redemption_change !== null) { selected.early_redemption_change = early_redemption_change; }
|
||
if(datefrom !== null) { selected.datefrom = moment(datefrom).format(); }
|
||
|
||
if(!sending)
|
||
{
|
||
const v = {};
|
||
for(let i in variants.types) { v[ variants.types[i].name ] = variants.types[i].value; }
|
||
const payload = {
|
||
...{ contract_number: number },
|
||
...v,
|
||
...selected
|
||
};
|
||
|
||
this.setState({ sending: true, }, () =>
|
||
{
|
||
getContractGraphicChangeCalculate(payload)
|
||
.then((calculation) =>
|
||
{
|
||
onCalculate(calculation.addcontract_number);
|
||
})
|
||
.catch(() =>
|
||
{
|
||
this.setState({ sending: false, }, () =>
|
||
{
|
||
alert("К сожаление при расчете возникла ошибка.");
|
||
});
|
||
});
|
||
});
|
||
}
|
||
}
|
||
|
||
_handle_onPaymentDateChange = (date) =>
|
||
{
|
||
this.setState({ number_paydate: date });
|
||
}
|
||
|
||
_handle_onFixLastPaymentChange = (value) =>
|
||
{
|
||
this.setState({ fix_last_payment_available: value });
|
||
}
|
||
|
||
_handle_onDateOffsetTypeChange = (value) =>
|
||
{
|
||
this.setState({ date_offset_type: value });
|
||
}
|
||
|
||
_handle_onPeriodChange = (value) =>
|
||
{
|
||
this.setState({ period_new: value });
|
||
}
|
||
|
||
_handle_onSumChange = (value, error) =>
|
||
{
|
||
const { errors } = this.state;
|
||
|
||
if(error) { errors['sum'] = true; } else { delete errors['sum']; }
|
||
|
||
this.setState({ sum: value, errors });
|
||
}
|
||
|
||
_handle_onInsurancePriceChange = (value, error) =>
|
||
{
|
||
const { errors } = this.state;
|
||
|
||
if(error) { errors['insurance_price_result'] = true; } else { delete errors['insurance_price_result']; }
|
||
|
||
this.setState({ insurance_price_result: value, errors });
|
||
}
|
||
|
||
_handle_onInsuranceDateFromChange = (date) =>
|
||
{
|
||
this.setState({ datefrom: date });
|
||
}
|
||
|
||
_checkAllowCalculate = () =>
|
||
{
|
||
const { errors } = this.state;
|
||
|
||
for(let i in errors)
|
||
{
|
||
if(errors[i])
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
render()
|
||
{
|
||
const { loading, sending, } = this.state;
|
||
const { variants, options } = this.props;
|
||
|
||
return (
|
||
<div className="block">
|
||
<p className="title">Параметры опций изменений графика платежей</p>
|
||
{ loading ? (
|
||
<div style={{ position: "absolute", left: "50%", top: "50%" }}>
|
||
<SpinnerCircular size={ 90 } thickness={ 51 } speed={ 100 } color="rgba(28, 1, 169, 1)" secondaryColor="rgba(236, 239, 244, 1)" style={{ marginTop: "-45px", marginLeft: "-45px", }}/>
|
||
</div>
|
||
) : (
|
||
<form className="calc">
|
||
{ options !== undefined && options !== null && options.number_paydate !== undefined && options.number_paydate !== null && options.number_paydate.visible && (
|
||
<PaymentDate option={ options.number_paydate } onOption={ this._handle_onPaymentDateChange } />
|
||
) }
|
||
{ options !== undefined && options !== null && options.fix_last_payment_available !== undefined && options.fix_last_payment_available !== null && options.fix_last_payment_available.visible && (
|
||
<FixLastPayment option={ options.fix_last_payment_available } onOption={ this._handle_onFixLastPaymentChange } />
|
||
) }
|
||
{ options !== undefined && options !== null && options.date_offset_type !== undefined && options.date_offset_type !== null && options.date_offset_type.visible && (
|
||
<DateOffestType option={ options.date_offset_type } onOption={ this._handle_onDateOffsetTypeChange } />
|
||
) }
|
||
{ options !== undefined && options !== null && options.period_new !== undefined && options.period_new !== null && options.period_new.visible && (
|
||
<PeriodSelector option={ options.period_new } onOption={ this._handle_onPeriodChange } />
|
||
) }
|
||
{ options !== undefined && options !== null && options.sum !== undefined && options.sum !== null && options.sum.visible && (
|
||
<SumSelector option={ options.sum } onOption={ this._handle_onSumChange } />
|
||
) }
|
||
{ options !== undefined && options !== null && options.insurance_price_result !== undefined && options.insurance_price_result !== null && options.insurance_price_result.visible && (
|
||
<InsurancePriceSelector option={ options.insurance_price_result } onOption={ this._handle_onInsurancePriceChange } />
|
||
) }
|
||
{ options !== undefined && options !== null && options.datefrom !== undefined && options.datefrom !== null && options.datefrom.visible && (
|
||
<InsuranceDateFromSelector option={ options.datefrom } onOption={ this._handle_onInsuranceDateFromChange } />
|
||
) }
|
||
<div className="btn_group">
|
||
<button className="button button-gray" onClick={ this._handle_onBack }>Назад</button>
|
||
<button className="button button-blue" onClick={ this._handle_onCalculate } disabled={ this._checkAllowCalculate() ? false : true } style={{ minWidth: 350 }}>
|
||
{ sending ? (
|
||
<SpinnerCircular size={24} thickness={100} speed={100} color="rgba(255, 255, 255, 1)" secondaryColor="rgba(255, 255, 255, 0.5)" style={{ marginTop: "0px" }}/>
|
||
) : ( "Рассчитать график" ) }
|
||
</button>
|
||
</div>
|
||
</form>
|
||
) }
|
||
</div>
|
||
);
|
||
}
|
||
} |