rating fixes, deals markup fixes

This commit is contained in:
merelendor 2023-08-28 10:08:19 +03:00
parent 8b5fcf0e6f
commit 41a4d824e8
21 changed files with 1113 additions and 734 deletions

49
actions/dealsActions.js Normal file
View File

@ -0,0 +1,49 @@
import axios from 'axios';
import { Cookies } from 'react-cookie';
import Router from 'next/router';
import moment from 'moment';
import { nSQL } from "@nano-sql/core";
/*
/lk/ConsiderationOpportunity/quote
[{
"quote_number": "582189",
"price": 5490000,
"first_payment_perc": 30,
"first_payment_rub": 1647000,
"brand_name": "Volkswagen",
"model_name": "Touareg",
"object_count": 1,
}, {
"quote_number": "580008",
"price": 5341770,
"first_payment_perc": 30,
"first_payment_rub": 1647000,
"brand_name": "Volkswagen",
"model_name": "Touareg",
"object_count": 1,
}]
*/
export const getDeals = ({ dispatch }) =>
{
//console.log("ACTION", "support", "getAppeals()", `${ process.env.NEXT_PUBLIC_SELF_API_HOST }/api/support/appeals`);
return new Promise((resolve, reject) =>
{
axios.post(`${ process.env.NEXT_PUBLIC_SELF_API_HOST }/api/deals/list`, {}, {
withCredentials: true,
})
.then((response) =>
{
//console.log("ACTION", "support", "getAppeals()", "response", response.data);
dispatch({ type: actionTypes.DEALS, data: {} });
resolve();
})
.catch((error) =>
{
console.error(error);
reject();
});
});
}

View File

@ -0,0 +1,45 @@
import axios from 'axios';
if(process.browser)
{
FormData.prototype.appendObject = function(obj, namespace)
{
let keyName;
for (var key in obj)
{
if (obj.hasOwnProperty(key))
{
keyName = [namespace, '[', key, ']'].join('');
this.append(keyName, obj[key]);
}
}
};
}
export const sendFeedback = (feedback) =>
{
//{ name, phone, email, company, recaptcha_token }
return new Promise((resolve, reject) =>
{
axios.post(`${ process.env.NEXT_PUBLIC_SELF_API_HOST }/api/feedbacks/add`, feedback,
{
withCredentials: true,
})
.then((response) =>
{
if(response.data.status === "success")
{
resolve();
}
else
{
reject(response.data);
}
})
.catch((error) =>
{
console.error(error);
reject();
});
});
}

View File

@ -13,3 +13,4 @@ export * from './supportActions';
export * from './adminActions'; export * from './adminActions';
export * from './suggestsActions'; export * from './suggestsActions';
export * from './questionnaireActions'; export * from './questionnaireActions';
export * from './feedbackActions';

View File

