389 lines
11 KiB
JavaScript
389 lines
11 KiB
JavaScript
import React from "react";
|
||
import Head from "next/head";
|
||
import Image from "next/image";
|
||
import { connect } from "react-redux";
|
||
import { withRouter } from "next/router";
|
||
import moment from "moment";
|
||
import { SpinnerCircular } from "spinners-react";
|
||
import Dropzone from 'react-dropzone';
|
||
import Select from 'react-select'
|
||
|
||
import { reduxWrapper } from "../../store";
|
||
|
||
import Header from "../components/Header";
|
||
import Footer from "../components/Footer";
|
||
import Company from "../components/Company";
|
||
import InnerMenu from "./components/InnerMenu";
|
||
import SuccessMessage from "./components/SuccessMessage";
|
||
|
||
import {
|
||
getSupportThemes,
|
||
getContractsList,
|
||
getBitrixFile
|
||
} from "../../actions";
|
||
|
||
class TemplateFile extends React.Component
|
||
{
|
||
constructor(props)
|
||
{
|
||
super(props);
|
||
this.state = {
|
||
downloading: false
|
||
}
|
||
}
|
||
|
||
_handle_onDownloadFile = () =>
|
||
{
|
||
const { filename, url } = this.props.template;
|
||
const { downloading } = this.state;
|
||
|
||
if(!downloading)
|
||
{
|
||
this.setState({ downloading: true }, () =>
|
||
{
|
||
getBitrixFile({ url, filename })
|
||
.then(() => { this.setState({ downloading: false }); })
|
||
.catch(() => { this.setState({ downloading: false }); });
|
||
});
|
||
}
|
||
}
|
||
|
||
render()
|
||
{
|
||
const { template } = this.props;
|
||
const { downloading } = this.state;
|
||
|
||
return (
|
||
<div className="row interactive" onClick={ this._handle_onDownloadFile }>
|
||
<p className="doc_name i-pdf extension" data-format={ template.extension }>{ template.filename }<span style={{ position: "relative", color: downloading ? "#8e94a780" : "#8e94a7" }}>Скачать шаблон{ downloading ? (<SpinnerCircular size={ 20 } thickness={ 100 } speed={ 100 } color="rgba(236, 239, 244, 1)" secondaryColor="rgba(28, 1, 169, 1)" style={{ position: "absolute", right: 0, marginRight: "-26px", top: 0, }} />) : null }</span></p>
|
||
</div>
|
||
)
|
||
}
|
||
}
|
||
class FileDropzone extends React.Component
|
||
{
|
||
constructor(props)
|
||
{
|
||
super(props);
|
||
this.state = {}
|
||
}
|
||
|
||
render()
|
||
{
|
||
const { files, onAddFile, onDeleteFile } = this.props;
|
||
return (
|
||
<>
|
||
{ files.length > 0 && (
|
||
<div className="column">
|
||
<div className="column_text_block">
|
||
<p><b>Приложенные файлы</b></p>
|
||
{ files.map((file, index) => (
|
||
<p key={ index }>{ file.name } <small style={{ color: "red", textDecoration: "underline", cursor: "pointer" }} onClick={ () => onDeleteFile(file.name) }>[ удалить ]</small></p>
|
||
)) }
|
||
</div>
|
||
</div>
|
||
) }
|
||
<Dropzone onDrop={ (acceptedFiles) => onAddFile(acceptedFiles) }>
|
||
{ ({getRootProps, getInputProps}) => (
|
||
<div className="file_upload dropzone" { ...getRootProps() }>
|
||
<div className="files"></div>
|
||
<div>
|
||
<p data-sm-text="Выберите файлы">
|
||
<span>Перенесите файлы на экран для быстрой загрузки или выберите файл с компьютера </span>
|
||
</p>
|
||
<label htmlFor="" className="button button-blue">Загрузить файл</label>
|
||
</div>
|
||
<input { ...getInputProps() } />
|
||
</div>
|
||
) }
|
||
</Dropzone>
|
||
</>
|
||
)
|
||
}
|
||
}
|
||
|
||
class SupportRequestPage extends React.Component
|
||
{
|
||
constructor(props) {
|
||
super(props);
|
||
this.state = {
|
||
loading: false,
|
||
contracts: null,
|
||
themes: null,
|
||
name: "",
|
||
phone: "",
|
||
email: "",
|
||
question: "",
|
||
selected_contracts: [],
|
||
file: null,
|
||
files: [],
|
||
opened_theme: 0,
|
||
opened_question: 0,
|
||
success: false,
|
||
};
|
||
}
|
||
|
||
static getDerivedStateFromProps(nextProps, prevState)
|
||
{
|
||
return {
|
||
contracts: nextProps.contracts,
|
||
themes: nextProps.themes,
|
||
};
|
||
}
|
||
|
||
componentDidMount()
|
||
{
|
||
console.log("CDM", "SupportRequestPage", this.state);
|
||
|
||
if (!this.state.loading)
|
||
{
|
||
this.setState({ loading: true }, () =>
|
||
{
|
||
Promise.all([
|
||
getContractsList({ dispatch: this.props.dispatch, all: true }),
|
||
getSupportThemes({ dispatch: this.props.dispatch })
|
||
])
|
||
.then(() =>
|
||
{
|
||
this.setState({ loading: false });
|
||
})
|
||
.catch(() => {});
|
||
});
|
||
}
|
||
}
|
||
|
||
componentDidUpdate(prevProps, prevState)
|
||
{
|
||
}
|
||
|
||
_handle_onBack = () =>
|
||
{
|
||
this.props.router.push('/support/faq/');
|
||
}
|
||
|
||
_handle_onChangeTheme = (index) =>
|
||
{
|
||
this.setState({ opened_theme: index, opened_question: 0 });
|
||
}
|
||
|
||
_handle_onSendAppeal = () =>
|
||
{
|
||
const { name, phone, email, question, selected_contracts, } = this.state;
|
||
|
||
const appeal = {
|
||
phone: phone,
|
||
email: email,
|
||
description: question,
|
||
contract_numbers: selected_contracts
|
||
}
|
||
}
|
||
|
||
_handle_onContract = (options) =>
|
||
{
|
||
const selected_contracts = [];
|
||
for(let i in options)
|
||
{
|
||
selected_contracts.push(options[i].value);
|
||
this.setState({ selected_contracts });
|
||
}
|
||
}
|
||
|
||
_handle_onAddFile = (files) =>
|
||
{
|
||
console.log("_handle_onAdd", files);
|
||
|
||
const existed_files = [ ...this.state.files ];
|
||
for(let nf in files)
|
||
{
|
||
let e = false;
|
||
for(let ef in this.state.files)
|
||
{
|
||
if(this.state.files[ef].name === files[nf].name) { e = true; }
|
||
}
|
||
|
||
if(!e)
|
||
{
|
||
existed_files.push(files[nf]);
|
||
}
|
||
}
|
||
|
||
this.setState({ files: existed_files });
|
||
}
|
||
|
||
_handle_onDeleteFile = (file_name) =>
|
||
{
|
||
const files = [];
|
||
for(let i in this.state.files)
|
||
{
|
||
if(this.state.files[i].name !== file_name)
|
||
{
|
||
files.push(this.state.files[i]);
|
||
}
|
||
}
|
||
|
||
this.setState({ files });
|
||
}
|
||
|
||
_renderForm = () =>
|
||
{
|
||
const { loading, contracts, themes, name, phone, email, question, file, files, opened_theme, opened_question } = this.state;
|
||
|
||
const contracts_list = [];
|
||
for(let i in contracts)
|
||
{
|
||
contracts_list.push({
|
||
value: contracts[i].number, label: contracts[i].number
|
||
});
|
||
}
|
||
|
||
return (
|
||
<form>
|
||
<div className="form_field">
|
||
<Select
|
||
options={ contracts_list }
|
||
isMulti
|
||
className="custom-multi-select form_field"
|
||
classNamePrefix="custom-select"
|
||
placeholder="Выберите договоры"
|
||
onChange={ this._handle_onContract }
|
||
/>
|
||
</div>
|
||
<div className="form_field">
|
||
<input
|
||
type="text"
|
||
name="name"
|
||
placeholder="Ваше ФИО"
|
||
/>
|
||
</div>
|
||
<div className="form_field">
|
||
<input type="tel" name="name" placeholder="Телефон" />
|
||
</div>
|
||
<div className="form_field">
|
||
<input type="email" name="name" placeholder="Email" />
|
||
</div>
|
||
<div className="form_field">
|
||
<textarea placeholder="Введите текст запроса" style={{ resize: "none" }}></textarea>
|
||
</div>
|
||
<FileDropzone files={ files } onAddFile={ this._handle_onAddFile } onDeleteFile={ this._handle_onDeleteFile }/>
|
||
</form>
|
||
)
|
||
}
|
||
|
||
render()
|
||
{
|
||
const { number } = this.props;
|
||
const { loading, success, themes, opened_theme, opened_question } = this.state;
|
||
|
||
const procedure = themes !== undefined && themes !== null ? themes[opened_theme].questions[opened_question] : undefined;
|
||
|
||
return (
|
||
<React.Fragment>
|
||
<Head>
|
||
<title>ЛК Эволюция автолизинга</title>
|
||
<meta name="description" content="ЛК Эволюция автолизинга" />
|
||
</Head>
|
||
<Header { ...this.props } />
|
||
<main>
|
||
<section>
|
||
<div className="clear"></div>
|
||
<div className="container">
|
||
<div className="title_wrapper">
|
||
<div className="left" style={{ alignItems: "center", flexWrap: "wrap" }}>
|
||
<button className="back" onClick={ this._handle_onBack }>Назад</button>
|
||
<h1 className="section_title">Новое обращение</h1>
|
||
</div>
|
||
<Company { ...this.props }/>
|
||
</div>
|
||
<div className="aside_container about">
|
||
{ loading ? (
|
||
<div className="container" style={{ display: "flex", alignItems: "center", justifyContent: "center", }}>
|
||
<SpinnerCircular size={ 90 } thickness={ 51 } speed={ 100 } color="rgba(28, 1, 169, 1)" secondaryColor="rgba(236, 239, 244, 1)" />
|
||
</div>
|
||
) : (
|
||
<>
|
||
{ success ? (
|
||
<SuccessMessage/>
|
||
) : (
|
||
<article className="full">
|
||
<div className="new_appeal">
|
||
<div className="column">
|
||
<div className="dropdown_blocks_list appeal_list visible">
|
||
{ themes !== undefined && themes !== null && themes.map((theme, theme_index) =>
|
||
(
|
||
<React.Fragment key={ `theme_${ theme_index }` } >
|
||
<div className={ `appeal_item dropdown_block ${ theme_index === opened_theme && "open" }` } style={ theme_index === opened_theme ? { backgroundColor: "unset"} : {} } onClick={ () => this._handle_onChangeTheme(theme_index) }>
|
||
<div className="block_header">
|
||
<p style={{ fontWeight: "bold" }}>{ theme.name }</p>
|
||
<button className="rotate"></button>
|
||
</div>
|
||
</div>
|
||
{ theme_index === opened_theme && theme.questions.map((question, question_index) => (
|
||
<div key={ `question_${ question_index }` } className={ `appeal_item dropdown_block ${ question_index === opened_question && "open" }` } style={{ paddingLeft: "20px" }} onClick={ () => this.setState({ opened_question: question_index }) }>
|
||
<div className="block_header">
|
||
<p>{ question.title }</p>
|
||
<button className="rotate"></button>
|
||
</div>
|
||
</div>
|
||
) )}
|
||
</React.Fragment>
|
||
)) }
|
||
</div>
|
||
</div>
|
||
{ themes !== undefined && themes !== null && (
|
||
<div className="column">
|
||
<div className="column_text_block">
|
||
<p><b>Процедура</b></p>
|
||
<p dangerouslySetInnerHTML={{ __html: procedure.answer }}/>
|
||
</div>
|
||
{ procedure.documents !== null && (
|
||
<div className="column_text_block">
|
||
<p><b>Документы</b></p>
|
||
<p dangerouslySetInnerHTML={{ __html: procedure.documents }}/>
|
||
</div>
|
||
) }
|
||
{ procedure.templates !== null && (
|
||
<div className="column_text_block">
|
||
<p><b>Документы</b></p>
|
||
<div className="dosc_list medium-icon">
|
||
{ procedure.templates.map((template, index) => (<TemplateFile key={ `template_${ index }` } template={ template } />)) }
|
||
</div>
|
||
</div>
|
||
) }
|
||
{ this._renderForm() }
|
||
</div>
|
||
) }
|
||
</div>
|
||
</article>
|
||
) }
|
||
</>
|
||
) }
|
||
</div>
|
||
</div>
|
||
</section>
|
||
</main>
|
||
<Footer />
|
||
</React.Fragment>
|
||
);
|
||
}
|
||
}
|
||
|
||
function mapStateToProps(state, ownProps)
|
||
{
|
||
return {
|
||
contracts: state.contracts.list,
|
||
themes: state.support.themes,
|
||
appeal: state.support.appeal,
|
||
};
|
||
}
|
||
|
||
export const getServerSideProps = reduxWrapper.getServerSideProps(
|
||
(store) =>
|
||
async ({ req, res, query }) => {
|
||
return {
|
||
props: {
|
||
},
|
||
};
|
||
}
|
||
);
|
||
|
||
export default withRouter(connect(mapStateToProps)(SupportRequestPage)); |