fixes for support pages, admin panel
This commit is contained in:
parent
6502705f3f
commit
93f3e46730
@ -42,10 +42,13 @@ export const getCalendar = ({ dispatch, date_from, date_to }) =>
|
||||
let payments = [];
|
||||
for(let i in contract.payments)
|
||||
{
|
||||
const mdate = moment(contract.payments[i].date, "DD-MM-YYYY");
|
||||
periods[mdate.format('YYYYMM')] = mdate.format('YYYYMM');
|
||||
|
||||
payments.push({ ...contract.payments[i], ...{ contract: { number: contract.number, date: contract.date }, date: mdate.format("YYYY-MM-DD"), js_date: mdate.toDate() } });
|
||||
if(contract.payments[i].date !== null)
|
||||
{
|
||||
const mdate = moment(contract.payments[i].date, "DD-MM-YYYY");
|
||||
periods[mdate.format('YYYYMM')] = mdate.format('YYYYMM');
|
||||
|
||||
payments.push({ ...contract.payments[i], ...{ contract: { number: contract.number, date: contract.date }, date: mdate.format("YYYY-MM-DD"), js_date: mdate.toDate() } });
|
||||
}
|
||||
}
|
||||
|
||||
let query = nSQL(payments)
|
||||
|
||||
@ -19,6 +19,59 @@ if(process.browser)
|
||||
};
|
||||
}
|
||||
|
||||
export const setAppealsRead = ({ dispatch, appeals }) =>
|
||||
{
|
||||
return new Promise((resolve, reject) =>
|
||||
{
|
||||
axios.post(`${ process.env.NEXT_PUBLIC_SELF_API_HOST }/api/support/read`, { appeals }, {
|
||||
withCredentials: true,
|
||||
})
|
||||
.then((response) =>
|
||||
{
|
||||
dispatch({ type: actionTypes.SUPPORT_APPEALS, data: { appeals: { new: 0, } } });
|
||||
resolve();
|
||||
})
|
||||
.catch((error) =>
|
||||
{
|
||||
console.log("error");
|
||||
console.error(error);
|
||||
|
||||
reject();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export const getAppeals = ({ 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/support/appeals`, {}, {
|
||||
withCredentials: true,
|
||||
})
|
||||
.then((response) =>
|
||||
{
|
||||
console.log("getEvents", "response", response.data);
|
||||
const events = response.data;
|
||||
const filtered_events = [];
|
||||
|
||||
console.log("events");
|
||||
console.log(events);
|
||||
|
||||
dispatch({ type: actionTypes.SUPPORT_APPEALS, data: { appeals: { list: response.data.appeals, new: response.data.new, } } });
|
||||
resolve();
|
||||
})
|
||||
.catch((error) =>
|
||||
{
|
||||
console.log("error");
|
||||
console.error(error);
|
||||
|
||||
reject();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export const getSupportThemes = ({ dispatch, query, }) =>
|
||||
{
|
||||
console.log("ACTION", "support", "getSupportThemes", { query });
|
||||
|
||||
169
pages/api/support/appeals.js
Normal file
169
pages/api/support/appeals.js
Normal file
@ -0,0 +1,169 @@
|
||||
// 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 Redis from 'ioredis';
|
||||
|
||||
import { cors } from '../../../lib/cors';
|
||||
|
||||
const redis = new Redis(process.env.REDIS_URL);
|
||||
|
||||
export default async function handler(req, res)
|
||||
{
|
||||
await cors(req, res);
|
||||
|
||||
console.log("API", "support", "appeals", req.headers);
|
||||
|
||||
if(req.headers.cookie !== undefined)
|
||||
{
|
||||
const cookies = cookie.parse(req.headers?.cookie ? req.headers?.cookie : "");
|
||||
|
||||
if(cookies.jwt !== undefined && cookies.jwt !== null)
|
||||
{
|
||||
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");
|
||||
console.log(client_jwt_decoded);
|
||||
|
||||
const read = await redis.keys(`${ client_jwt_decoded.acc_number }_appeal_*`);
|
||||
console.log("API", "support", "appeals", "read", read);
|
||||
|
||||
try
|
||||
{
|
||||
await axios.get(`${ process.env.CRM_API_HOST }/lk/Account/GetIncidents/`, {
|
||||
params: client_jwt_decoded,
|
||||
headers: {
|
||||
"Authorization": `Bearer ${ crm_jwt }`,
|
||||
}
|
||||
})
|
||||
.then((crm_response) =>
|
||||
{
|
||||
let unread = 0;
|
||||
console.log("API", "support", "appeals", "response", crm_response.data);
|
||||
|
||||
const appeals = [
|
||||
{
|
||||
number: "CAS-02991-J2M9B8",
|
||||
created_date: "2021-09-06",
|
||||
subject: "Вопросы по пени и штрафам",
|
||||
owner: "Анастасия Ломакина",
|
||||
status: "cancelled",
|
||||
answer: "",
|
||||
contracts: "No2021_1889, No2021_2453, No2021_2465, No2021_2857",
|
||||
documents: [
|
||||
{
|
||||
doc_name: "Письмо от ЛП",
|
||||
doc_url: "24bfe404-9905-4b69-8898-09a7229a8fc1",
|
||||
doc_extension: "pdf",
|
||||
},
|
||||
{
|
||||
doc_name: "Пояснения СБ",
|
||||
doc_url: "24bfe404-9905-4b69-8898-09a7229a8fc1",
|
||||
doc_extension: "pdf",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
number: "CAS-01779-S2Q3Q6",
|
||||
created_date: "2021-06-22",
|
||||
subject: "Изменение графика",
|
||||
owner: "Анастасия Ломакина",
|
||||
status: "active",
|
||||
answer: "",
|
||||
contracts: "No2021_1889, No2021_1891, No2021_1914, No2021_2453, No2021_3023, No2021_7349, No2021_9969, No2021_125 95",
|
||||
documents: [
|
||||
{
|
||||
doc_name: "Запрос на выезд за границу",
|
||||
doc_url: "4291c8b0-2aff-47a1-b246-fc8e5e196c24",
|
||||
doc_extension: "pdf",
|
||||
},
|
||||
{
|
||||
doc_name: "согласование УЭБ",
|
||||
doc_url: "4291c8b0-2aff-47a1-b246-fc8e5e196c24",
|
||||
doc_extension: "pdf",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
number: "CAS-01691-L2Z7H2",
|
||||
created_date: "2021-06-08",
|
||||
subject: "Выдача документов по сделке",
|
||||
owner: "Анастасия Ломакина",
|
||||
status: "closed",
|
||||
answer: "",
|
||||
contracts: "No2021_1889, No2021_3023, No2021_7349, No2021_9969, No2021_12595",
|
||||
documents: [
|
||||
{
|
||||
doc_name: "Доп. соглашение по КАСКО",
|
||||
doc_url: "7e11a7b0-0246-44ea-8f92-65698b79ea36",
|
||||
doc_extension: "pdf",
|
||||
},
|
||||
{
|
||||
doc_name: "Запрос на выезд за границу",
|
||||
doc_url: "7e11a7b0-0246-44ea-8f92-65698b79ea36",
|
||||
doc_extension: "pdf",
|
||||
},
|
||||
{
|
||||
doc_name: "письмо о назначении платежей",
|
||||
doc_url: "7e11a7b0-0246-44ea-8f92-65698b79ea36",
|
||||
doc_extension: "pdf",
|
||||
},
|
||||
{
|
||||
doc_name: "ПП по платежу за июнь",
|
||||
doc_url: "7e11a7b0-0246-44ea-8f92-65698b79ea36",
|
||||
doc_extension: "pdf",
|
||||
},
|
||||
{
|
||||
doc_name: "ПП по расширению страхового покрытия",
|
||||
doc_url: "7e11a7b0-0246-44ea-8f92-65698b79ea36",
|
||||
doc_extension: "pdf",
|
||||
}
|
||||
],
|
||||
}
|
||||
];
|
||||
|
||||
for(let i in appeals)
|
||||
{
|
||||
const key = `${ client_jwt_decoded.acc_number }_appeal_${ appeals[i].number }_${ appeals[i].status }`;
|
||||
console.log("LOOK", key);
|
||||
|
||||
if(read.indexOf(key) > -1)
|
||||
{
|
||||
appeals[i].read = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
unread++;
|
||||
}
|
||||
}
|
||||
//res.status(200).json(crm_response.data);
|
||||
res.status(200).json({
|
||||
new: unread,
|
||||
appeals
|
||||
});
|
||||
})
|
||||
.catch((error) =>
|
||||
{
|
||||
console.error(error);
|
||||
res.status(500).send();
|
||||
});
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
console.error(e);
|
||||
res.status(500).send();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
res.status(403).send();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
res.status(403).send();
|
||||
}
|
||||
}
|
||||
53
pages/api/support/read.js
Normal file
53
pages/api/support/read.js
Normal 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 Redis from 'ioredis';
|
||||
import md5 from 'md5';
|
||||
|
||||
import { cors } from '../../../lib/cors';
|
||||
|
||||
const redis = new Redis(process.env.REDIS_URL);
|
||||
|
||||
export default async function handler(req, res)
|
||||
{
|
||||
await cors(req, res);
|
||||
|
||||
let { appeals } = req.body;
|
||||
|
||||
if(req.headers.cookie !== undefined)
|
||||
{
|
||||
const cookies = cookie.parse(req.headers?.cookie ? req.headers?.cookie : "");
|
||||
|
||||
if(cookies.jwt !== undefined && cookies.jwt !== null)
|
||||
{
|
||||
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");
|
||||
console.log(client_jwt_decoded);
|
||||
|
||||
try
|
||||
{
|
||||
for(let i in appeals)
|
||||
{
|
||||
const key = `${ client_jwt_decoded.acc_number }_appeal_${ appeals[i].number }_${ appeals[i].status }`;
|
||||
console.log("API", "support", "read", "key", key);
|
||||
|
||||
await redis.set(key, appeals[i].status);
|
||||
}
|
||||
}
|
||||
catch(exception)
|
||||
{
|
||||
console.error("EXCEPTION", "API", "support", "read");
|
||||
console.error(exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
res.status(200).json({
|
||||
status: "success",
|
||||
});
|
||||
}
|
||||
@ -122,6 +122,30 @@ export default class NotificationMessage extends React.Component
|
||||
</li>
|
||||
)
|
||||
}
|
||||
|
||||
case "return_pts":
|
||||
{
|
||||
return (
|
||||
<li className="new">
|
||||
{ event.important ? (
|
||||
<p className="name"><b>Внимание! Просрочена дата возврата СТС по договору №{ event.contract_number }. Посмотрите порядок возврата СТС или загрузите скан СТС по ссылке.</b></p>
|
||||
) : (
|
||||
<p className="name"><b>Приближается дата возврата СТС по договору №{ event.contract_number }. Посмотрите порядок возврата СТС или загрузите скан СТС по ссылке.</b></p>
|
||||
) }
|
||||
{ event.important && (<p className="type">Важное</p>) }
|
||||
<p className="date">{ event.event_date }</p>
|
||||
<p className="action">
|
||||
<Link href="/support/faq">
|
||||
<a>Посмотрите порядок возврата СТС</a>
|
||||
</Link>
|
||||
или
|
||||
<Link href="/support/request">
|
||||
<a>Загрузите скан СТС <span style={{ color: "red" }}>(какой раздел FAQ ?)</span></a>
|
||||
</Link>
|
||||
</p>
|
||||
</li>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@ -2,7 +2,7 @@ import React from "react";
|
||||
import Link from "next/link";
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import { logout, getEvents } from "../../../actions";
|
||||
import { logout, getEvents, getAppeals } from "../../../actions";
|
||||
import NotificationsList from "./NotificationsList";
|
||||
|
||||
class Header extends React.Component
|
||||
@ -17,6 +17,7 @@ class Header extends React.Component
|
||||
messagesOpened: false,
|
||||
events: [],
|
||||
events_loaded: false,
|
||||
appeals: 0,
|
||||
};
|
||||
}
|
||||
|
||||
@ -24,7 +25,8 @@ class Header extends React.Component
|
||||
{
|
||||
return {
|
||||
observer: nextProps.observer,
|
||||
events: nextProps.events,
|
||||
events: nextProps.events,
|
||||
appeals: nextProps.appeals,
|
||||
};
|
||||
}
|
||||
|
||||
@ -32,6 +34,8 @@ class Header extends React.Component
|
||||
{
|
||||
console.log("Header", "CDM");
|
||||
getEvents({ dispatch: this.props.dispatch });
|
||||
console.log("Header", "CDM", "222222");
|
||||
getAppeals({ dispatch: this.props.dispatch });
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps, prevState)
|
||||
@ -138,7 +142,7 @@ class Header extends React.Component
|
||||
|
||||
render()
|
||||
{
|
||||
const { observer, menuOpened, notificationsOpened, messagesOpened, events, events_loaded } = this.state;
|
||||
const { observer, menuOpened, notificationsOpened, messagesOpened, events, events_loaded, appeals } = this.state;
|
||||
console.log("events", events);
|
||||
|
||||
return (
|
||||
@ -187,13 +191,11 @@ class Header extends React.Component
|
||||
</a>
|
||||
</Link>
|
||||
</li>
|
||||
{/*}
|
||||
<li>
|
||||
<Link href="/support/faq/" shallow>
|
||||
<a className={ this.props.router && this.props.router.route.indexOf("/support") === 0 ? "active" : "" }>Обращения</a>
|
||||
</Link>
|
||||
</li>
|
||||
{*/}
|
||||
{/*
|
||||
<li>
|
||||
<Link href={ process.env.NEXT_PUBLIC_MAIN_SITE }>
|
||||
@ -227,15 +229,13 @@ class Header extends React.Component
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
{/*}
|
||||
<li>
|
||||
<Link href="/support/" shallow>
|
||||
<a data-icon="message" data-notify="0" className="button" onClick={ this._handle_onToggleMessages }>
|
||||
<Link href={ `/support/appeals` } shallow>
|
||||
<a data-icon="message" data-notify={ appeals } className="button" onClick={ this._handle_onToggleMessages }>
|
||||
Сообщения
|
||||
</a>
|
||||
</Link>
|
||||
</li>
|
||||
{*/}
|
||||
<li>
|
||||
<button
|
||||
className="lk"
|
||||
@ -255,6 +255,7 @@ function mapStateToProps(state, ownProps)
|
||||
return {
|
||||
observer: state.auth.observer,
|
||||
events: state.events.list,
|
||||
appeals: state.support.appeals.new,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import React from "react";
|
||||
import * as ReactDOM from 'react-dom';
|
||||
import Head from 'next/head';
|
||||
import Image from 'next/image';
|
||||
import Link from "next/link";
|
||||
@ -25,7 +26,6 @@ class IndexPage extends React.Component
|
||||
{
|
||||
super(props);
|
||||
this.state = {
|
||||
|
||||
user: {},
|
||||
};
|
||||
}
|
||||
@ -37,11 +37,41 @@ class IndexPage extends React.Component
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
componentDidMount()
|
||||
{
|
||||
ReactDOM.findDOMNode(this).parentNode.style.height = "100%";
|
||||
ReactDOM.findDOMNode(this).parentNode.style.display = "flex";
|
||||
ReactDOM.findDOMNode(this).parentNode.style.flexDirection = "column";
|
||||
ReactDOM.findDOMNode(this).parentNode.style.justifyContent = "spaceBetween";
|
||||
ReactDOM.findDOMNode(this).parentNode.style.alignItems = "stretch";
|
||||
|
||||
document.documentElement.style.height = "100%";
|
||||
document.documentElement.style.display = "flex";
|
||||
document.documentElement.style.flexDirection = "column";
|
||||
document.body.style.height = "100%";
|
||||
document.body.style.display = "flex";
|
||||
document.body.style.flexDirection = "column";
|
||||
}
|
||||
|
||||
componentWillUnmount()
|
||||
{
|
||||
ReactDOM.findDOMNode(this).parentNode.style.height = "unset";
|
||||
ReactDOM.findDOMNode(this).parentNode.style.display = "unset";
|
||||
ReactDOM.findDOMNode(this).parentNode.style.flexDirection = "unset";
|
||||
ReactDOM.findDOMNode(this).parentNode.style.justifyContent = "unset";
|
||||
ReactDOM.findDOMNode(this).parentNode.style.alignItems = "unset";
|
||||
|
||||
document.documentElement.style.height = "unset";
|
||||
document.documentElement.style.display = "unset";
|
||||
document.documentElement.style.flexDirection = "unset";
|
||||
document.body.style.height = "unset";
|
||||
document.body.style.display = "unset";
|
||||
document.body.style.flexDirection = "unset";
|
||||
}
|
||||
|
||||
render()
|
||||
{
|
||||
const { user } = this.state;
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
@ -53,7 +83,7 @@ class IndexPage extends React.Component
|
||||
/>
|
||||
</Head>
|
||||
<Header { ...this.props }/>
|
||||
<main>
|
||||
<main style={{ flex: 1, display: "flex", flexDirection: "column" }}>
|
||||
<section>
|
||||
<div className="clear"></div>
|
||||
<div className="container">
|
||||
@ -68,13 +98,11 @@ class IndexPage extends React.Component
|
||||
<article>
|
||||
<div className="settings_user_control">
|
||||
<p>Настройки доступа к личному кабинету</p>
|
||||
|
||||
<div>
|
||||
<button className="button button-blue">Добавить пользователя</button>
|
||||
<button className="button button-blue">Редактировать</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="settings_table editable">
|
||||
<div className="table_header table_row">
|
||||
<div className="table_cell">ФИО пользователя</div>
|
||||
@ -84,26 +112,26 @@ class IndexPage extends React.Component
|
||||
<div className="table_cell">Статус</div>
|
||||
<div className="table_cell"></div>
|
||||
</div>
|
||||
|
||||
{ user !== undefined && user !== null && user.email !== undefined && user.email !== null && (
|
||||
<div className="table_row">
|
||||
<div className="table_cell" data-title="ФИО пользователя">{ `${ user.lastname } ${ user.name } ${ user.secondname }` }</div>
|
||||
<div className="table_cell" data-title="Почта">{ user.email }</div>
|
||||
<div className="table_cell" data-title="Роль">Администратор</div>
|
||||
<div className="table_cell" data-title="Доступные организации">Все организации</div>
|
||||
<div className="table_cell" data-title="Статус">Активен</div>
|
||||
<div className="table_cell delete" style={{ position: 'relative' }}>
|
||||
</div>
|
||||
</div>
|
||||
) }
|
||||
{/*}
|
||||
<div className="table_row">
|
||||
<div className="table_cell" data-title="ФИО пользователя">Иванов Иван Иванович</div>
|
||||
<div className="table_cell" data-title="Почта">iivanov@mail.com</div>
|
||||
<div className="table_cell" data-title="Роль">Администратор</div>
|
||||
<div className="table_cell" data-title="Доступные организации">Все организации</div>
|
||||
<div className="table_cell" data-title="Статус">Активен</div>
|
||||
<div className="table_cell delete">
|
||||
<button className="delete_user" title="Удалить пользователя">Удалить</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="table_row">
|
||||
<div className="table_cell" data-title="ФИО пользователя">Иванов Иван Иванович</div>
|
||||
<div className="table_cell" data-title="Почта">iivanov@mail.com</div>
|
||||
<div className="table_cell" data-title="Роль">Администратор</div>
|
||||
<div className="table_cell" data-title="Доступные организации">Все организации</div>
|
||||
<div className="table_cell" data-title="Статус">Активен</div>
|
||||
<div className="table_cell delete">
|
||||
<button className="delete_user" title="Удалить пользователя">Удалить</button>
|
||||
<div className="table_cell delete" style={{ position: 'relative' }}>
|
||||
<button className="delete_user" title="Удалить пользователя"></button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="table_row editable">
|
||||
@ -140,10 +168,11 @@ class IndexPage extends React.Component
|
||||
</div>
|
||||
</div>
|
||||
<div className="table_cell" data-title="Статус">-</div>
|
||||
<div className="table_cell delete">
|
||||
<button className="delete_user" title="Удалить пользователя">Удалить</button>
|
||||
<div className="table_cell delete" style={{ position: 'relative' }}>
|
||||
<button className="delete_user" title="Удалить пользователя"></button>
|
||||
</div>
|
||||
</div>
|
||||
{*/}
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
@ -4,6 +4,7 @@ import Link from "next/link";
|
||||
const menu = [
|
||||
{id: 1, name: "Номер телефона", link: "/settings/phone"},
|
||||
{id: 2, name: "Пароль", link: "/settings/password"},
|
||||
{id: 3, name: "Настройки доступа", link: "/settings/admin"},
|
||||
]
|
||||
|
||||
export default class InnerMenu extends React.Component
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import React from "react";
|
||||
import * as ReactDOM from 'react-dom';
|
||||
import Head from 'next/head';
|
||||
import Image from 'next/image';
|
||||
import Link from "next/link";
|
||||
@ -43,6 +44,38 @@ class IndexPage extends React.Component
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount()
|
||||
{
|
||||
ReactDOM.findDOMNode(this).parentNode.style.height = "100%";
|
||||
ReactDOM.findDOMNode(this).parentNode.style.display = "flex";
|
||||
ReactDOM.findDOMNode(this).parentNode.style.flexDirection = "column";
|
||||
ReactDOM.findDOMNode(this).parentNode.style.justifyContent = "spaceBetween";
|
||||
ReactDOM.findDOMNode(this).parentNode.style.alignItems = "stretch";
|
||||
|
||||
document.documentElement.style.height = "100%";
|
||||
document.documentElement.style.display = "flex";
|
||||
document.documentElement.style.flexDirection = "column";
|
||||
document.body.style.height = "100%";
|
||||
document.body.style.display = "flex";
|
||||
document.body.style.flexDirection = "column";
|
||||
}
|
||||
|
||||
componentWillUnmount()
|
||||
{
|
||||
ReactDOM.findDOMNode(this).parentNode.style.height = "unset";
|
||||
ReactDOM.findDOMNode(this).parentNode.style.display = "unset";
|
||||
ReactDOM.findDOMNode(this).parentNode.style.flexDirection = "unset";
|
||||
ReactDOM.findDOMNode(this).parentNode.style.justifyContent = "unset";
|
||||
ReactDOM.findDOMNode(this).parentNode.style.alignItems = "unset";
|
||||
|
||||
document.documentElement.style.height = "unset";
|
||||
document.documentElement.style.display = "unset";
|
||||
document.documentElement.style.flexDirection = "unset";
|
||||
document.body.style.height = "unset";
|
||||
document.body.style.display = "unset";
|
||||
document.body.style.flexDirection = "unset";
|
||||
}
|
||||
|
||||
_handle_onPasswordSubmit = (event) =>
|
||||
{
|
||||
event.preventDefault();
|
||||
@ -130,7 +163,7 @@ class IndexPage extends React.Component
|
||||
/>
|
||||
</Head>
|
||||
<Header { ...this.props }/>
|
||||
<main>
|
||||
<main style={{ flex: 1, display: "flex", flexDirection: "column" }}>
|
||||
<section>
|
||||
<div className="clear"></div>
|
||||
<div className="container">
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import React from "react";
|
||||
import * as ReactDOM from 'react-dom';
|
||||
import Head from 'next/head';
|
||||
import Image from 'next/image';
|
||||
import Link from "next/link";
|
||||
@ -49,6 +50,38 @@ class IndexPage extends React.Component
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount()
|
||||
{
|
||||
ReactDOM.findDOMNode(this).parentNode.style.height = "100%";
|
||||
ReactDOM.findDOMNode(this).parentNode.style.display = "flex";
|
||||
ReactDOM.findDOMNode(this).parentNode.style.flexDirection = "column";
|
||||
ReactDOM.findDOMNode(this).parentNode.style.justifyContent = "spaceBetween";
|
||||
ReactDOM.findDOMNode(this).parentNode.style.alignItems = "stretch";
|
||||
|
||||
document.documentElement.style.height = "100%";
|
||||
document.documentElement.style.display = "flex";
|
||||
document.documentElement.style.flexDirection = "column";
|
||||
document.body.style.height = "100%";
|
||||
document.body.style.display = "flex";
|
||||
document.body.style.flexDirection = "column";
|
||||
}
|
||||
|
||||
componentWillUnmount()
|
||||
{
|
||||
ReactDOM.findDOMNode(this).parentNode.style.height = "unset";
|
||||
ReactDOM.findDOMNode(this).parentNode.style.display = "unset";
|
||||
ReactDOM.findDOMNode(this).parentNode.style.flexDirection = "unset";
|
||||
ReactDOM.findDOMNode(this).parentNode.style.justifyContent = "unset";
|
||||
ReactDOM.findDOMNode(this).parentNode.style.alignItems = "unset";
|
||||
|
||||
document.documentElement.style.height = "unset";
|
||||
document.documentElement.style.display = "unset";
|
||||
document.documentElement.style.flexDirection = "unset";
|
||||
document.body.style.height = "unset";
|
||||
document.body.style.display = "unset";
|
||||
document.body.style.flexDirection = "unset";
|
||||
}
|
||||
|
||||
_handle_onPhoneSubmit = (event) =>
|
||||
{
|
||||
event.preventDefault();
|
||||
@ -161,7 +194,7 @@ class IndexPage extends React.Component
|
||||
/>
|
||||
</Head>
|
||||
<Header { ...this.props }/>
|
||||
<main>
|
||||
<main style={{ flex: 1, display: "flex", flexDirection: "column" }}>
|
||||
<section>
|
||||
<div className="clear"></div>
|
||||
<div className="container">
|
||||
|
||||
252
pages/support/appeals.js
Normal file
252
pages/support/appeals.js
Normal file
@ -0,0 +1,252 @@
|
||||
import React from "react";
|
||||
import * as ReactDOM from 'react-dom';
|
||||
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 { reduxWrapper } from "../../store";
|
||||
|
||||
import Header from "../components/Header";
|
||||
import Footer from "../components/Footer";
|
||||
import Company from "../components/Company";
|
||||
import InnerMenu from "./components/InnerMenu";
|
||||
|
||||
import {
|
||||
getContractInfo,
|
||||
getContractAgreement,
|
||||
getContractRules,
|
||||
getFile,
|
||||
setAppealsRead,
|
||||
} from "../../actions";
|
||||
|
||||
class SupportAppealsPage extends React.Component
|
||||
{
|
||||
constructor(props)
|
||||
{
|
||||
super(props);
|
||||
this.state = {
|
||||
appeals: null,
|
||||
loading: false,
|
||||
};
|
||||
}
|
||||
|
||||
static getDerivedStateFromProps(nextProps, prevState)
|
||||
{
|
||||
return {
|
||||
appeals: nextProps.appeals,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount()
|
||||
{
|
||||
ReactDOM.findDOMNode(this).parentNode.style.height = "100%";
|
||||
ReactDOM.findDOMNode(this).parentNode.style.display = "flex";
|
||||
ReactDOM.findDOMNode(this).parentNode.style.flexDirection = "column";
|
||||
ReactDOM.findDOMNode(this).parentNode.style.justifyContent = "spaceBetween";
|
||||
ReactDOM.findDOMNode(this).parentNode.style.alignItems = "stretch";
|
||||
|
||||
document.documentElement.style.height = "100%";
|
||||
document.documentElement.style.display = "flex";
|
||||
document.documentElement.style.flexDirection = "column";
|
||||
document.body.style.height = "100%";
|
||||
document.body.style.display = "flex";
|
||||
document.body.style.flexDirection = "column";
|
||||
|
||||
setTimeout(() =>
|
||||
{
|
||||
const appeals = [];
|
||||
if(this.state.appeals !== undefined && this.state.appeals !== null && this.state.appeals.list !== undefined && this.state.appeals.list !== null)
|
||||
{
|
||||
for(let i in this.state.appeals.list)
|
||||
{
|
||||
if(this.state.appeals.list[i].read !== true)
|
||||
{
|
||||
appeals.push({ number: this.state.appeals.list[i].number, status: this.state.appeals.list[i].status });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log("appeals");
|
||||
console.log(appeals);
|
||||
|
||||
setAppealsRead({ dispatch: this.props.dispatch, appeals });
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
componentWillUnmount()
|
||||
{
|
||||
ReactDOM.findDOMNode(this).parentNode.style.height = "unset";
|
||||
ReactDOM.findDOMNode(this).parentNode.style.display = "unset";
|
||||
ReactDOM.findDOMNode(this).parentNode.style.flexDirection = "unset";
|
||||
ReactDOM.findDOMNode(this).parentNode.style.justifyContent = "unset";
|
||||
ReactDOM.findDOMNode(this).parentNode.style.alignItems = "unset";
|
||||
|
||||
document.documentElement.style.height = "unset";
|
||||
document.documentElement.style.display = "unset";
|
||||
document.documentElement.style.flexDirection = "unset";
|
||||
document.body.style.height = "unset";
|
||||
document.body.style.display = "unset";
|
||||
document.body.style.flexDirection = "unset";
|
||||
}
|
||||
|
||||
render()
|
||||
{
|
||||
const { loading, appeals } = this.state;
|
||||
const { number } = this.props;
|
||||
const status = {
|
||||
active: { title: "Активное", color: "#04A8A4" },
|
||||
closed: { title: "Закрыто", color: "#000", },
|
||||
cancelled: { title: "Отменено", color: "#A8026B", }
|
||||
};
|
||||
|
||||
console.log(appeals);
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Head>
|
||||
<title>ЛК Эволюция автолизинга</title>
|
||||
<meta name="description" content="ЛК Эволюция автолизинга" />
|
||||
</Head>
|
||||
<Header { ...this.props } />
|
||||
<main style={{ flex: 1, display: "flex", flexDirection: "column" }}>
|
||||
<section>
|
||||
<div className="clear"></div>
|
||||
<div className="container">
|
||||
<div className="title_wrapper">
|
||||
<div className="left" style={{ flexDirection: "column" }}>
|
||||
<h1 className="section_title">Мои обращения</h1>
|
||||
</div>
|
||||
<Company />
|
||||
</div>
|
||||
<div className="aside_container about">
|
||||
<InnerMenu { ...this.props } />
|
||||
<article>
|
||||
<div className="appeal_list">
|
||||
{ appeals !== undefined && appeals !== null && appeals.list !== undefined && appeals.list !== null && (
|
||||
<>
|
||||
{ appeals.list.length > 0 ? (
|
||||
<>
|
||||
{ appeals.list.map((appeal, index) =>
|
||||
(
|
||||
<div className="appeal_item" key={ index }>
|
||||
<div className="item_header">
|
||||
<p>Номер обращения: <b>{ appeal.number } от { moment(appeal.created_date, "YYYY-MM-DD").format("DD.MM.YYYY") }</b></p>
|
||||
<p>Отвественный ОРК: <b>{ appeal.owner }</b></p>
|
||||
<p>Договор(ы): <b>{ appeal.contracts }</b></p>
|
||||
<div className="status" style={{ backgroundColor: status[appeal.status].color }}>{ status[appeal.status].title }</div>
|
||||
</div>
|
||||
<div className="item_body">
|
||||
<div className="item_text">
|
||||
<p><b>Тема запроса</b></p>
|
||||
<p>{ appeal.subject }</p>
|
||||
</div>
|
||||
<div className="item_text">
|
||||
<p><b>Текст ответа ОРК</b></p>
|
||||
<p>{ appeal.answer === "" ? "Без ответа" : appeal.answer }</p>
|
||||
{ appeal.documents.length > 0 && (
|
||||
<div className="dosc_list medium-icon">
|
||||
{ appeal.documents.map((document, document_index) =>
|
||||
(
|
||||
<div className="row" key={ document_index }>
|
||||
<p className="doc_name i-pdf extension" data-format={ document.doc_extension }>
|
||||
{ document.doc_name }
|
||||
<span>Скачать документ</span>
|
||||
</p>
|
||||
</div>
|
||||
)) }
|
||||
</div>
|
||||
) }
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)) }
|
||||
</>
|
||||
) : (
|
||||
<p>У Вас пока нет обращений.</p>
|
||||
) }
|
||||
</>
|
||||
)}
|
||||
{/*}
|
||||
<div className="appeal_item">
|
||||
<div className="item_header">
|
||||
<p>Номер обращения: <b>123 от 13.04.2022</b></p>
|
||||
<p>Отвественный ОРК: <b>Иванов И.И.</b></p>
|
||||
<p>Договор: <b>№2021_1655, №2021_1655</b></p>
|
||||
<div className="status">Активное</div>
|
||||
</div>
|
||||
<div className="item_body">
|
||||
<div className="item_text">
|
||||
<p><b>Тема запроса</b></p>
|
||||
<p>Текстовый контент</p>
|
||||
</div>
|
||||
<div className="item_text">
|
||||
<p><b>Текст ответа ОРК</b></p>
|
||||
<p>Текстовый контент</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="appeal_item">
|
||||
<div className="item_header">
|
||||
<p>Номер обращения: <b>123 от 13.04.2022</b></p>
|
||||
<p>Отвественный ОРК: <b>Иванов И.И.</b></p>
|
||||
<p>Договор: <b>№2021_1655, №2021_1655</b></p>
|
||||
</div>
|
||||
<div className="item_body">
|
||||
<div className="item_text">
|
||||
<p><b>Тема запроса</b></p>
|
||||
<p>Текстовый контент</p>
|
||||
</div>
|
||||
<div className="item_text">
|
||||
<p><b>Текст ответа ОРК</b></p>
|
||||
<p>Текстовый контент</p>
|
||||
<div className="dosc_list medium-icon">
|
||||
<div className="row">
|
||||
<p className="doc_name i-pdf extension">
|
||||
№2021_1655 от 20.04.2021
|
||||
<span>2021_1655 от 20.04.2021</span>
|
||||
</p>
|
||||
</div>
|
||||
<div className="row">
|
||||
<p className="doc_name i-pdf extension">
|
||||
№2021_1655 от 20.04.2021
|
||||
<span>2021_1655 от 20.04.2021</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{*/}
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
<Footer />
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function mapStateToProps(state, ownProps)
|
||||
{
|
||||
return {
|
||||
appeals: state.support.appeals,
|
||||
};
|
||||
}
|
||||
|
||||
export const getServerSideProps = reduxWrapper.getServerSideProps(
|
||||
(store) =>
|
||||
async ({ req, res, query }) => {
|
||||
return {
|
||||
props: {
|
||||
},
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
export default withRouter(connect(mapStateToProps)(SupportAppealsPage));
|
||||
@ -1,14 +1,26 @@
|
||||
import React from "react";
|
||||
import Link from "next/link";
|
||||
import { connect } from "react-redux";
|
||||
|
||||
export default class InnerMenu extends React.Component
|
||||
class InnerMenu extends React.Component
|
||||
{
|
||||
constructor(props)
|
||||
{
|
||||
super(props);
|
||||
this.state = {
|
||||
appeals: 0,
|
||||
}
|
||||
|
||||
this.menuRef = React.createRef();
|
||||
}
|
||||
|
||||
static getDerivedStateFromProps(nextProps, prevState)
|
||||
{
|
||||
return {
|
||||
appeals: nextProps.appeals,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount()
|
||||
{
|
||||
let l = 0;
|
||||
@ -33,26 +45,25 @@ export default class InnerMenu extends React.Component
|
||||
|
||||
_handle_onNewAppeal = () =>
|
||||
{
|
||||
this.props.router.push('/support/new/');
|
||||
this.props.router.push('/support/request/');
|
||||
}
|
||||
|
||||
render()
|
||||
{
|
||||
const { appeals } = this.state;
|
||||
const { number } = this.props;
|
||||
|
||||
return (
|
||||
<aside className="flex">
|
||||
<button className="nav_toggle">
|
||||
Меню
|
||||
</button>
|
||||
<button className="nav_toggle">Меню</button>
|
||||
<ul className="aside_nav" ref={ this.menuRef }>
|
||||
<li>
|
||||
<Link href={`/support/faq`} shallow>
|
||||
<a className={ this.props.router && this.props.router.asPath.indexOf("faq") > -1 ? "active" : "" }>FAQ</a></Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href={`/support/messages`} shallow>
|
||||
<a className={ this.props.router && this.props.router.asPath.indexOf("messages") > -1 ? "active" : "" }>Мои обращения <span>3</span></a>
|
||||
<Link href={`/support/appeals`} shallow>
|
||||
<a className={ this.props.router && this.props.router.asPath.indexOf("appeals") > -1 ? "active" : "" }>Мои обращения { appeals > 0 && (<span>{ appeals }</span> ) }</a>
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
@ -60,4 +71,13 @@ export default class InnerMenu extends React.Component
|
||||
</aside>
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function mapStateToProps(state, ownProps)
|
||||
{
|
||||
return {
|
||||
appeals: state.support.appeals.new,
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(InnerMenu);
|
||||
@ -15,10 +15,6 @@ import Company from "../components/Company";
|
||||
import InnerMenu from "./components/InnerMenu";
|
||||
|
||||
import {
|
||||
getContractInfo,
|
||||
getContractAgreement,
|
||||
getContractRules,
|
||||
getFile,
|
||||
getSupportThemes,
|
||||
} from "../../actions";
|
||||
|
||||
@ -34,7 +30,7 @@ class ContractPage extends React.Component
|
||||
appeal: null,
|
||||
searched: null,
|
||||
loading: false,
|
||||
search: "",
|
||||
query: "",
|
||||
};
|
||||
}
|
||||
|
||||
@ -61,7 +57,7 @@ class ContractPage extends React.Component
|
||||
document.documentElement.style.flexDirection = "column";
|
||||
document.body.style.height = "100%";
|
||||
document.body.style.display = "flex";
|
||||
document.body.style.flexDirection = "column";
|
||||
document.body.style.flexDirection = "column";
|
||||
|
||||
if (!this.state.loading)
|
||||
{
|
||||
@ -105,12 +101,19 @@ class ContractPage extends React.Component
|
||||
}
|
||||
}
|
||||
|
||||
_handle_onRequest = (question) =>
|
||||
{
|
||||
this.props.router.push(`/support/request#${ question }`);
|
||||
}
|
||||
|
||||
_handle_onChangeSearchQuery = (value) =>
|
||||
{
|
||||
this.setState({ query: value });
|
||||
}
|
||||
|
||||
render()
|
||||
{
|
||||
const { loading, themes, question_selected, searched, appleals, search } = this.state;
|
||||
|
||||
console.log("themesthemesthemesthemesthemes");
|
||||
console.log(themes);
|
||||
const { loading, themes, question_selected, searched, appleals, query } = this.state;
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
@ -141,10 +144,10 @@ class ContractPage extends React.Component
|
||||
<div className="contract_search">
|
||||
<form onSubmit={(event) => { event.preventDefault(); }}>
|
||||
<div className="form_field full">
|
||||
<input type="search" value={ search } placeholder="Поиск" onChange={(event) => { this._handle_onChange_search(event.target.value);} }
|
||||
<input type="search" value={ query } placeholder="Поиск" onChange={(event) => { this._handle_onChangeSearchQuery(event.target.value);} }
|
||||
/>
|
||||
</div>
|
||||
<button className="button" disabled={ search !== "" ? false : true } onClick={ this._handle_onSearch }>
|
||||
<button className="button" disabled={ query !== "" ? false : true } onClick={ this._handle_onSearch }>
|
||||
Поиск
|
||||
</button>
|
||||
</form>
|
||||
@ -162,7 +165,7 @@ class ContractPage extends React.Component
|
||||
<p>{ question.title }</p>
|
||||
<button></button>
|
||||
</div>
|
||||
<div className="block_body">
|
||||
<div className="block_body" style={{ paddingBottom: "20px" }}>
|
||||
<div className="column full">
|
||||
<div className="column_text_block">
|
||||
<p><b>Процедура</b></p>
|
||||
@ -187,7 +190,7 @@ class ContractPage extends React.Component
|
||||
</div>
|
||||
</div>
|
||||
) }
|
||||
<button className="button button-blue">Создать обращение</button>
|
||||
<button className="button button-blue" onClick={ () => this._handle_onRequest(question.id) }>Создать обращение</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,217 +0,0 @@
|
||||
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 { reduxWrapper } from "../../store";
|
||||
|
||||
import Header from "../components/Header";
|
||||
import Footer from "../components/Footer";
|
||||
import Company from "../components/Company";
|
||||
import InnerMenu from "./components/InnerMenu";
|
||||
|
||||
import {
|
||||
getContractInfo,
|
||||
getContractAgreement,
|
||||
getContractRules,
|
||||
getFile,
|
||||
} from "../../actions";
|
||||
|
||||
class ContractPage extends React.Component
|
||||
{
|
||||
constructor(props)
|
||||
{
|
||||
super(props);
|
||||
this.state = {
|
||||
date: null,
|
||||
car: null,
|
||||
contract_date: null,
|
||||
agreement: null,
|
||||
rules: null,
|
||||
loading: false,
|
||||
};
|
||||
}
|
||||
|
||||
static getDerivedStateFromProps(nextProps, prevState)
|
||||
{
|
||||
return {
|
||||
date: nextProps.date,
|
||||
car: nextProps.car,
|
||||
contract_date: nextProps.contract_date,
|
||||
agreement: nextProps.agreement,
|
||||
rules: nextProps.rules,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {}
|
||||
|
||||
render()
|
||||
{
|
||||
const { loading, date, car, contract_date, agreement, rules } = this.state;
|
||||
const { number } = this.props;
|
||||
|
||||
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={{ flexDirection: "column" }}>
|
||||
<h1 className="section_title">Мои обращения</h1>
|
||||
</div>
|
||||
<Company />
|
||||
</div>
|
||||
<div className="aside_container about">
|
||||
<InnerMenu number={number} {...this.props} />
|
||||
<article>
|
||||
<div className="appeal_list">
|
||||
<div className="appeal_item">
|
||||
<div className="item_header">
|
||||
<p>
|
||||
Номер обращения: <b>123 от 13.04.2022</b>
|
||||
</p>
|
||||
<p>
|
||||
Отвественный ОРК: <b>Иванов И.И.</b>
|
||||
</p>
|
||||
<p>
|
||||
Договор: <b>№2021_1655, №2021_1655</b>
|
||||
</p>
|
||||
<div className="status">Активное</div>
|
||||
</div>
|
||||
<div className="item_body">
|
||||
<div className="item_text">
|
||||
<p>
|
||||
<b>Тема запроса</b>
|
||||
</p>
|
||||
<p>
|
||||
Текстовый контент Текстовый контент Текстовый
|
||||
контент Текстовый контент Текстовый контент
|
||||
Текстовый контент Текстовый контент Текстовый
|
||||
контент Текстовый контент Текстовый контент
|
||||
Текстовый контент Текстовый контент Текстовый
|
||||
контент Текстовый контент Текстовый контент
|
||||
Текстовый контент Текстовый контент Текстовый
|
||||
контент Текстовый контент
|
||||
</p>
|
||||
</div>
|
||||
<div className="item_text">
|
||||
<p>
|
||||
<b>Текст ответа ОРК</b>
|
||||
</p>
|
||||
<p>
|
||||
Текстовый контент Текстовый контент Текстовый
|
||||
контент Текстовый контент Текстовый контент
|
||||
Текстовый контент Текстовый контент Текстовый
|
||||
контент Текстовый контент Текстовый контент
|
||||
Текстовый контент Текстовый контент Текстовый
|
||||
контент Текстовый контент Текстовый контент
|
||||
Текстовый контент Текстовый контент Текстовый
|
||||
контент Текстовый контент
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="appeal_item">
|
||||
<div className="item_header">
|
||||
<p>
|
||||
Номер обращения: <b>123 от 13.04.2022</b>
|
||||
</p>
|
||||
<p>
|
||||
Отвественный ОРК: <b>Иванов И.И.</b>
|
||||
</p>
|
||||
<p>
|
||||
Договор: <b>№2021_1655, №2021_1655</b>
|
||||
</p>
|
||||
</div>
|
||||
<div className="item_body">
|
||||
<div className="item_text">
|
||||
<p>
|
||||
<b>Тема запроса</b>
|
||||
</p>
|
||||
<p>
|
||||
Текстовый контент Текстовый контент Текстовый
|
||||
контент Текстовый контент Текстовый контент
|
||||
Текстовый контент Текстовый контент Текстовый
|
||||
контент Текстовый контент Текстовый контент
|
||||
Текстовый контент Текстовый контент Текстовый
|
||||
контент Текстовый контент Текстовый контент
|
||||
Текстовый контент Текстовый контент Текстовый
|
||||
контент Текстовый контент
|
||||
</p>
|
||||
</div>
|
||||
<div className="item_text">
|
||||
<p>
|
||||
<b>Текст ответа ОРК</b>
|
||||
</p>
|
||||
<p>
|
||||
Текстовый контент Текстовый контент Текстовый
|
||||
контент Текстовый контент Текстовый контент
|
||||
Текстовый контент Текстовый контент Текстовый
|
||||
контент Текстовый контент Текстовый контент
|
||||
Текстовый контент Текстовый контент Текстовый
|
||||
контент Текстовый контент Текстовый контент
|
||||
Текстовый контент Текстовый контент Текстовый
|
||||
контент Текстовый контент
|
||||
</p>
|
||||
<div className="dosc_list medium-icon">
|
||||
<div className="row">
|
||||
<p className="doc_name i-pdf extension">
|
||||
№2021_1655 от 20.04.2021
|
||||
<span>2021_1655 от 20.04.2021</span>
|
||||
</p>
|
||||
</div>
|
||||
<div className="row">
|
||||
<p className="doc_name i-pdf extension">
|
||||
№2021_1655 от 20.04.2021
|
||||
<span>2021_1655 от 20.04.2021</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
<Footer />
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function mapStateToProps(state, ownProps)
|
||||
{
|
||||
return {
|
||||
contract_date: state.contract.date,
|
||||
date: state.contract.date,
|
||||
car: state.contract.car,
|
||||
agreement: state.contract.agreement,
|
||||
rules: state.contract.rules,
|
||||
};
|
||||
}
|
||||
|
||||
export const getServerSideProps = reduxWrapper.getServerSideProps(
|
||||
(store) =>
|
||||
async ({ req, res, query }) => {
|
||||
return {
|
||||
props: {
|
||||
//number: query.number,
|
||||
number: null,
|
||||
},
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
export default withRouter(connect(mapStateToProps)(ContractPage));
|
||||
@ -1,219 +0,0 @@
|
||||
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 { reduxWrapper } from "../../store";
|
||||
|
||||
import Header from "../components/Header";
|
||||
import Footer from "../components/Footer";
|
||||
import Company from "../components/Company";
|
||||
import InnerMenu from "./components/InnerMenu";
|
||||
|
||||
import {
|
||||
getContractInfo,
|
||||
getContractAgreement,
|
||||
getContractRules,
|
||||
getFile,
|
||||
} from "../../actions";
|
||||
|
||||
class ContractPage extends React.Component
|
||||
{
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
date: null,
|
||||
car: null,
|
||||
contract_date: null,
|
||||
agreement: null,
|
||||
rules: null,
|
||||
loading: false,
|
||||
};
|
||||
}
|
||||
|
||||
static getDerivedStateFromProps(nextProps, prevState)
|
||||
{
|
||||
return {
|
||||
date: nextProps.date,
|
||||
car: nextProps.car,
|
||||
contract_date: nextProps.contract_date,
|
||||
agreement: nextProps.agreement,
|
||||
rules: nextProps.rules,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {}
|
||||
|
||||
_handle_onBack = () =>
|
||||
{
|
||||
this.props.router.push('/support/faq/');
|
||||
}
|
||||
|
||||
render()
|
||||
{
|
||||
const { loading, date, car, contract_date, agreement, rules } = this.state;
|
||||
const { number } = this.props;
|
||||
|
||||
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 />
|
||||
</div>
|
||||
<div className="aside_container about">
|
||||
<article className="full">
|
||||
<div className="new_appeal">
|
||||
<div className="column">
|
||||
<div className="dropdown_blocks_list appeal_list visible">
|
||||
<div className="appeal_item dropdown_block">
|
||||
<div className="block_header">
|
||||
<p>
|
||||
Процедура досрочного прекращения срока действия
|
||||
договора лизинга
|
||||
</p>
|
||||
<button className="rotate"></button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="appeal_item dropdown_block">
|
||||
<div className="block_header">
|
||||
<p>
|
||||
Как изменить график платежей по договору лизинга?
|
||||
</p>
|
||||
<button className="rotate"></button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="appeal_item dropdown_block">
|
||||
<div className="block_header">
|
||||
<p>Как получить консультацию по Цессии?</p>
|
||||
<button className="rotate"></button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="appeal_item dropdown_block open">
|
||||
<div className="block_header">
|
||||
<p>
|
||||
Оформление переуступки прав и обязательств по
|
||||
договору лизинга
|
||||
</p>
|
||||
<button className="rotate"></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="column">
|
||||
<div className="column_text_block">
|
||||
<p>
|
||||
<b>Процедура</b>
|
||||
</p>
|
||||
<p>
|
||||
К каждой теме свободное html поле для миниинструкции
|
||||
(со ссылками на <a>формы документов</a> и{" "}
|
||||
<a>документы</a>). Привязка к теме обращения в CRM
|
||||
</p>
|
||||
</div>
|
||||
<div className="column_text_block">
|
||||
<p>
|
||||
<b>Документы</b>
|
||||
</p>
|
||||
<div className="dosc_list medium-icon">
|
||||
<div className="row">
|
||||
<p className="doc_name i-pdf extension">
|
||||
№2021_1655 от 20.04.2021
|
||||
<span>2021_1655 от 20.04.2021</span>
|
||||
</p>
|
||||
</div>
|
||||
<div className="row">
|
||||
<p className="doc_name i-pdf extension">
|
||||
№2021_1655 от 20.04.2021
|
||||
<span>2021_1655 от 20.04.2021</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<form>
|
||||
<div className="form_field">
|
||||
<select>
|
||||
<option default selected disabled>
|
||||
Выберите договоры
|
||||
</option>
|
||||
<option>Договор 1</option>
|
||||
</select>
|
||||
</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="Введите текст запроса"></textarea>
|
||||
</div>
|
||||
<div className="file_upload dropzone">
|
||||
<div className="files"></div>
|
||||
<div>
|
||||
<p data-sm-text="Выберите файлы">
|
||||
<span>Перенесите файлы на экран для быстрой загрузки или выберите файл с компьютера </span>
|
||||
</p>
|
||||
<label htmlFor="" className="button button-blue">Загрузить файл</label>
|
||||
</div>
|
||||
<input type="file" accept="" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
<Footer />
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function mapStateToProps(state, ownProps)
|
||||
{
|
||||
return {
|
||||
contract_date: state.contract.date,
|
||||
date: state.contract.date,
|
||||
car: state.contract.car,
|
||||
agreement: state.contract.agreement,
|
||||
rules: state.contract.rules,
|
||||
};
|
||||
}
|
||||
|
||||
export const getServerSideProps = reduxWrapper.getServerSideProps(
|
||||
(store) =>
|
||||
async ({ req, res, query }) => {
|
||||
return {
|
||||
props: {
|
||||
//number: query.number,
|
||||
number: null,
|
||||
},
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
export default withRouter(connect(mapStateToProps)(ContractPage));
|
||||
270
pages/support/request.js
Normal file
270
pages/support/request.js
Normal file
@ -0,0 +1,270 @@
|
||||
import React from "react";
|
||||
import * as ReactDOM from 'react-dom';
|
||||
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 { reduxWrapper } from "../../store";
|
||||
|
||||
import Header from "../components/Header";
|
||||
import Footer from "../components/Footer";
|
||||
import Company from "../components/Company";
|
||||
import InnerMenu from "./components/InnerMenu";
|
||||
|
||||
import {
|
||||
getSupportThemes,
|
||||
getContractsList,
|
||||
} from "../../actions";
|
||||
|
||||
class SupportRequestPage extends React.Component
|
||||
{
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
loading: false,
|
||||
contracts: null,
|
||||
themes: null,
|
||||
name: "",
|
||||
phone: "",
|
||||
email: "",
|
||||
question: "",
|
||||
file: null,
|
||||
opened_theme: 0,
|
||||
opened_question: 0,
|
||||
};
|
||||
}
|
||||
|
||||
static getDerivedStateFromProps(nextProps, prevState)
|
||||
{
|
||||
return {
|
||||
contracts: nextProps.contracts,
|
||||
themes: nextProps.themes,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount()
|
||||
{
|
||||
console.log("CDM", "SupportRequestPage", this.state);
|
||||
|
||||
ReactDOM.findDOMNode(this).parentNode.style.height = "100%";
|
||||
ReactDOM.findDOMNode(this).parentNode.style.display = "flex";
|
||||
ReactDOM.findDOMNode(this).parentNode.style.flexDirection = "column";
|
||||
ReactDOM.findDOMNode(this).parentNode.style.justifyContent = "spaceBetween";
|
||||
ReactDOM.findDOMNode(this).parentNode.style.alignItems = "stretch";
|
||||
|
||||
document.documentElement.style.height = "100%";
|
||||
document.documentElement.style.display = "flex";
|
||||
document.documentElement.style.flexDirection = "column";
|
||||
document.body.style.height = "100%";
|
||||
document.body.style.display = "flex";
|
||||
document.body.style.flexDirection = "column";
|
||||
|
||||
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(() => {});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount()
|
||||
{
|
||||
ReactDOM.findDOMNode(this).parentNode.style.height = "unset";
|
||||
ReactDOM.findDOMNode(this).parentNode.style.display = "unset";
|
||||
ReactDOM.findDOMNode(this).parentNode.style.flexDirection = "unset";
|
||||
ReactDOM.findDOMNode(this).parentNode.style.justifyContent = "unset";
|
||||
ReactDOM.findDOMNode(this).parentNode.style.alignItems = "unset";
|
||||
|
||||
document.documentElement.style.height = "unset";
|
||||
document.documentElement.style.display = "unset";
|
||||
document.documentElement.style.flexDirection = "unset";
|
||||
document.body.style.height = "unset";
|
||||
document.body.style.display = "unset";
|
||||
document.body.style.flexDirection = "unset";
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps, prevState)
|
||||
{
|
||||
}
|
||||
|
||||
_handle_onBack = () =>
|
||||
{
|
||||
this.props.router.push('/support/faq/');
|
||||
}
|
||||
|
||||
_handle_onChangeTheme = (index) =>
|
||||
{
|
||||
this.setState({ opened_theme: index, opened_question: 0 });
|
||||
}
|
||||
|
||||
_handle_onSelectContracts = (event) =>
|
||||
{
|
||||
}
|
||||
|
||||
_renderForm = () =>
|
||||
{
|
||||
const { loading, contracts, themes, name, phone, email, question, file, opened_theme, opened_question } = this.state;
|
||||
|
||||
return (
|
||||
<form>
|
||||
<div className="form_field">
|
||||
<select multiple={ false } onChange={ this._handle_onSelectContracts }>
|
||||
<option default selected disabled>Выберите договоры</option>
|
||||
{ contracts !== undefined && contracts !== null && contracts.map((contract, index) => (
|
||||
<option index={ index } value={ contract.number }>{ contract.number }</option>
|
||||
)) }
|
||||
</select>
|
||||
</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="Введите текст запроса"></textarea>
|
||||
</div>
|
||||
<div className="file_upload dropzone">
|
||||
<div className="files"></div>
|
||||
<div>
|
||||
<p data-sm-text="Выберите файлы">
|
||||
<span>Перенесите файлы на экран для быстрой загрузки или выберите файл с компьютера </span>
|
||||
</p>
|
||||
<label htmlFor="" className="button button-blue">Загрузить файл</label>
|
||||
</div>
|
||||
<input type="file" accept="" />
|
||||
</div>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
|
||||
render()
|
||||
{
|
||||
const { loading, themes, opened_theme, opened_question } = this.state;
|
||||
const { number } = this.props;
|
||||
|
||||
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 style={{ flex: 1, display: "flex", flexDirection: "column" }}>
|
||||
<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 />
|
||||
</div>
|
||||
<div className="aside_container about">
|
||||
<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) =>
|
||||
(
|
||||
<div className="row" key={ `template_${ index }` }>
|
||||
<p className="doc_name i-pdf extension" data-format={ template.extension }>{ template.filename }<span>Скачать шаблон</span></p>
|
||||
</div>
|
||||
)) }
|
||||
</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));
|
||||
@ -73,7 +73,7 @@ export const defaultState = {
|
||||
{
|
||||
themes: null,
|
||||
searched: null,
|
||||
appeals: null,
|
||||
appeals: { list: null, new: 0 },
|
||||
appeal: null,
|
||||
request: null,
|
||||
}
|
||||
|
||||
@ -35,7 +35,7 @@ const supportReducer = (state = initialState.support, action) =>
|
||||
{
|
||||
return {
|
||||
...state,
|
||||
appeals: action.data.appeals,
|
||||
appeals: { ...state.appeals, ...action.data.appeals, },
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user