@ -0,0 +1,539 @@
import React from "react"
import { connect } from "react-redux"
class SingleDeal extends React.Component
{
constructor(props)
{
super(props);
}
render()
{
const { close } = this.props;
return (
<div className="contractStatus_modal">
<div className="modal_header">
<p className="modal_title">Статус сделки</p>
<button className="modal_close" onClick={close}></button>
</div>
<div className="modal_body single_status">
<div className="current">
<p>Сделка 1</p>
<span></span>
<div className="status_body">
<div className="status_header">
<i className="status_1"></i>
<p>Выбор КП</p>
</div>
<div className="wrap">
<table>
<thead>
<tr>
<th></th>
<th></th>
<th>Стоимость</th>
<th>Первый платеж, р.</th>
<th>Первый платеж, %</th>
<th>Марка</th>
<th>Модель</th>
<th>Объектов лизинга</th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td>
<div className="form_field checkbox">
<input type="checkbox" name="row" id="row" checked="" onChange={ () => {} }/>
<label htmlFor="row"></label>
</div>
</td>
<td>1</td>
<td>5 600 000 р.</td>
<td>560 000 р.</td>
<td>10 %</td>
<td>Audi</td>
<td>A8</td>
<td>1</td>
<td>
<div className="dosc_list">
<div className="row">
<div className="small-icon">
<p className="doc_name i-pdf">
КП
<span>1</span>
</p>
</div>
</div>
</div>
</td>
</tr>
<tr>
<td>
<div className="form_field checkbox">
<input type="checkbox" name="row" id="row" checked="" onChange={ () => {} }/>
<label htmlFor="row"></label>
</div>
</td>
<td>1</td>
<td>5 600 000 р.</td>
<td>560 000 р.</td>
<td>10 %</td>
<td>Audi</td>
<td>A8</td>
<td>1</td>
<td>
<div className="dosc_list">
<div className="row">
<div className="small-icon">
<p className="doc_name i-pdf">
КП
<span>1</span>
</p>
</div>
</div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div>
<p>Сделка 1</p>
<span></span>
<div className="status_body">
<div className="status_header">
<i className="status_2"></i>
<p className="header">Программа финансирования</p>
</div>
<div className="wrap">
<div className="single_text">
<p>Статусный текст о том что выбирается программа финансированияи может быть по центру иконочка часиков или слева от статусного текста иконочка часиков</p>
</div>
</div>
</div>
</div>
<div>
<p>Сделка 1</p>
<span></span>
<div className="status_body">
<div className="status_header">
<i className="status_3"></i>
<p>Сборка пакета документов</p>
</div>
<div className="wrap">
<div className="message ok">
<p>Вам не требуется актуализация данных анкеты Клиента</p>
</div>
<div className="message alert">
<p>Требуется обновить данные в анкете</p>
<button className="button button-blue">Актуализировать данные</button>
</div>
<div className="message wait">
<p>Проводится проверка анкеты Вашей организации</p>
</div>
<p><b>Устав организации</b></p>
<div className="attach_file">
<label>
<input type="file" hidden onChange={ () => {} }/>
Прикрепить скан документов
</label>
</div>
<div class="message documents">
<div className="doc_list">
<div class="dosc_list medium-icon">
<div class="row">
<p class="doc_name i-pdf i-medium">123/2023 от 01.01.2023</p>
</div>
</div>
<div class="dosc_list medium-icon">
<div class="row">
<p class="doc_name i-pdf i-medium">123/2023 от 01.01.2023</p>
</div>
</div>
</div>
<p>Документы, отправленные Вами принадлежат другой организации бла бла коммент от менеджера</p>
</div>
<div className="attach_file">
<label>
<input type="file" hidden onChange={ () => {} }/>
Прикрепить ещё
</label>
</div>
<p><b>Другое название документа</b></p>
<div className="attach_file">
<label>
<input type="file" hidden onChange={ () => {} }/>
Прикрепить скан документов
</label>
</div>
</div>
</div>
</div>
<div className="">
<p>Сделка 1</p>
<span></span>
<div className="status_body">
<div className="status_header">
<i className="status_4"></i>
<p>Проверка документов</p>
</div>
<div className="wrap">
<div className="single_text">
<p>Статусный текст о том что выбирается программа финансированияи может быть по центру иконочка часиков или слева от статусного текста иконочка часиков</p>
</div>
</div>
</div>
</div>
<div>
<p>Сделка 1</p>
<span></span>
<div className="status_body">
<div className="status_header">
<i className="status_5"></i>
<p>Принятие решения по заявке</p>
</div>
<div className="wrap">
<div className="single_text">
<p>Статусный текст о том что выбирается программа финансированияи может быть по центру иконочка часиков или слева от статусного текста иконочка часиков</p>
</div>
</div>
</div>
</div>
<div>
<p>Сделка 1</p>
<span></span>
<div className="status_body">
<div className="status_header">
<i className="status_6"></i>
<p>Оформление лизинга</p>
</div>
<div className="wrap">
<div className="single_text">
<p>Статусный текст о том что выбирается программа финансированияи может быть по центру иконочка часиков или слева от статусного текста иконочка часиков</p>
</div>
</div>
</div>
</div>
<div>
<p>Сделка 1</p>
<span></span>
<div className="status_body">
<div className="status_header">
<i className="status_7"></i>
<p>Выбор типа подписания</p>
</div>
<div className="wrap">
<div className="block-column">
<div className="dropdown_block open" >
<div className="block_header default">
<p><b>Подготовлено 3 из 12</b></p>
</div>
</div>
<div className="dosc_list acts_list-checkbox medium-icon">
<div className="row">
<p className="doc_name i-doc i-medium" >
<input type="checkbox" name="" id="" checked="" onChange={ () => {} }/>
<label for="">2022_6875 от 28.06.2022</label>
</p>
</div>
</div>
<div className="block_footer_btn">
<button className="button button-blue">Подписать в ЭДО</button>
<button className="button button-blue">Подписать в бумажном виде</button>
</div>
</div>
<div className="block-column">
<div className="dropdown_block open" >
<div className="block_header default">
<p><b>К подписанию 3 из 12</b></p>
</div>
</div>
<div className="dosc_list medium-icon">
<div className="row flex-start">
<p className="doc_name i-doc i-medium" >
123/2023 от 01.01.2023
</p>
<button className="button">Перейти в ЭДО</button>
</div>
<div className="row flex-start">
<p className="doc_name i-doc i-medium" >
123/2023 от 01.01.2023
</p>
<button className="button">Скачать документ</button>
<button className="button">Загрузить подписанный экземпляр</button>
</div>
</div>
</div>
<div className="block-column">
<div className="dropdown_block open" >
<div className="block_header default">
<p><b>Подписано 3 из 12</b></p>
</div>
</div>
<div className="dosc_list medium-icon">
<div className="row">
<p className="doc_name i-doc i-medium" >
<a href="#">Скачать 129/2023 от 01.01.2023 - Ожидание оплаты</a>
</p>
</div>
</div>
</div>
<div className="block-column">
<div className="dropdown_block open">
<div className="block_header default">
<p><b>Подготовлено 3 из 12</b></p>
</div>
</div>
<div className="dosc_list medium-icon">
<div className="row">
<p className="doc_name i-doc i-medium">
123/2023 от 01.01.2023
</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
)
}
}
class AllContractsModal extends React.Component
{
constructor(props)
{
super(props);
}
render()
{
const { open, close, activeContract, handleContractSelected } = this.props
return (
<div className={open ? "fade opened" : "fade"}>
<div className="contractStatus_modal all_contracts_modal">
<div className="modal_header">
<p className="modal_title">Статусы сделок</p>
<button className="modal_close" onClick={close}></button>
</div>
<div className="modal_body">
<div className="contractStatus_list">
<div className="single_status">
<div>
<p>Сделка 1</p>
<span></span>
<i className="status_1"></i>
<p>Выбор КП</p>
</div>
<div>
<p>Сделка 1</p>
<span></span>
<i className="status_2"></i>
<p>Программа финансирования</p>
</div>
<div>
<p>Сделка 1</p>
<span></span>
<i className="status_3"></i>
<p>Сборка пакета документов</p>
</div>
<div className="current">
<p>Сделка 1</p>
<span></span>
<i className="status_4"></i>
<p>Проверка документов</p>
</div>
<div>
<p>Сделка 1</p>
<span></span>
<i className="status_5"></i>
<p>Принятие решения по заявке</p>
</div>
<div>
<p>Сделка 1</p>
<span></span>
<i className="status_6"></i>
<p>Оформление лизинга</p>
</div>
<div>
<p>Сделка 1</p>
<span></span>
<i className="status_7"></i>
<p>Выбор типа подписания</p>
</div>
</div>
</div>
</div>
</div>
</div>
)
}
}
class DealsList extends React.Component
{
constructor(props)
{
super(props)
}
render()
{
return (
<div className="contractStatus_list">
<div className="list_item">
<div>
<p>Сделка 1</p>
</div>
<div>
<p>
2 этапа пройдено
<svg xmlns="http://www.w3.org/2000/svg" width={18} height={18} fill="none">
<path stroke="#8E94A7" strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M14.625 6.75 9 12.375 3.375 6.75" />
</svg>
</p>
</div>
<div>
<img src="/assets/images/status/1.svg" width="50" height="50" />
<p>Сбор пакета документов</p>
</div>
<div>
<p>
еще 4 этапа
<svg xmlns="http://www.w3.org/2000/svg" width={18} height={18} fill="none">
<path stroke="#8E94A7" strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M14.625 6.75 9 12.375 3.375 6.75" />
</svg>
</p>
</div>
<div>
<button className="button" onClick={() => { this._handleModalToggle("all") }} >
Все сделки
<svg xmlns="http://www.w3.org/2000/svg" width={18} height={18} fill="none">
<path stroke="#1C01A9" strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M14.625 6.75 9 12.375 3.375 6.75" />
</svg>
</button>
</div>
</div>
<div className="list_item">
<div>
<p>Сделка 1</p>
</div>
<div>
<p onClick={() => { this._handleModalToggle("current") }} >
2 этапа пройдено
<svg xmlns="http://www.w3.org/2000/svg" width={18} height={18} fill="none">
<path stroke="#8E94A7" strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M14.625 6.75 9 12.375 3.375 6.75"/>
</svg>
</p>
</div>
<div>
<img src="/assets/images/status/3.svg" width="50" height="50" />
<p>Сбор пакета документов</p>
</div>
<div>
<p onClick={() => { this._handleModalToggle("current") }} >
еще 4 этапа
<svg xmlns="http://www.w3.org/2000/svg" width={18} height={18} fill="none">
<path stroke="#8E94A7" strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M14.625 6.75 9 12.375 3.375 6.75" />
</svg>
</p>
</div>
<div>
<button className="button" onClick={() => { this._handleModalToggle("all") }}>
Все сделки
<svg xmlns="http://www.w3.org/2000/svg" width={18} height={18} fill="none">
<path stroke="#1C01A9" strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M14.625 6.75 9 12.375 3.375 6.75" />
</svg>
</button>
</div>
</div>
</div>
)
}
}
class DealsStatus extends React.Component
{
constructor(props)
{
super(props)
this.state = {
currentContractModalOpened: false,
allContractModalOpened: false,
currentSelected: null
}
}
static getDerivedStateFromProps(nextProps, prevState) {
return {}
}
componentDidMount() { }
componentDidUpdate(prevProps, prevState) { }
_handleModalToggle = (modal) =>
{
if (modal === "current")
{
this.setState({
currentContractModalOpened: !this.state.currentContractModalOpened
})
}
else
{
this.setState({
allContractModalOpened: !this.state.allContractModalOpened
})
}
}
_handleContractSelected = (index) =>
{
this.setState({
currentSelected: index
})
}
render()
{
const { currentContractModalOpened, allContractModalOpened, currentSelected } = this.state
return (
<>
<DealsList/>
<SingleDeal
close={() => {
this._handleModalToggle("current")
}}
/>
{/*}
<AllContractsModal
open={allContractModalOpened}
close={() => {
this._handleModalToggle("all")
}}
activeContract={currentSelected}
handleContractSelected={this._handleContractSelected}
/>
{*/}
</>
)
}
}
function mapStateToProps(state, ownProps)
{
return {}
}
export default connect(mapStateToProps)(DealsStatus)

View File

@ -45,3 +45,12 @@ export const SUPPORT_RESET = 'SUPPORT_RESET';
export const QUESTIONNAIRE_UPDATE = 'QUESTIONNAIRE_UPDATE'; export const QUESTIONNAIRE_UPDATE = 'QUESTIONNAIRE_UPDATE';
export const QUESTIONNAIRE_RESET = 'QUESTIONNAIRE_RESET'; export const QUESTIONNAIRE_RESET = 'QUESTIONNAIRE_RESET';
export const QUESTIONNAIRE_SET_SIGN = 'QUESTIONNAIRE_SET_SIGN'; export const QUESTIONNAIRE_SET_SIGN = 'QUESTIONNAIRE_SET_SIGN';
export const DEALS_LOADED = 'DEALS_LOADED';
export const DEALS_LIST = 'DEALS_LIST';
export const DEAL_LOADED = 'DEAL_LOADED';
export const DEAL_OFFERS_LIST = 'DEAL_OFFERS_LIST';
export const DEAL_DOCUMENTS_LIST = 'DEAL_DOCUMENTS_LIST';
export const DEAL_CONTRACTS_LIST = 'DEAL_CONTRACTS_LIST';
export const DEALS_RESET = 'DEALS_RESET';
export const DEAL_RESET = 'DEAL_RESET';

View File

@ -3783,9 +3783,9 @@ main .dropdown_blocks_list .dropdown_block .block_body .fines_detail ul li {
align-items: flex-end; align-items: flex-end;
height: 102px; height: 102px;
} }
@media all and (max-width: 1200px) { @media all and (max-width: 960px) {
.rate_us { .rate_us {
display: none; height: 120px;
} }
} }
.rate_us.opened { .rate_us.opened {
@ -3868,6 +3868,13 @@ main .dropdown_blocks_list .dropdown_block .block_body .fines_detail ul li {
flex-direction: column; flex-direction: column;
justify-content: space-between; justify-content: space-between;
} }
@media all and (min-width: 961px) and (max-width: 1420px) {
.rate_us .rate_body {
border-top-right-radius: 0px;
border-bottom-right-radius: 0px;
margin-right: -80px;
}
}
.rate_us p { .rate_us p {
font-size: 15px; font-size: 15px;
font-weight: 700; font-weight: 700;

View File

@ -4224,8 +4224,9 @@ main .dropdown_blocks_list .dropdown_block .block_body {
align-items: flex-end; align-items: flex-end;
height: 102px; height: 102px;
@media all and (max-width: 1200px) { @media all and (max-width: 960px) {
display: none; //display: none;
height: 120px;
} }
&.opened { &.opened {
@ -4324,6 +4325,12 @@ main .dropdown_blocks_list .dropdown_block .block_body {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: space-between; justify-content: space-between;
@media all and (min-width: 961px) and (max-width: 1420px) {
border-top-right-radius: 0px;
border-bottom-right-radius: 0px;
margin-right: -80px;
}
} }
p { p {

View File

@ -625,3 +625,10 @@ div {
right: 5px; right: 5px;
} }
} }
.contracts_list_title {
font-size: 26px;
font-weight: 700;
line-height: 35px;
margin-top: 35px;
margin-bottom: 35px;
}

View File

@ -668,3 +668,11 @@ div {
} }
} }
} }
.contracts_list_title {
font-size: 26px;
font-weight: 700;
line-height: 35px;
margin-top: 35px;
margin-bottom: 35px;
}

View File

@ -0,0 +1,4 @@
/*
2.7.6 - Метод получения списка договоров со статусами по Лизинговой сделке в CRM
GET /lk/ConsiderationOpportunity/contract
*/

View File

@ -0,0 +1,4 @@
/*
2.7.4 - Метод получения списка документов для рассмотрения Лизинговой сделке в CRM
GET /lk/ConsiderationOpportunity/document
*/

71
pages/api/deals/index.js Normal file
View File

@ -0,0 +1,71 @@
/*
2.7.1 - Метод получения данных по лизинговым сделкам в CRM
GET /lk/ConsiderationOpportunity
*/
import axios from 'axios';
import { Cookies } from 'react-cookie';
import cookie from 'cookie';
import moment from 'moment';
import jwt from 'jsonwebtoken';
import { cors } from '../../../lib/cors';
export default async function handler(req, res)
{
await cors(req, res);
if(req.headers.cookie !== undefined)
{
const cookies = cookie.parse(req.headers?.cookie ? req.headers?.cookie : "");
console.log("req.body");
console.log(req.body);
if(cookies.jwt !== undefined && cookies.jwt !== null)
{
console.log("cookies.jwt");
console.log(cookies.jwt);
var client_jwt_decoded = jwt.verify(cookies.jwt, process.env.JWT_SECRET_CLIENT);
var crm_jwt = jwt.sign(client_jwt_decoded, process.env.JWT_SECRET_CRM, { noTimestamp: true });
console.log("client_jwt_decoded", client_jwt_decoded);
console.log("crm_jwt", crm_jwt);
const url = `${ process.env.CRM_API_HOST }/lk/ConsiderationOpportunity`;
console.log({ url });
try
{
await axios.get(url, {
params: { ...client_jwt_decoded, },
headers: {
"Authorization": `Bearer ${ crm_jwt }`,
},
withCredentials: true,
})
.then((crm_response) =>
{
console.log("API", "contract", "crm_response.data");
//console.log("API", "contract", crm_response.data);
res.status(200).json(crm_response.data);
})
.catch((error) =>
{
console.error(error);
res.status(500);
});
}
catch(e)
{
console.error(e);
res.status(500);
}
}
else
{
res.status(403);
}
}
}

View File

@ -0,0 +1,4 @@
/*
2.7.2 - Метод получения списка Предложений по Лизинговой сделке в CRM
GET /lk/ConsiderationOpportunity/quote
*/

4
pages/api/deals/quote.js Normal file
View File

@ -0,0 +1,4 @@
/*
2.7.3 - Метод согласования Предложений Клиентом по Лизинговой сделке в CRM
POST /lk/ConsiderationOpportunity/quote
*/

View File

@ -0,0 +1,4 @@
/*
2.7.5 - Метод отправки документов по Сделке на проверку
POST /lk/document
*/

View File

@ -0,0 +1,53 @@
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import axios from 'axios';
import { Cookies } from 'react-cookie';
import cookie from 'cookie';
import moment from 'moment';
import jwt from 'jsonwebtoken';
import { inspect } from 'util';
import { cors } from '../../../lib/cors';
export default async function handler(req, res)
{
await cors(req, res);
let { name, phone, rating, comment } = req.body;
console.log("API", "feedbacks/add");
if(req.headers.cookie !== undefined)
{
const cookies = cookie.parse(req.headers?.cookie ? req.headers?.cookie : "");
if(cookies.jwt !== undefined && cookies.jwt !== null)
{
let client_jwt_decoded = jwt.verify(cookies.jwt, process.env.JWT_SECRET_CLIENT);
await axios.post(`${ process.env.NEXT_PUBLIC_API_HOST }/api/feedbacks/add/`, {
token: jwt.sign({ "acc_number": client_jwt_decoded.acc_number, "login": client_jwt_decoded.login }, process.env.JWT_SECRET_CRM, { noTimestamp: true }),
name, phone, rating, comment,
})
.then((api_response) =>
{
console.log("API", "feedbacks/add", "RESPONSE");
console.log(inspect(api_response.data, true, null, true));
res.status(200).send(api_response.data);
})
.catch((error) =>
{
console.error("API", "feedbacks/add", "error");
console.error(error);
res.status(403).json();
});
}
else
{
res.status(403).json();
}
}
else
{
res.status(403).json();
}
}

View File

@ -1,593 +0,0 @@
import React from "react"
import { connect } from "react-redux"
const SingleContractModal = (props) => {
const { open, close } = props
return (
<div className="contractStatus_modal">
<div className="modal_header">
<p className="modal_title">Статус сделки</p>
<button className="modal_close" onClick={close}></button>
</div>
<div className="modal_body single_status">
<div className="current">
<p>Сделка 1</p>
<span></span>
<div className="status_body">
<div className="status_header">
<i className="status_1"></i>
<p>Выбор КП</p>
</div>
<div className="wrap">
<table>
<thead>
<tr>
<th></th>
<th></th>
<th>Стоимость</th>
<th>Первый платеж, р.</th>
<th>Первый платеж, %</th>
<th>Марка</th>
<th>Модель</th>
<th>Объектов лизинга</th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td>
<div className="form_field checkbox">
<input type="checkbox" name="row" id="row" checked="" />
<label htmlFor="row"></label>
</div>
</td>
<td>1</td>
<td>5 600 000 р.</td>
<td>560 000 р.</td>
<td>10 %</td>
<td>Audi</td>
<td>A8</td>
<td>1</td>
<td>
<div className="dosc_list">
<div className="row">
<div className="small-icon">
<p className="doc_name i-pdf">
КП
<span>1</span>
</p>
</div>
</div>
</div>
</td>
</tr>
<tr>
<td>
<div className="form_field checkbox">
<input type="checkbox" name="row" id="row" checked="" />
<label htmlFor="row"></label>
</div>
</td>
<td>1</td>
<td>5 600 000 р.</td>
<td>560 000 р.</td>
<td>10 %</td>
<td>Audi</td>
<td>A8</td>
<td>1</td>
<td>
<div className="dosc_list">
<div className="row">
<div className="small-icon">
<p className="doc_name i-pdf">
КП
<span>1</span>
</p>
</div>
</div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div>
<p>Сделка 1</p>
<span></span>
<div className="status_body">
<div className="status_header">
<i className="status_2"></i>
<p className="header">Программа финансирования</p>
</div>
<div className="wrap">
<div className="single_text">
<p>Статусный текст о том что выбирается программа финансированияи может быть по центру иконочка часиков или слева от статусного текста иконочка часиков</p>
</div>
</div>
</div>
</div>
<div>
<p>Сделка 1</p>
<span></span>
<div className="status_body">
<div className="status_header">
<i className="status_3"></i>
<p>Сборка пакета документов</p>
</div>
<div className="wrap">
<div className="message ok">
<p>Вам не требуется актуализация данных анкеты Клиента</p>
</div>
<div className="message alert">
<p>Требуется обновить данные в анкете</p>
<button className="button button-blue">Актуализировать данные</button>
</div>
<div className="message wait">
<p>Проводится проверка анкеты Вашей организации</p>
</div>
<p><b>Устав организации</b></p>
<div className="attach_file">
<label>
<input type="file" hidden />
Прикрепить скан документов
</label>
</div>
<div class="message documents">
<div className="doc_list">
<div class="dosc_list medium-icon"><div class="row"><p class="doc_name i-pdf i-medium">123/2023 от 01.01.2023</p></div></div>
<div class="dosc_list medium-icon"><div class="row"><p class="doc_name i-pdf i-medium">123/2023 от 01.01.2023</p></div></div>
</div>
<p>Документы, отправленные Вами принадлежат другой организации бла бла коммент от менеджера</p>
</div>
<div className="attach_file">
<label>
<input type="file" hidden />
Прикрепить ещё
</label>
</div>
<p><b>Другое название документа</b></p>
<div className="attach_file">
<label>
<input type="file" hidden />
Прикрепить скан документов
</label>
</div>
</div>
</div>
</div>
<div className="">
<p>Сделка 1</p>
<span></span>
<div className="status_body">
<div className="status_header">
<i className="status_4"></i>
<p>Проверка документов</p>
</div>
<div className="wrap">
<div className="single_text">
<p>Статусный текст о том что выбирается программа финансированияи может быть по центру иконочка часиков или слева от статусного текста иконочка часиков</p>
</div>
</div>
</div>
</div>
<div>
<p>Сделка 1</p>
<span></span>
<div className="status_body">
<div className="status_header">
<i className="status_5"></i>
<p>Принятие решения по заявке</p>
</div>
<div className="wrap">
<div className="single_text">
<p>Статусный текст о том что выбирается программа финансированияи может быть по центру иконочка часиков или слева от статусного текста иконочка часиков</p>
</div>
</div>
</div>
</div>
<div>
<p>Сделка 1</p>
<span></span>
<div className="status_body">
<div className="status_header">
<i className="status_6"></i>
<p>Оформление лизинга</p>
</div>
<div className="wrap">
<div className="single_text">
<p>Статусный текст о том что выбирается программа финансированияи может быть по центру иконочка часиков или слева от статусного текста иконочка часиков</p>
</div>
</div>
</div>
</div>
<div>
<p>Сделка 1</p>
<span></span>
<div className="status_body">
<div className="status_header">
<i className="status_7"></i>
<p>Выбор типа подписания</p>
</div>
<div className="wrap">
<div className="block-column">
<div
className="dropdown_block open"
>
<div className="block_header default">
<p><b>Подготовлено 3 из 12</b></p>
</div>
</div>
<div className="dosc_list acts_list-checkbox medium-icon">
< div className="row">
<p
className="doc_name i-doc i-medium"
>
<input type="checkbox" name="" id="" checked="" />
<label for="">2022_6875 от 28.06.2022</label>
</p>
</div>
</div>
<div className="block_footer_btn">
<button className="button button-blue">Подписать в ЭДО</button>
<button className="button button-blue">Подписать в бумажном виде</button>
</div>
</div>
<div className="block-column">
<div
className="dropdown_block open"
>
<div className="block_header default">
<p><b>К подписанию 3 из 12</b></p>
</div>
</div>
<div className="dosc_list medium-icon">
< div className="row flex-start">
<p
className="doc_name i-doc i-medium"
>
123/2023 от 01.01.2023
</p>
<button className="button">Перейти в ЭДО</button>
</div>
< div className="row flex-start">
<p
className="doc_name i-doc i-medium"
>
123/2023 от 01.01.2023
</p>
<button className="button">Скачать документ</button>
<button className="button">Загрузить подписанный экземпляр</button>
</div>
</div>
</div>
<div className="block-column">
<div
className="dropdown_block open"
>
<div className="block_header default">
<p><b>Подписано 3 из 12</b></p>
</div>
</div>
<div className="dosc_list medium-icon">
< div className="row">
<p
className="doc_name i-doc i-medium"
>
<a href="#">Скачать 129/2023 от 01.01.2023 - Ожидание оплаты</a>
</p>
</div>
</div>
</div>
<div className="block-column">
<div
className="dropdown_block open"
>
<div className="block_header default">
<p><b>Подготовлено 3 из 12</b></p>
</div>
</div>
<div className="dosc_list medium-icon">
< div className="row">
<p
className="doc_name i-doc i-medium"
>
123/2023 от 01.01.2023
</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
)
}
const AllContractsModal = (props) => {
const { open, close, activeContract, handleContractSelected } = props
return (
<div className={open ? "fade opened" : "fade"}>
<div className="contractStatus_modal all_contracts_modal">
<div className="modal_header">
<p className="modal_title">Статусы сделок</p>
<button className="modal_close" onClick={close}></button>
</div>
<div className="modal_body">
<div className="contractStatus_list">
<div className="single_status">
<div>
<p>Сделка 1</p>
<span></span>
<i className="status_1"></i>
<p>Выбор КП</p>
</div>
<div>
<p>Сделка 1</p>
<span></span>
<i className="status_2"></i>
<p>Программа финансирования</p>
</div>
<div>
<p>Сделка 1</p>
<span></span>
<i className="status_3"></i>
<p>Сборка пакета документов</p>
</div>
<div className="current">
<p>Сделка 1</p>
<span></span>
<i className="status_4"></i>
<p>Проверка документов</p>
</div>
<div>
<p>Сделка 1</p>
<span></span>
<i className="status_5"></i>
<p>Принятие решения по заявке</p>
</div>
<div>
<p>Сделка 1</p>
<span></span>
<i className="status_6"></i>
<p>Оформление лизинга</p>
</div>
<div>
<p>Сделка 1</p>
<span></span>
<i className="status_7"></i>
<p>Выбор типа подписания</p>
</div>
</div>
</div>
</div>
</div>
</div>
)
}
class ContractStatus extends React.Component {
constructor(props) {
super(props)
this.state = {
currentContractModalOpened: false,
allContractModalOpened: false,
currentSelected: null
}
}
static getDerivedStateFromProps(nextProps, prevState) {
return {}
}
componentDidMount() { }
componentDidUpdate(prevProps, prevState) { }
_handleModalToggle = (modal) => {
if (modal === "current") {
this.setState({
currentContractModalOpened: !this.state.currentContractModalOpened
})
} else {
this.setState({
allContractModalOpened: !this.state.allContractModalOpened
})
}
}
_handleContractSelected = (index) => {
this.setState({
currentSelected: index
})
}
render() {
const { currentContractModalOpened, allContractModalOpened, currentSelected } = this.state
return (
<>
<div className="contractStatus_list">
<div className="list_item">
<div>
<p>Сделка 1</p>
</div>
<div>
<p>
2 этапа пройдено
<svg xmlns="http://www.w3.org/2000/svg" width={18} height={18} fill="none">
<path
stroke="#8E94A7"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M14.625 6.75 9 12.375 3.375 6.75"
/>
</svg>
</p>
</div>
<div>
<img src="/assets/images/status/1.svg" width="50" height="50" />
<p>Сбор пакета документов</p>
</div>
<div>
<p>
еще 4 этапа
<svg xmlns="http://www.w3.org/2000/svg" width={18} height={18} fill="none">
<path
stroke="#8E94A7"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M14.625 6.75 9 12.375 3.375 6.75"
/>
</svg>
</p>
</div>
<div>
<button
className="button"
onClick={() => {
this._handleModalToggle("all")
}}
>
Все сделки
<svg xmlns="http://www.w3.org/2000/svg" width={18} height={18} fill="none">
<path
stroke="#1C01A9"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M14.625 6.75 9 12.375 3.375 6.75"
/>
</svg>
</button>
</div>
</div>
<div className="list_item">
<div>
<p>Сделка 1</p>
</div>
<div>
<p
onClick={() => {
this._handleModalToggle("current")
}}
>
2 этапа пройдено
<svg xmlns="http://www.w3.org/2000/svg" width={18} height={18} fill="none">
<path
stroke="#8E94A7"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M14.625 6.75 9 12.375 3.375 6.75"
/>
</svg>
</p>
</div>
<div>
<img src="/assets/images/status/3.svg" width="50" height="50" />
<p>Сбор пакета документов</p>
</div>
<div>
<p
onClick={() => {
this._handleModalToggle("current")
}}
>
еще 4 этапа
<svg xmlns="http://www.w3.org/2000/svg" width={18} height={18} fill="none">
<path
stroke="#8E94A7"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M14.625 6.75 9 12.375 3.375 6.75"
/>
</svg>
</p>
</div>
<div>
<button
className="button"
onClick={() => {
this._handleModalToggle("all")
}}
>
Все сделки
<svg xmlns="http://www.w3.org/2000/svg" width={18} height={18} fill="none">
<path
stroke="#1C01A9"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M14.625 6.75 9 12.375 3.375 6.75"
/>
</svg>
</button>
</div>
</div>
</div>
<SingleContractModal
open={currentContractModalOpened}
close={() => {
this._handleModalToggle("current")
}}
/>
<AllContractsModal
open={allContractModalOpened}
close={() => {
this._handleModalToggle("all")
}}
activeContract={currentSelected}
handleContractSelected={this._handleContractSelected}
/>
</>
)
}
}
function mapStateToProps(state, ownProps) {
return {}
}
export default connect(mapStateToProps)(ContractStatus)

View File

@ -3,7 +3,7 @@ import { connect } from "react-redux"
import { SpinnerCircular } from "spinners-react"; import { SpinnerCircular } from "spinners-react";
import InputMask from 'react-input-mask'; import InputMask from 'react-input-mask';
import { sendNewAppeal } from "../../../actions" import { sendFeedback, sendNewAppeal } from "../../../actions"
import { _checkStrValue } from "../../../utils"; import { _checkStrValue } from "../../../utils";
class Rating extends React.Component class Rating extends React.Component
@ -17,6 +17,7 @@ class Rating extends React.Component
comment: "", comment: "",
opened: false, opened: false,
hidden: false, hidden: false,
deleted: false,
rating: 0, rating: 0,
hovered: 0, hovered: 0,
stars: [], stars: [],
@ -76,12 +77,31 @@ class Rating extends React.Component
} }
_handle_onSetPublished = () => _handle_onSetPublished = () =>
{
const { name, phone, comment, rating } = this.state;
if(!this.state.publish)
{ {
this.setState({ publish: this.state.publish ? false : true }); this.setState({ publish: this.state.publish ? false : true });
sendFeedback({
name,
phone,
comment,
rating,
})
.then(() => {})
.catch(() => {});
setTimeout(() => { setTimeout(() => {
this.setState({ hidden: true }) this.setState({ hidden: true })
}, 1000);
setTimeout(() => {
this.setState({ deleted: true })
}, 2000); }, 2000);
} }
}
_removeError = (name) => _removeError = (name) =>
{ {
@ -135,9 +155,15 @@ class Rating extends React.Component
render() render()
{ {
const { opened, hidden, stars, rating, hovered, completed, publish, loading, name, phone, comment, errors } = this.state const { opened, hidden, deleted, stars, rating, hovered, completed, publish, loading, name, phone, comment, errors } = this.state
const data = ["Очень плохо", "Плохо", "Нормально", "Хорошо", "Отлично"] const data = ["Очень плохо", "Плохо", "Нормально", "Хорошо", "Отлично"]
if(deleted)
{
return null;
}
else
{
return ( return (
<div className={`rate_us ${ opened && "opened" } ${ hidden && "hidden" }`}> <div className={`rate_us ${ opened && "opened" } ${ hidden && "hidden" }`}>
<div className={`rate_body ${ completed && "completed" }`}> <div className={`rate_body ${ completed && "completed" }`}>
@ -208,7 +234,7 @@ class Rating extends React.Component
placeholder="Комментарий" placeholder="Комментарий"
onChange={ (event) => this._handle_onFieldChange(event.target.name, event.target.value) } onChange={ (event) => this._handle_onFieldChange(event.target.name, event.target.value) }
defaultValue={ comment } defaultValue={ comment }
required={ rating > 1 ? false : true } required={ rating > 4 ? false : true }
/> />
</div> </div>
<button type="submit" className="button button button-blue"> <button type="submit" className="button button button-blue">
@ -222,6 +248,7 @@ class Rating extends React.Component
) )
} }
} }
}
function mapStateToProps(state, ownProps) function mapStateToProps(state, ownProps)
{ {

View File

@ -18,7 +18,7 @@ import DateInput from "../components/DatePicker"
import Pagination from "./components/Pagination" import Pagination from "./components/Pagination"
import Manager from "./components/Manager" import Manager from "./components/Manager"
import AccountLayout from "./components/Layout/Account" import AccountLayout from "./components/Layout/Account"
import ContractStatus from "./components/ContractStatus" import DealsStatus from "../components/DealsStatus"
import AnnouncementsList from "./components/AnnouncementsList" import AnnouncementsList from "./components/AnnouncementsList"
import { getCompanyInfo, getContractsList, getImage } from '../actions'; import { getCompanyInfo, getContractsList, getImage } from '../actions';
@ -313,9 +313,15 @@ class IndexPage extends React.Component
</div> </div>
)} )}
<ContractStatus /> {/*}
<DealsStatus />
{*/}
{ contracts !== null && contracts.length > 0 && ( { contracts !== null && contracts.length > 0 && (
<>
<div>
<p className="contracts_list_title">Список договоров</p>
</div>
<div className="contract_search"> <div className="contract_search">
<form <form
onSubmit={(event) => { onSubmit={(event) => {
@ -365,6 +371,7 @@ class IndexPage extends React.Component
</button> </button>
</form> </form>
</div> </div>
</>
)} )}
{ loading ? ( { loading ? (
<div <div

104
reducers/dealsReducer.js Normal file
View File

@ -0,0 +1,104 @@
import { HYDRATE } from 'next-redux-wrapper';
import * as actionTypes from '../constants/actionTypes';
import initialState from "./initialState";
const dealsReducer = (state = initialState.deals, action) =>
{
switch (action.type)
{
case actionTypes.DEALS_LOADED:
{
return {
...state,
loaded: action.data.loaded,
};
}
case actionTypes.DEALS_LIST:
{
return {
...state,
list: action.data.list,
};
}
case actionTypes.DEAL_LOADED:
{
return {
...state,
deal: { ...state.deal, ...{ loaded: action.data.loaded, } },
};
}
case actionTypes.DEAL_OFFERS_LIST:
{
return {
...state,
deal: { ...state.deal, ...{ offers: action.data.offers, } },
};
}
case actionTypes.DEAL_DOCUMENTS_LIST:
{
return {
...state,
deal: { ...state.deal, ...{ documents: action.data.documents, } },
};
}
case actionTypes.DEAL_CONTRACTS_LIST:
{
return {
...state,
deal: { ...state.deal, ...{ contracts: action.data.contracts, } },
};
}
case actionTypes.DEALS_RESET:
{
return {
loaded: false,
list: undefined,
deal: {
loaded: false,
offers: {
list: undefined,
filtered: undefined,
},
documents: {
list: undefined,
},
contracts: {
list: undefined,
},
},
};
}
case actionTypes.DEAL_RESET:
{
return {
deal: {
loaded: false,
offers: {
list: undefined,
filtered: undefined,
},
documents: {
list: undefined,
},
contracts: {
list: undefined,
},
},
};
}
default: {
return state;
}
}
};
export default dealsReducer;

View File

@ -232,6 +232,24 @@ export const defaultState = {
appeal: null, appeal: null,
request: null, request: null,
}, },
deals:
{
loaded: false,
list: undefined,
deal: {
loaded: false,
offers: {
list: undefined,
filtered: undefined,
},
documents: {
list: undefined,
},
contracts: {
list: undefined,
},
},
},
}; };
export default JSON.parse(JSON.stringify({ ...defaultState, ...{ questionnaire: questionnaire_template } })); export default JSON.parse(JSON.stringify({ ...defaultState, ...{ questionnaire: questionnaire_template } }));