calendar connected

This commit is contained in:
merelendor 2021-11-25 12:43:03 +01:00
parent 528ac065d9
commit d29a1f68ad
35 changed files with 4565 additions and 1082 deletions

View File

@ -155,4 +155,20 @@ export const sendLoginFormPhone = (fields) =>
});
*/
});
}
}
export const logout = ({ dispatch }) =>
{
return new Promise((resolve, reject) =>
{
const cookies = new Cookies();
cookies.remove('jwt');
dispatch({ type: actionTypes.AUTH, data: { logged: false } });
dispatch({ type: actionTypes.USER, data: {} });
dispatch({ type: actionTypes.COMPANY, data: {} });
resolve();
Router.push('/');
});
}

View File

@ -0,0 +1,87 @@
import axios from 'axios';
import { Cookies } from 'react-cookie';
import Router from 'next/router';
import moment from 'moment';
import { nSQL } from "@nano-sql/core";
import { concatSeries } from "async";
import * as actionTypes from '../constants/actionTypes';
import * as currentState from '../reducers/initialState';
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 getCalendar = ({ dispatch, date_from, date_to }) =>
{
console.log("getCalendar");
return new Promise((resolve, reject) =>
{
axios.post(`${ process.env.NEXT_PUBLIC_SELF_API_HOST }/api/calendar`, {},
{
withCredentials: true,
})
.then((response) =>
{
const periods = {};
concatSeries(response.data, (contract, callback) =>
{
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() } });
}
let query = nSQL(payments)
.query("select")
.where([ [ "js_date", ">=", date_from ], "AND", [ "js_date", "<=", date_to ] ])
.orderBy("number", "asc")
.exec().then((rows) =>
{
callback(null, rows);
});
}, (error, result) =>
{
let calendar = [];
nSQL(result)
.query("select", ["date", "SUM(total_amount) AS total"])
.groupBy(["date ASC"])
.exec().then(async (grouped_rows) =>
{
for(let i in grouped_rows)
{
const payments = await nSQL(result).query("select").where([[ "date", "=", grouped_rows[i].date ]]).exec();
calendar.push({ ...grouped_rows[i], ...{ payments: payments }});
}
console.log("TOTAL calendar", calendar);
dispatch({ type: actionTypes.CALENDAR, data: { payments: calendar, periods: periods } });
});
});
resolve();
})
.catch((error) =>
{
console.error(error);
reject();
});
});
}

View File

@ -0,0 +1,51 @@
import axios from 'axios';
import { Cookies } from 'react-cookie';
import Router from 'next/router';
import moment from 'moment';
import { nSQL } from "@nano-sql/core";
import * as actionTypes from '../constants/actionTypes';
import * as currentState from '../reducers/initialState';
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 getContract = ({ dispatch, number, }) =>
{
return new Promise((resolve, reject) =>
{
axios.post(`${ process.env.NEXT_PUBLIC_SELF_API_HOST }/api/contract`, {
number: number
},
{
withCredentials: true,
})
.then((response) =>
{
console.log("response.data");
console.log(response.data);
dispatch({ type: actionTypes.CONTRACT, data: response.data });
resolve();
})
.catch((error) =>
{
console.error(error);
reject();
});
});
}

View File

@ -2,6 +2,7 @@ import axios from 'axios';
import { Cookies } from 'react-cookie';
import Router from 'next/router';
import moment from 'moment';
import { nSQL } from "@nano-sql/core";
import * as actionTypes from '../constants/actionTypes';
import * as currentState from '../reducers/initialState';
@ -22,22 +23,62 @@ if(process.browser)
};
}
export const getContractsList = ({ query, date_from, date_to }) =>
export const getContractsList = ({ dispatch, order = "date", sort = "desc", page = 1, search, date_from, date_to }) =>
{
const page_size = 5;
return new Promise((resolve, reject) =>
{
let cookies = new Cookies();
let cookies_list = cookies.getAll();
console.log(cookies_list);
//let cookies = new Cookies();
//let cookies_list = cookies.getAll();
axios.post(`${ process.env.NEXT_PUBLIC_SELF_API_HOST }/api/contracts`, {}, {
//headers: {
// "Authorization": `Bearer ${ cookies_list.jwt }`,
//},
withCredentials: true,
});
})
.then((response) =>
{
const orderBy = {};
orderBy[order] = sort;
const offset = (page - 1) * page_size;
resolve();
let query = nSQL(response.data).query("select");
let query_total = nSQL(response.data).query("select", ["COUNT(*) AS total"]);
if(search !== undefined && search !== null && search !== "")
{
query = query.where([["number", "LIKE", `%${ search }%`], "OR", ["car.reg_number", "LIKE", `%${ search }%`], "OR", ["car.vin_number", "LIKE", `%${ search }%`]]);
query_total = query_total.where([["number", "LIKE", `%${ search }%`], "OR", ["car.reg_number", "LIKE", `%${ search }%`], "OR", ["car.vin_number", "LIKE", `%${ search }%`]])
}
/*
if(date_from !== undefined && date_from !== null && date_from !== "")
{
query = query.where([["date", ">=", `%${ date_from }%`]]);
query_total = query_total.where([["date", ">=", `%${ date_from }%`]])
}
*/
query = query.orderBy(orderBy).limit(page_size).offset(offset);
query_total.exec().then((total_rows) =>
{
const total = total_rows[0].total;
console.log("total", total);
query.exec().then((rows) =>
{
console.log(rows); // <= [{name: "jeb", age: 27}]
dispatch({ type: actionTypes.CONTRACTS, data: { list: rows, page: page, pages: Math.ceil(total / page_size) } });
});
});
resolve();
})
.catch((error) =>
{
console.error(error);
reject();
});
/*
axios.post(`${ process.env.NEXT_PUBLIC_API_HOST }/api/account/contracts/`, { }, {

View File

@ -1,2 +1,4 @@
export * from './authActions';
export * from './contractsActions';
export * from './contractsActions';
export * from './contractActions';
export * from './calendarActions';

View File

@ -2,4 +2,5 @@ export const AUTH = 'AUTH';
export const USER = 'USER';
export const COMPANY = 'COMPANY';
export const CONTRACTS = 'CONTRACTS';
export const CONTRACT = 'CONTRACT';
export const CALENDAR = 'CALENDAR';

File diff suppressed because one or more lines are too long

View File

@ -2445,6 +2445,12 @@ main {
margin-left: 6px;
background: url("/assets/images/icons/icon-select.svg") no-repeat center;
}
&.reverse {
&:after {
transform: scaleY(-1);
}
}
}
}
}

32
lib/cors.js Normal file
View File

@ -0,0 +1,32 @@
import Cors from 'cors';
function initMiddleware(middleware)
{
console.log("CORS initMiddleware !!!!");
return (req, res) =>
new Promise((resolve, reject) =>
{
middleware(req, res, (result) =>
{
if (result instanceof Error)
{
return reject(result);
}
return resolve(result);
});
});
}
// Initialize the cors middleware
const cors = initMiddleware(
// You can read more about the available options here: https://github.com/expressjs/cors#configuration-options
Cors({
origin: ["http://localhost:3000", "https://lk-evo.quickcode.ru"],
// Only allow requests with GET, POST and OPTIONS
methods: ['GET', 'POST', 'OPTIONS'],
})
)
export { cors };

View File

@ -9,8 +9,11 @@
"lint": "next lint"
},
"dependencies": {
"@nano-sql/core": "^2.3.7",
"async": "^3.2.2",
"axios": "^0.24.0",
"cookie": "^0.4.1",
"cors": "^2.8.5",
"jsonwebtoken": "^8.5.1",
"moment": "^2.29.1",
"next": "11.1.2",

View File

@ -1,6 +1,62 @@
// 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 { cors } from '../../lib/cors';
export default function handler(req, res)
export default async function handler(req, res)
{
res.status(200).json({ name: 'John Doe' });
await cors(req, res);
if(req.headers.cookie !== undefined)
{
const cookies = cookie.parse(req.headers?.cookie ? req.headers?.cookie : "");
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);
console.log(`URL`);
console.log(`${ process.env.CRM_API_HOST }/lk/Account/GetPaymentCalendar/`);
try
{
axios.get(`${ process.env.CRM_API_HOST }/lk/Account/GetPaymentCalendar/`, {
params: client_jwt_decoded,
headers: {
"Authorization": `Bearer ${ crm_jwt }`,
}
})
.then((crm_response) =>
{
console.log("crm_response");
console.log(crm_response);
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,65 @@
// 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 { 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);
console.log(`${ process.env.CRM_API_HOST }/lk/Contract/GetSchedulePayments`);
try
{
axios.get(`${ process.env.CRM_API_HOST }/lk/Contract/GetSchedulePayments`, {
params: { ...client_jwt_decoded, contract_number: req.body.number },
headers: {
"Authorization": `Bearer ${ crm_jwt }`,
},
withCredentials: true,
})
.then((crm_response) =>
{
console.log("crm_response");
console.log(crm_response);
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,75 @@
// 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 { 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);
console.log(`${ process.env.CRM_API_HOST }/lk/Contract/GetOsago`);
const result = {
osago: null,
kasko: null,
nsib: null,
};
Promise.all([
new Promise((resolve) => {
axios.get(`${ process.env.CRM_API_HOST }/lk/Contract/GetOsago`, {
params: client_jwt_decoded,
headers: { "Authorization": `Bearer ${ crm_jwt }`, },
})
.then((crm_response) => { result.osago = crm_response; resolve(); })
.catch((error) => { console.error(error); resolve(); });
}),
new Promise((resolve) => {
axios.get(`${ process.env.CRM_API_HOST }/lk/Contract/GetKasko`, {
params: client_jwt_decoded,
headers: { "Authorization": `Bearer ${ crm_jwt }`, },
})
.then((crm_response) => { result.kasko = crm_response; resolve(); })
.catch((error) => { console.error(error); resolve(); });
}),
new Promise((resolve) => {
axios.get(`${ process.env.CRM_API_HOST }/lk/Contract/GetNsib`, {
params: client_jwt_decoded,
headers: { "Authorization": `Bearer ${ crm_jwt }`, },
})
.then((crm_response) => { result.nsib = crm_response; resolve(); })
.catch((error) => { console.error(error); resolve(); });
}),
])
.then(() =>
{
res.status(200).json(result);
});
}
else
{
res.status(403);
}
}
}

View File

@ -4,9 +4,12 @@ import { Cookies } from 'react-cookie';
import cookie from 'cookie';
import moment from 'moment';
import jwt from 'jsonwebtoken';
import { cors } from '../../lib/cors';
export default function handler(req, res)
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 : "");
@ -22,6 +25,7 @@ export default function handler(req, res)
console.log("client_jwt_decoded", client_jwt_decoded);
console.log("crm_jwt", crm_jwt);
console.log(`URL`);
console.log(`${ process.env.CRM_API_HOST }/lk/Account/GetContracts/`);
try
@ -30,25 +34,25 @@ export default function handler(req, res)
params: client_jwt_decoded,
headers: {
"Authorization": `Bearer ${ crm_jwt }`,
},
withCredentials: true,
}
})
.then((crm_response) =>
{
console.log("crm_response");
console.log(crm_response);
//console.log(crm_response);
res.status(200).json(crm_response.data);
})
.catch((error) =>
{
console.error(error);
res.status(500);
});
}
catch(e)
{
console.error(e);
res.status(500);
}
res.status(200).json({ name: 'John Doe' });
}
else
{

View File

@ -1,402 +0,0 @@
import React, { Component } from "react";
import Head from "next/head";
import Image from "next/image";
import Header from "./components/Header";
import Footer from "./components/Footer";
import CalendarCellModal from "./components/Modal/calendar";
class CalendarPage extends Component {
constructor(props) {
super(props);
this.state = {
cellModalOpen: false
};
}
handle_cell_click = () => {
this.setState({
cellModalOpen: !this.state.cellModalOpen
});
};
close_cell_modal = () => {
this.setState({
cellModalOpen: false
});
}
render() {
return (
<React.Fragment>
<Head>
<title>ЛК Эволюция автолизинга</title>
<meta name="description" content="ЛК Эволюция автолизинга" />
</Head>
<Header />
<main>
<section>
<div className="clear"></div>
<div className="container">
<div className="title_wrapper">
<div className="left">
<h1 className="section_title">Календарь оплат</h1>
</div>
<div className="right">
<p align="right">
<b>ООО Друзья и КО</b>
<br />
ИНН: 12345678765 КПП: 13432-02
</p>
</div>
</div>
<div className="aside_container about">
<aside>
<ul className="aside_nav">
<li>
<a href="#" className="active">
Календарь оплат
</a>
</li>
<li>
<a href="#">Акты сверок</a>
</li>
<li>
<a href="#">Закрывающие документы</a>
</li>
</ul>
</aside>
<article>
<div className="calendar_wrapper">
<div className="form_field">
<select id="calendar_month">
<option selected="">Июнь</option>
</select>
</div>
<div className="calendar_nav">
<button>Предыдущая неделя</button>
<button>Следующая неделя</button>
</div>
<div className="calendar_grid">
<div className="grid_header">
<div className="grid_cell">Пн</div>
<div className="grid_cell">Вт</div>
<div className="grid_cell">Ср</div>
<div className="grid_cell">Чт</div>
<div className="grid_cell">Пт</div>
<div className="grid_cell">Сб</div>
<div className="grid_cell">Вс</div>
</div>
<div className="grid_body">
<div className="grid_week active">
<div className="grid_cell disabled">
<div className="cell_header">
<p>
<span>30</span> мая
</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell disabled">
<div className="cell_header">
<p>
<span>31</span> мая
</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell">
<div className="cell_header">
<p>
<span>31</span> мая
</p>
</div>
<div className="cell_body">
<p>
Общий платеж
<span>239 400,00 р.</span>
</p>
</div>
</div>
<div className="grid_cell">
<div className="cell_header">
<p>
<span>02</span> июня
</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell current" onClick={() => this.handle_cell_click()}>
<div className="cell_header">
<p>
<span>02</span> июня
</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell">
<div className="cell_header">
<p>
<span>02</span> июня
</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell">
<div className="cell_header">
<p>
<span>02</span> июня
</p>
</div>
<div className="cell_body"></div>
</div>
</div>
<div className="grid_week">
<div className="grid_cell current">
<div className="cell_header">
<p>
<span>03</span> июня
</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell">
<div className="cell_header">
<p>
<span>04</span> июня
</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell">
<div className="cell_header">
<p>
<span>05</span> июня
</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell">
<div className="cell_header">
<p>
<span>30</span> мая
</p>
</div>
<div className="cell_body"></div>
</div>
</div>
<div className="grid_week">
<div className="grid_cell">
<div className="cell_header">
<p>
<span>31</span> мая
</p>
</div>
<div className="cell_body">
<p>
Общий платеж
<span>239 400,00 р.</span>
</p>
</div>
</div>
<div className="grid_cell">
<div className="cell_header">
<p>
<span>01</span> июня
</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell">
<div className="cell_header">
<p>
<span>02</span> июня
</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell">
<div className="cell_header">
<p>
<span>03</span> июня
</p>
</div>
<div className="cell_body"></div>
</div>
</div>
<div className="grid_week">
<div className="grid_cell">
<div className="cell_header">
<p>
<span>04</span> июня
</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell">
<div className="cell_header">
<p>
<span>05</span> июня
</p>
</div>
<div className="cell_body"></div>
</div>
</div>
<div className="grid_week">
<div className="grid_cell disabled">
<div className="cell_header">
<p>
<span>30</span> мая
</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell disabled">
<div className="cell_header">
<p>
<span>31</span> мая
</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell">
<div className="cell_header">
<p>
<span>01</span> июня
</p>
</div>
<div className="cell_body"></div>
</div>
</div>
<div className="grid_week">
<div className="grid_cell disabled">
<div className="cell_header">
<p>
<span>30</span> мая
</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell disabled">
<div className="cell_header">
<p>
<span>31</span> мая
</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell">
<div className="cell_header">
<p>
<span>01</span> июня
</p>
</div>
<div className="cell_body"></div>
</div>
</div>
<div className="grid_week">
<div className="grid_cell disabled">
<div className="cell_header">
<p>
<span>30</span> мая
</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell disabled">
<div className="cell_header">
<p>
<span>31</span> мая
</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell">
<div className="cell_header">
<p>
<span>01</span> июня
</p>
</div>
<div className="cell_body"></div>
</div>
</div>
</div>
</div>
</div>
</article>
</div>
</div>
</section>
<CalendarCellModal open = {this.state.cellModalOpen} close = {this.close_cell_modal} />
<section id="order">
<div className="container wide">
<h2 className="section_title">Купить в лизинг?</h2>
<div className="order_form">
<div className="order_email">
<p>
Напишите на <a href="mailto:">buy@domain.ru</a> или
заполните форму
</p>
</div>
<form>
<div className="form_field">
<input type="text" value="" placeholder="Имя" />
</div>
<div className="form_field">
<input type="tel" value="" placeholder="Телефон" />
</div>
<div className="form_field">
<input type="email" value="" placeholder="E-mail" />
</div>
<div className="form_field">
<input type="text" value="" placeholder="Организация" />
</div>
<div className="policy">
<input
type="checkbox"
name="policy"
id="policy"
hidden
checked
/>
<label for="policy">
Даю свое согласие на обработку моих персональных данных
</label>
</div>
<button className="button">Отправить</button>
</form>
</div>
</div>
</section>
</main>
<Footer />
</React.Fragment>
);
}
}
export default CalendarPage;

View File

@ -49,7 +49,7 @@ export default class Header extends React.Component
</Link>
</li>
<li>
<Link href="/documents/schedule/">
<Link href="/documents/calendar/">
<a className={ this.props.router && this.props.router.route.indexOf("/documents/") === 0 ? "active" : "" }>Взаиморасчеты и закрывающие документы</a>
</Link>
</li>

View File

@ -1,68 +1,69 @@
import React, { Component } from "react";
import Link from "next/link";
import numeral from "numeral";
class CalendarCellModal extends Component {
constructor(props) {
super(props);
this.state = {
menuOpened: false,
activeLink: ""
};
}
class CalendarCellModal extends Component
{
constructor(props)
{
super(props);
this.state = {
menuOpened: false,
activeLink: ""
};
}
toggleMenu = () => {
this.setState({
menuOpened: !this.state.menuOpened
});
};
toggleMenu = () => {
this.setState({
menuOpened: !this.state.menuOpened
});
};
selected = (text) => {
this.toggleMenu();
this.setState({
activeLink: text
})
}
render() {
const {menuOpened, activeLink} = this.state;
return (
<div className={this.props.open ? "fade opened" : "fade"}>
<div className="modal">
<div className="calendar_payment">
<div className="day">
<span>16</span>
июня
</div>
<div className="payment_table">
<div className="table_row table_header">
<div className="table_cell">Договор</div>
<div className="table_cell">Платеж</div>
</div>
<div className="table_row">
<div className="table_cell">
<a href="#">1234/2021 от 10.01.2021</a>
</div>
<div className="table_cell">
<b>139 400,00 р.</b>
</div>
</div>
<div className="table_row">
<div className="table_cell">
<a href="#">1234/2021 от 10.01.2021</a>
</div>
<div className="table_cell">
<b>139 400,00 р.</b>
</div>
</div>
</div>
</div>
selected = (text) => {
this.toggleMenu();
this.setState({
activeLink: text
})
}
<div className="modal_footer">
<button className="button button-blue" onClick={() => this.props.close()}>Закрыть</button>
</div>
</div>
</div>
);
}
render()
{
const {menuOpened, activeLink} = this.state;
const { selected_payment } = this.props;
return (
<div className={this.props.open ? "fade opened" : "fade"}>
<div className="modal">
<div className="calendar_payment">
<div className="day">
<span>16</span> июня
</div>
<div className="payment_table">
<div className="table_row table_header">
<div className="table_cell">Договор</div>
<div className="table_cell">Платеж</div>
</div>
{ selected_payment && selected_payment.payments.map((payment, index) => (
<div className="table_row" key={ index }>
<div className="table_cell">
<Link href={`/contract/${ payment.contract.number }/payments`}>
<a>{ payment.contract.number } от { payment.contract.date }</a>
</Link>
</div>
<div className="table_cell">
<b>{ numeral(payment.total_amount).format('') } р.</b>
</div>
</div>
)) }
</div>
</div>
<div className="modal_footer">
<button className="button button-blue" onClick={() => this.props.close()}>Закрыть</button>
</div>
</div>
</div>
);
}
}
export default CalendarCellModal;

View File

@ -0,0 +1,126 @@
import React, { Component } from "react";
import Image from "next/image";
import Link from "next/link";
import moment from "moment";
class NewsCard extends Component
{
constructor(props)
{
super(props);
this.state = {
};
}
_onPagePress = (page) =>
{
this.props.onPagePress(page);
}
_renderPageNumber = (page, p, index) =>
{
return (
<li key={ index } style={ p === page ? { fontWeight: "bold" } : {} }>
<a onClick={ () => p === page ? {} : this.props.onPage(p) }>{ p }</a>
</li>
)
}
render()
{
const { pages } = this.props;
let page = this.props.page;
if(page < 0) { page = pages; }
let firstPage = 1;
let lastPage = pages;
if(lastPage <= 1)
{
return null;
}
let pagesLinks = [];
let p = page;
if(lastPage > 6)
{
if(p === lastPage)
{
p = p - 3;
}
else
{
if(p <= 3) { p = p - (p-1); };
if(p > 3) { p = p - 1; }
//if(p > (lastPage - 3)) { p = p - 4; }
if(p > (lastPage - 3))
{
p = p - (lastPage - (p+1));
}
}
}
if(lastPage > 6)
{
for(let i = 0; i < 7; i++)
{
if(i == 0)
{
pagesLinks.push(this._renderPageNumber(page, firstPage, i));
}
else if(i == 1)
{
if(p >= 3)
{
pagesLinks.push(<li key={i}>...</li>);
}
else
{
if(p > 1)
{
pagesLinks.push(this._renderPageNumber(page, p, i));
}
p++;
}
}
else if(i == 5)
{
if(p < (lastPage))
{
pagesLinks.push(<li key={i}>...</li>);
}
}
else if(i == 6)
{
pagesLinks.push(this._renderPageNumber(page, lastPage, i));
}
else
{
pagesLinks.push(this._renderPageNumber(page, p, i));
p++;
}
}
}
else
{
for(let i = 0; i < lastPage; i++)
{
pagesLinks.push(this._renderPageNumber(page, i+1, i));
}
}
return (
<div className="pagination">
<ul>
{ page !== 1 && (<li><a style={{ cursor: "pointer" }} onClick={ () => this.props.onPage(page - 1) }>{`<`}</a></li>) }
{ pagesLinks }
{ page < pages && (<li><a style={{ cursor: "pointer" }} onClick={ () => this.props.onPage(page + 1) }>{`>`}</a></li>) }
</ul>
</div>
)
}
}
export default NewsCard;

View File

@ -19,6 +19,8 @@ class ContractPage extends React.Component
render()
{
const { number } = this.props;
return (
<React.Fragment>
<Head>
@ -31,57 +33,57 @@ class ContractPage extends React.Component
<Header { ...this.props }/>
<main>
<section>
<div class="clear"></div>
<div class="container">
<div class="title_wrapper">
<div class="left">
<h1 class="section_title">Договор 1234/2021 от 10.01.2021</h1>
<div className="clear"></div>
<div className="container">
<div className="title_wrapper">
<div className="left">
<h1 className="section_title">Договор { number.replace("_", "/") } от 10.01.2021</h1>
</div>
<Company/>
</div>
<div class="aside_container about">
<InnerMenu number={ "1234-2021" } { ...this.props }/>
<div className="aside_container about">
<InnerMenu number={ number } { ...this.props }/>
<article>
<div class="dosc_list">
<div class="row">
<p class="doc_name i-pdf">
<div className="dosc_list">
<div className="row">
<p className="doc_name i-pdf">
Договор
<span>Краткое описание. Может быть много-много строк.
Столько строк, сколько есть в описании</span>
</p>
<a href="#" class="button button-blue">Скачать</a>
<a href="#" className="button button-blue">Скачать</a>
</div>
<div class="row">
<p class="doc_name i-pdf">
<div className="row">
<p className="doc_name i-pdf">
Договор цессии
<span>Краткое описание. Может быть много-много строк.
Столько строк, сколько есть в описании</span>
</p>
<a href="#" class="button button-blue">Скачать</a>
<a href="#" className="button button-blue">Скачать</a>
</div>
<div class="row">
<p class="doc_name i-pdf">
<div className="row">
<p className="doc_name i-pdf">
Дополнительное соглашение 1
<span>Краткое описание. Может быть много-много строк.
Столько строк, сколько есть в описании</span>
</p>
<a href="#" class="button button-blue">Скачать</a>
<a href="#" className="button button-blue">Скачать</a>
</div>
<div class="row">
<p class="doc_name i-pdf">
<div className="row">
<p className="doc_name i-pdf">
Дополнительное соглашение 2
<span>Краткое описание. Может быть много-много строк.
Столько строк, сколько есть в описании</span>
</p>
<a href="#" class="button button-blue">Скачать</a>
<a href="#" className="button button-blue">Скачать</a>
</div>
<div class="row">
<p class="doc_name i-pdf">
<div className="row">
<p className="doc_name i-pdf">
Выкупные документы
<span>Краткое описание. Может быть много-много строк.
Столько строк, сколько есть в описании</span>
</p>
<a href="#" class="button button-blue">Скачать</a>
<a href="#" className="button button-blue">Скачать</a>
</div>
</div>
</article>
@ -106,6 +108,11 @@ function mapStateToProps(state, ownProps)
export const getServerSideProps = reduxWrapper.getServerSideProps(store =>
async ({ req, res, query }) =>
{
return {
props: {
number: query.number,
}
}
}
);

View File

@ -10,12 +10,17 @@ import Footer from '../components/Footer';
import InnerMenu from "./components/InnerMenu";
import Company from "../components/Company";
class ContractDocumentsPage extends React.Component {
constructor(props) {
class ContractDocumentsPage extends React.Component
{
constructor(props)
{
super(props);
}
render() {
render()
{
const { number } = this.props;
return (
<React.Fragment>
<Head>
@ -32,12 +37,12 @@ class ContractDocumentsPage extends React.Component {
<div className="container">
<div className="title_wrapper">
<div className="left">
<h1 className="section_title">Договор 1234/2021 от 10.01.2021</h1>
<h1 className="section_title">Договор { number.replace("_", "/") } от 10.01.2021</h1>
</div>
<Company />
</div>
<div className="aside_container about">
<InnerMenu number={"1234-2021"} {...this.props} />
<InnerMenu number={ number } {...this.props} />
<article>
<div className="reconciliation_form">
<p>Акт сверки</p>
@ -117,7 +122,8 @@ class ContractDocumentsPage extends React.Component {
}
}
function mapStateToProps(state, ownProps) {
function mapStateToProps(state, ownProps)
{
return {
company: state.company,
schedule: state.payments,
@ -125,7 +131,13 @@ function mapStateToProps(state, ownProps) {
}
export const getServerSideProps = reduxWrapper.getServerSideProps(store =>
async ({ req, res, query }) => {
async ({ req, res, query }) =>
{
return {
props: {
number: query.number,
}
}
}
);

View File

@ -10,15 +10,81 @@ import Footer from '../components/Footer';
import Company from "../components/Company";
import InnerMenu from "./components/InnerMenu";
import { getContract } from './../../actions';
import numeral from "numeral";
import moment from "moment";
class ContractSchedulePage extends React.Component
{
constructor(props)
{
super(props);
this.state = {
loading: false,
contract: null,
full: false,
opened: [],
}
}
static getDerivedStateFromProps(nextProps, prevState)
{
return {
contract: nextProps.contract,
};
}
componentDidMount()
{
console.log("this.props");
console.log(this.props);
if(!this.state.loading && this.props.number !== undefined)
{
console.log("this.props.number", this.props.number);
this.setState({ loading: true }, () =>
{
getContract({ dispatch: this.props.dispatch, number: this.props.number }).then(() => {
this.setState({ loading: false });
}).catch(() => {});
});
}
}
_handle_onSetFull = () =>
{
this.setState({ full: true });
}
_handle_onSetOpen = (number) =>
{
const opened = [ ...this.state.opened ];
if(opened.indexOf(number) < 0)
{ opened.push(number); }
else
{ opened.splice(opened.indexOf(number), 1); }
this.setState({ opened: opened });
}
render()
{
const { contract, full, opened } = this.state;
const { number } = this.props;
console.log("RENDER", "contact");
console.log(contract);
const statuses = {
"NotPaid": "",
"HalfPaid": "overpayment-1",
"OverPaid": "overpayment-2",
"Paid": "paid",
};
let today = moment();
return (
<React.Fragment>
<Head>
@ -35,23 +101,55 @@ class ContractSchedulePage extends React.Component
<div className="container">
<div className="title_wrapper">
<div className="left">
<h1 className="section_title">Договор 1234/2021 от 10.01.2021</h1>
<h1 className="section_title">Договор { number.replace("_", "/") }{/* от 10.01.2021*/}</h1>
</div>
<Company/>
</div>
<div className="aside_container about">
<InnerMenu number={ "1234-2021" } { ...this.props }/>
<InnerMenu number={ number } { ...this.props }/>
<article>
<div className="contract_table schedule">
<div className="table_row table_header">
<div className="table_cell caret"> платежа</div>
<div className="table_cell caret">Дата лизингового платежа</div>
<div className="table_cell caret">Лизинговый платеж с НДС (рубли)</div>
<div className="table_cell caret">НДС, 20% (рубли)</div>
<div className="table_cell"> платежа</div>
<div className="table_cell">Дата лизингового платежа</div>
<div className="table_cell">Лизинговый платеж с НДС (рубли)</div>
<div className="table_cell">НДС, 20% (рубли)</div>
<div className="table_cell">Статус платежа</div>
<div className="table_cell">Платежное поручение</div>
</div>
<button className="show_more primary">Показать прошедшие платежи</button>
{ !full && (
<button className="show_more primary" onClick={ this._handle_onSetFull }>Показать прошедшие платежи</button>
) }
{ contract !== null && Object.values(contract).map((payment, index) =>
{
let pd = moment(payment.date, "DD-MM-YYYY");
if(!full && today > pd) { return null; }
return (
<div className={ `table_row ${ opened.indexOf(payment.number) > -1 ? "opened" : "" }` } data-status={ statuses[payment.status] } key={ index }>
<div className="table_cell" data-title="Платеж №">{ payment.number }</div>
<div className="table_cell" data-title="от">{ moment(payment.date, "DD-MM-YYYY").format("DD.MM.YYYY") }</div>
<div className="table_cell" data-title="На сумму">{ numeral(payment.total_amount).format('') }</div>
<div className="table_cell" data-title="НДС, 20% ₽">{ numeral(payment.vat_amount).format('') }</div>
{ payment.status === "NotPaid" && (
<div className="table_cell">Не оплачено</div>
) }
{ payment.status === "HalfPaid" && (
<div className="table_cell">Частично оплачено</div>
) }
{ payment.status === "OverPaid" && (
<div className="table_cell"><span>Переплата</span> <span>{ numeral(payment.total_amount).format('') } </span></div>
) }
<div className="table_cell">
{ payment.invoices.map((invoice, invoice_index) =>
(
<span key={ invoice_index }>{ invoice.number } от { moment(invoice.date, "DD-MM-YYYY").format("DD.MM.YYYY") } на сумму { numeral(invoice.total_amount).format('') } </span>
)) }
</div>
<button className="toggle_cell" onClick={ () => this._handle_onSetOpen(payment.number) }></button>
</div>
)})}
{/*}
<div className="table_row" data-status="overpayment-2">
<div className="table_cell" data-title="Платеж №">11</div>
<div className="table_cell" data-title="от">21.02.2021</div>
@ -93,6 +191,7 @@ class ContractSchedulePage extends React.Component
<button className="toggle_cell"></button>
</div>
{*/}
</div>
</article>
</div>
@ -109,13 +208,19 @@ function mapStateToProps(state, ownProps)
{
return {
company: state.company,
schedule: state.payments,
contract: state.contract,
//schedule: state.payments,
}
}
export const getServerSideProps = reduxWrapper.getServerSideProps(store =>
async ({ req, res, query }) =>
{
return {
props: {
number: query.number,
}
}
}
);

View File

@ -38,6 +38,7 @@ class ContractServicesPage extends React.Component
render()
{
const { opened } = this.state;
const { number } = this.props;
return (
<React.Fragment>
@ -55,16 +56,16 @@ class ContractServicesPage extends React.Component
<div className="container">
<div className="title_wrapper">
<div className="left">
<h1 className="section_title">Договор 1234/2021 от 10.01.2021</h1>
<h1 className="section_title">Договор { number.replace("_", "/") } от 10.01.2021</h1>
</div>
<Company/>
</div>
<div className="aside_container about">
<InnerMenu number={ "1234-2021" } { ...this.props }/>
<InnerMenu number={ number } { ...this.props }/>
<article>
<div className="dropdown_blocks_list filled zero-margin">
<div class={`dropdown_block ${ opened.indexOf("ratcard") > -1 ? 'open' : '' }`}>
<div className={`dropdown_block ${ opened.indexOf("ratcard") > -1 ? 'open' : '' }`}>
<div className="block_header" onClick={ () => this._handle_onCard('ratcard') }>
<p className="with-icon">
<img src="/assets/images/lk/additional-1.svg" alt="Карта РАТ" width="32px" height="32px" />
@ -83,7 +84,7 @@ class ContractServicesPage extends React.Component
</div>
</div>
<div class={`dropdown_block ${ opened.indexOf("insurance") > -1 ? 'open' : '' }`}>
<div className={`dropdown_block ${ opened.indexOf("insurance") > -1 ? 'open' : '' }`}>
<div className="block_header" onClick={ () => this._handle_onCard('insurance') }>
<p className="with-icon">
<img src="/assets/images/lk/additional-2.svg" alt="Страхование" width="32px" height="32px" />
@ -107,7 +108,7 @@ class ContractServicesPage extends React.Component
</div>
</div>
<div class={`dropdown_block ${ opened.indexOf("registration") > -1 ? 'open' : '' }`}>
<div className={`dropdown_block ${ opened.indexOf("registration") > -1 ? 'open' : '' }`}>
<div className="block_header" onClick={ () => this._handle_onCard('registration') }>
<p className="with-icon">
<img src="/assets/images/lk/additional-3.svg" alt="Регистрация" width="32px" height="32px" />
@ -120,7 +121,7 @@ class ContractServicesPage extends React.Component
</div>
</div>
<div class={`dropdown_block ${ opened.indexOf("telematic") > -1 ? 'open' : '' }`}>
<div className={`dropdown_block ${ opened.indexOf("telematic") > -1 ? 'open' : '' }`}>
<div className="block_header" onClick={ () => this._handle_onCard('telematic') }>
<p className="with-icon">
<img src="/assets/images/lk/additional-4.svg" alt="Телематика" width="32px" height="32px" />
@ -163,6 +164,11 @@ function mapStateToProps(state, ownProps)
export const getServerSideProps = reduxWrapper.getServerSideProps(store =>
async ({ req, res, query }) =>
{
return {
props: {
number: query.number,
}
}
}
);

384
pages/documents/calendar.js Normal file
View File

@ -0,0 +1,384 @@
import React from "react";
import Head from 'next/head';
import Image from 'next/image';
import moment from 'moment';
import 'moment/locale/ru';
import numeral from "numeral";
import cookie from 'cookie';
import { connect } from "react-redux";
import { withRouter } from 'next/router';
import { reduxWrapper } from '../../store';
import Header from '../components/Header';
import Footer from '../components/Footer';
import InnerMenu from "./components/InnerMenu";
import Company from "../components/Company";
import CalendarCellModal from "../components/Modal/calendar";
import { getCalendar } from '../../actions';
class CalendarPage extends React.Component
{
constructor(props)
{
super(props);
this.state = {
modalOpened: false,
payments: null,
periods: null,
selected_period: moment().format("YYYYMM"),
selected_payment: undefined,
};
}
static getDerivedStateFromProps(nextProps, prevState)
{
return {
company: nextProps.company,
payments: nextProps.payments,
periods: nextProps.periods,
};
}
componentDidMount()
{
const date_from = moment().startOf("month").toDate();
const date_to = moment().endOf("month").toDate();
getCalendar({ dispatch: this.props.dispatch, date_from, date_to }).then().catch();
}
toggleModal = () =>
{
this.setState({
modalOpened: !this.state.modalOpened
})
}
getPayments = (date) =>
{
const { payments } = this.state;
for(let i in payments)
{
if(payments[i].date === date)
{
return payments[i];
}
}
return undefined;
}
_handle_onDayClick = (day) =>
{
this.setState({ selected_payment: day.payment });
this.toggleModal();
}
_handle_onChangePeriod = (period) =>
{
this.setState({ selected_period: period }, () =>
{
const date_from = moment(period, "YYYYMM").startOf("month").toDate();
const date_to = moment(period, "YYYYMM").endOf("month").toDate();
getCalendar({ dispatch: this.props.dispatch, date_from, date_to }).then().catch();
});
}
render()
{
const { selected_period, selected_payment, periods, payments } = this.state;
if(payments === null) { return null; }
let month = moment(selected_period, "YYYYMM").format("M") - 1;
//console.log("periodsperiodsperiodsperiodsperiods");
//console.log(periods);
const dates = [];
const date_sm = moment(selected_period, 'YYYYMM').startOf("month");
const date_em = moment(selected_period, 'YYYYMM').endOf("month");
//console.log("date_sm", date_sm.format("YYYY-MM-DD"));
//console.log("date_em", date_em.format("YYYY-MM-DD"));
//console.log("date_sm.day()", date_sm.day());
//console.log("date_em.day()", date_em.day());
let date_s = null;
if(date_sm.day() !== 1)
{ date_s = date_sm.subtract(date_sm.day() - 1, "days"); }
else
{ date_s = date_sm; }
let date_e = null;
if(date_em.day() !== 0)
{ date_e = date_em.add(7 - date_em.day(), "days"); }
else
{ date_e = date_em; }
const date = moment();
//console.log(date_sm.format("YYYY-MM-DD"));
//console.log(date_sm.day());
//console.log("date_s", date_s.format("YYYY-MM-DD"))
//console.log("date_e", date_e.format("YYYY-MM-DD"))
let d = date_s;
let payment = this.getPayments(date_s.format("YYYY-MM-DD"));
dates.push({
date: date_s.clone(),
payment: payment,
});
while(d.add(1, 'days').diff(date_e) < 0)
{
//console.log(d.toDate());
let payment = this.getPayments(d.format("YYYY-MM-DD"));
dates.push({
date: d.clone(),
payment: payment,
});
}
const dow = date.day();
//console.log(dow);
//console.log("date.month())", date.month());
const weeks = dates.reduce(function(result, value, index, array) {
if (index % 7 === 0)
result.push(array.slice(index, index +7));
return result;
}, []);
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">
<h1 className="section_title">Календарь оплат</h1>
</div>
<Company/>
</div>
<div className="aside_container about">
<InnerMenu { ...this.props }/>
<article>
<div className="calendar_wrapper">
<div className="form_field">
<select id="calendar_month" defaultValue={ selected_period } onChange={ (event) => this._handle_onChangePeriod(event.target.value) }>
{ periods !== null && Object.values(periods).map((period, index) => (
<option key={ index } value={ period }>{ moment(period, "YYYYMM").format('MMMM YYYY') }</option>
)) }
</select>
</div>
<div className="calendar_nav">
<button>Предыдущая неделя</button>
<button>Следующая неделя</button>
</div>
<div className="calendar_grid">
<div className="grid_header">
<div className="grid_cell">Пн</div>
<div className="grid_cell">Вт</div>
<div className="grid_cell">Ср</div>
<div className="grid_cell">Чт</div>
<div className="grid_cell">Пт</div>
<div className="grid_cell">Сб</div>
<div className="grid_cell">Вс</div>
</div>
<div className="grid_body">
{ weeks.map((week, index) =>
{
return (
<div className={index == 0 ? "grid_week active" : "grid_week"} key={"week_" + index}>
{ week.map((day, index) => {
return (
<div key={ index } className={`grid_cell ${ day.date.month() !== month ? 'disabled' : '' } ${ day.date.format("YYYYMMDD") === moment().format("YYYYMMDD") ? 'current' : '' } `}>
<div className="cell_header">
<p><span>{ day.date.format("DD") }</span> { day.date.format("MMM").toLocaleLowerCase() } { day.date.format("Y").toLocaleLowerCase() }</p>
</div>
<div className="cell_body">{ day.payment && (
<p onClick={ () => this._handle_onDayClick(day) }>
Общий платеж
<span>{ numeral(day.payment.total).format('') } р.</span>
</p>
)}
</div>
</div>
)
}) }
</div>
)
}) }
{/*}
<div className="grid_cell disabled">
<div className="cell_header">
<p><span>30</span> мая</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell disabled">
<div className="cell_header">
<p><span>31</span> мая</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell">
<div className="cell_header">
<p><span>01</span> июня</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell">
<div className="cell_header">
<p><span>02</span> июня</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell current">
<div className="cell_header">
<p><span>03</span> июня</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell">
<div className="cell_header">
<p><span>04</span> июня</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell">
<div className="cell_header">
<p><span>05</span> июня</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell">
<div className="cell_header">
<p><span>30</span> мая</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell">
<div className="cell_header">
<p><span>31</span> мая</p>
</div>
<div className="cell_body">
<p>
Общий платеж
<span>239 400,00 р.</span>
</p>
</div>
</div>
<div className="grid_cell">
<div className="cell_header">
<p><span>01</span> июня</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell">
<div className="cell_header">
<p><span>02</span> июня</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell">
<div className="cell_header">
<p><span>03</span> июня</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell">
<div className="cell_header">
<p><span>04</span> июня</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell">
<div className="cell_header">
<p><span>05</span> июня</p>
</div>
<div className="cell_body"></div>
</div>
{*/}
</div>
</div>
</div>
</article>
</div>
</div>
</section>
<CalendarCellModal open={ this.state.modalOpened } selected_payment={ selected_payment } close={ () => this.toggleModal() }/>
</main>
<Footer/>
</React.Fragment>
)
}
}
function mapStateToProps(state, ownProps)
{
return {
company: state.company,
payments: state.calendar.payments,
periods: state.calendar.periods,
}
}
export const getServerSideProps = reduxWrapper.getServerSideProps(store =>
async ({ req, res, query }) =>
{
let props = {};
if(req.headers.cookie !== undefined)
{
const cookies = cookie.parse(req.headers?.cookie ? req.headers?.cookie : "");
if(cookies.jwt === undefined || cookies.jwt === null)
{
res.statusCode = 302;
res.setHeader('Location', `/login`);
}
else
{
const tokenValid = true;
if(!tokenValid)
{
res.statusCode = 302;
res.setHeader('Location', `/login`);
}
}
}
else
{
res.statusCode = 302;
res.setHeader('Location', `/login`);
}
return { props: props };
}
);
export default withRouter(connect(mapStateToProps)(CalendarPage));

View File

@ -14,8 +14,8 @@ export default class InnerMenu extends React.Component
<aside>
<ul className="aside_nav">
<li>
<Link href="/documents/schedule/">
<a className={ this.props.router && this.props.router.route === "/documents/schedule" ? "active" : "" }>Календарь оплат</a>
<Link href="/documents/calendar/">
<a className={ this.props.router && this.props.router.route === "/documents/calendar" ? "active" : "" }>Календарь оплат</a>
</Link>
</li>
<li>

View File

@ -1,315 +0,0 @@
import React from "react";
import Head from 'next/head';
import Image from 'next/image';
import moment from 'moment';
import 'moment/locale/ru';
import numeral from "numeral";
import { connect } from "react-redux";
import { withRouter } from 'next/router';
import { reduxWrapper } from '../../store';
import Header from '../components/Header';
import Footer from '../components/Footer';
import InnerMenu from "./components/InnerMenu";
import Company from "../components/Company";
import CalendarCellModal from "../components/Modal/calendar";
class SchedulePage extends React.Component
{
constructor(props)
{
super(props);
this.state = {
modalOpened: false,
payments: [{
date: "2021-11-15",
total: 128000.22,
}, {
date: "2021-11-25",
total: 239400.88,
}]
};
}
toggleModal = () => {
this.setState({
modalOpened: !this.state.modalOpened
})
}
getPayments = (date) =>
{
const { payments } = this.state;
for(let i in payments)
{
if(payments[i].date === date)
{
return payments[i].total;
}
}
return undefined;
}
render()
{
let month = 10;
const dates = [];
const date_sm = moment().month(month).startOf("month");
const date_em = moment().month(month).endOf("month");
console.log("date_sm", date_sm.format("YYYY-MM-DD"));
console.log("date_em", date_em.format("YYYY-MM-DD"));
console.log("date_sm.day()", date_sm.day());
console.log("date_em.day()", date_em.day());
let date_s = null;
if(date_sm.day() !== 1)
{ date_s = date_sm.subtract(date_sm.day() - 1, "days"); }
else
{ date_s = date_sm; }
let date_e = null;
if(date_em.day() !== 0)
{ date_e = date_em.add(7 - date_em.day(), "days"); }
else
{ date_e = date_em; }
const date = moment();
console.log(date_sm.format("YYYY-MM-DD"));
console.log(date_sm.day());
console.log("date_s", date_s.format("YYYY-MM-DD"))
console.log("date_e", date_e.format("YYYY-MM-DD"))
let d = date_s;
dates.push({
date: date_s.clone(),
payment: this.getPayments(date_s.format("YYYY-MM-DD")),
});
while(d.add(1, 'days').diff(date_e) < 0)
{
//console.log(d.toDate());
dates.push({
date: d.clone(),
payment: this.getPayments(d.format("YYYY-MM-DD")),
});
}
const dow = date.day();
console.log(dow);
console.log("date.month())", date.month());
const weeks = dates.reduce(function(result, value, index, array) {
if (index % 7 === 0)
result.push(array.slice(index, index +7));
return result;
}, []);
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">
<h1 className="section_title">Календарь оплат</h1>
</div>
<Company/>
</div>
<div className="aside_container about">
<InnerMenu { ...this.props }/>
<article>
<div className="calendar_wrapper">
<div className="form_field">
<select id="calendar_month">
<option selected>{ moment().month(month).format('MMMM') }</option>
</select>
</div>
<div className="calendar_nav">
<button>Предыдущая неделя</button>
<button>Следующая неделя</button>
</div>
<div className="calendar_grid">
<div className="grid_header">
<div className="grid_cell">Пн</div>
<div className="grid_cell">Вт</div>
<div className="grid_cell">Ср</div>
<div className="grid_cell">Чт</div>
<div className="grid_cell">Пт</div>
<div className="grid_cell">Сб</div>
<div className="grid_cell">Вс</div>
</div>
<div className="grid_body">
{ weeks.map((week, index) => {
return (
<div className={index == 0 ? "grid_week active" : "grid_week"} key={"week_" + index}>
{ week.map((day, index) => {
return (
<div key={ index } className={`grid_cell ${ day.date.month() !== month ? 'disabled' : '' }`}>
<div className="cell_header">
<p><span>{ day.date.format("DD") }</span> { day.date.format("MMM").toLocaleLowerCase() } { day.date.format("Y").toLocaleLowerCase() }</p>
</div>
<div className="cell_body">{ day.payment && (
<p onClick={() => this.toggleModal()}>
Общий платеж
<span>{ numeral(day.payment).format('') } р.</span>
</p>
)}
</div>
</div>
)
}) }
</div>
)
}) }
{/*}
<div className="grid_cell disabled">
<div className="cell_header">
<p><span>30</span> мая</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell disabled">
<div className="cell_header">
<p><span>31</span> мая</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell">
<div className="cell_header">
<p><span>01</span> июня</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell">
<div className="cell_header">
<p><span>02</span> июня</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell current">
<div className="cell_header">
<p><span>03</span> июня</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell">
<div className="cell_header">
<p><span>04</span> июня</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell">
<div className="cell_header">
<p><span>05</span> июня</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell">
<div className="cell_header">
<p><span>30</span> мая</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell">
<div className="cell_header">
<p><span>31</span> мая</p>
</div>
<div className="cell_body">
<p>
Общий платеж
<span>239 400,00 р.</span>
</p>
</div>
</div>
<div className="grid_cell">
<div className="cell_header">
<p><span>01</span> июня</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell">
<div className="cell_header">
<p><span>02</span> июня</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell">
<div className="cell_header">
<p><span>03</span> июня</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell">
<div className="cell_header">
<p><span>04</span> июня</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell">
<div className="cell_header">
<p><span>05</span> июня</p>
</div>
<div className="cell_body"></div>
</div>
{*/}
</div>
</div>
</div>
</article>
</div>
</div>
</section>
<CalendarCellModal open = {this.state.modalOpened} close = {() => this.toggleModal()}/>
</main>
<Footer/>
</React.Fragment>
)
}
}
function mapStateToProps(state, ownProps)
{
return {
company: state.company,
schedule: state.payments,
}
}
export const getServerSideProps = reduxWrapper.getServerSideProps(store =>
async ({ req, res, query }) =>
{
}
);
export default withRouter(connect(mapStateToProps)(SchedulePage));

View File

@ -4,11 +4,14 @@ import Image from 'next/image';
import Link from "next/link";
import cookie from 'cookie';
import { connect } from "react-redux";
import numeral from "numeral";
import { withRouter } from 'next/router';
import { reduxWrapper } from '../store';
import Header from './components/Header';
import Footer from './components/Footer';
import Pagination from './components/Pagination';
import { getContractsList } from '../actions';
@ -19,24 +22,117 @@ class IndexPage extends React.Component
super(props);
this.state = {
contracts: null,
sort_number: "desc",
sort_date: "desc",
sort_status: "desc",
search: "",
date_from: undefined,
date_from_type: "text",
date_to: undefined,
date_to_type: "text",
loading: false,
page: 1,
pages: 1,
};
}
getContractsList
static getDerivedStateFromProps(nextProps, prevState)
{
return {
company: nextProps.company,
contracts: nextProps.contracts,
page: nextProps.page,
pages: nextProps.pages,
};
}
componentDidMount()
{
getContractsList({}).then(() => {}).catch(() => {});
this.setState({ loading: true }, () =>
{
getContractsList({ dispatch: this.props.dispatch }).then(() => {
this.setState({ loading: false });
}).catch(() => {});
});
}
_handle_onChange_search = (value) =>
{
this.setState({ search: value });
}
_handle_onChange_date_from = (value) =>
{
this.setState({ date_from: value });
}
_handle_onChange_date_to = (value) =>
{
this.setState({ date_to: value });
}
_handle_onChangeSort_number = () =>
{
this.setState({ loading: true, sort_number: this.state.sort_number === "desc" ? "asc" : "desc" }, () =>
{
getContractsList({ dispatch: this.props.dispatch, order: "number", sort: this.state.sort_number, }).then(() => {
this.setState({ loading: false });
}).catch(() => {});
});
}
_handle_onChangeSort_date = () =>
{
this.setState({ loading: true, sort_date: this.state.sort_date === "desc" ? "asc" : "desc" }, () =>
{
getContractsList({ dispatch: this.props.dispatch, order: "date", sort: this.state.sort_date, }).then(() => {
this.setState({ loading: false });
}).catch(() => {});
});
}
_handle_onChangeSort_status = () =>
{
this.setState({ loading: true, sort_status: this.state.sort_status === "desc" ? "asc" : "desc" }, () =>
{
getContractsList({ dispatch: this.props.dispatch, order: "status", sort: this.state.sort_status, }).then(() => {
this.setState({ loading: false });
}).catch(() => {});
});
}
_handle_onPage = (page) =>
{
const { sort_number, sort_status, search, date_from, date_to, } = this.state;
this.setState({ loading: true, }, () =>
{
getContractsList({ dispatch: this.props.dispatch, sort_number, sort_status, search, date_from, date_to, page, }).then(() => {
this.setState({ loading: false });
}).catch(() => {});
});
}
_handle_onSearch = () =>
{
const { search, date_from, date_to, } = this.state;
this.setState({ loading: true, }, () =>
{
getContractsList({ dispatch: this.props.dispatch, search, date_from, date_to, }).then(() => {
this.setState({ loading: false });
}).catch(() => {});
});
}
render()
{
const { loading, page, pages, search, date_from, date_from_type, date_to, date_to_type, contracts, sort_number, sort_date, sort_status } = this.state;
const contract_status = {
"Действующий": "opened",
"Закрыт": "closed",
};
return (
<React.Fragment>
<Head>
@ -53,45 +149,67 @@ class IndexPage extends React.Component
<div className="container">
<h1 className="section_title">Личный кабинет</h1>
<div className="contract_search">
<form>
<form onSubmit={ (event) => { event.preventDefault(); } }>
<div className="form_field">
<input type="search" value="" placeholder="Поиск" onChange={ () => {} }/>
<input type="search" value={ search } placeholder="Поиск" onChange={ (event) => {
this._handle_onChange_search(event.target.value);
} }/>
</div>
<div className="form_field">
<input type="text" id="date_from" className="date_input" value="1" placeholder="Дата договора от" onFocus={ () => { /*(this.type='date')*/ } } onBlur={ () => { /*(this.value == '' ? this.type='text' : this.type='date')*/ } } onChange={ () => {} }/>
<input type={ date_from_type } id="date_from" className="date_input" value="" placeholder="Дата договора от" onFocus={ () => this.setState({ date_from_type: "date" }) } onBlur={ () => { this.setState({ date_from_type: "text" }) } } onChange={ (date) => {
this._handle_onChange_date_from(date);
} }/>
<label htmlFor="date_from">Дата<br/>договора от</label>
</div>
<div className="form_field">
<input type="text" id="date_for" className="date_input" value="" placeholder="Дата договора по" onFocus={ () => { /*(this.type='date')*/ } } onBlur={ () => { /*(this.value == '' ? this.type='text' : this.type='date')*/ } } onChange={ () => {} }/>
<input type={ date_to_type } id="date_for" className="date_input" value="" placeholder="Дата договора по" onFocus={ () => this.setState({ date_from_type: "date" }) } onBlur={ () => { this.setState({ date_from_type: "text" }) } } onChange={ (date) => {
this._handle_onChange_date_to(date);
} }/>
<label htmlFor="date_for">Дата<br/>договора по</label>
</div>
<button className="button" disabled>Поиск</button>
<button className="button" disabled={ search !== "" || date_from !== "" || date_to !== "" ? false : true } onClick={ this._handle_onSearch }>Поиск</button>
</form>
</div>
<div className="contract_table">
<div className="contract_table" style={ loading ? { opacity: 0.6 } : {} }>
<div className="table_row table_header">
<div className="table_cell caret">Номер договора</div>
<div className="table_cell caret">Дата договора</div>
<div className={`table_cell caret ${ sort_number === "asc" ? "reverse" : "" }`} onClick={ this._handle_onChangeSort_number }>Номер договора</div>
<div className={`table_cell caret ${ sort_date === "asc" ? "reverse" : "" }`} onClick={ this._handle_onChangeSort_date }>Дата договора</div>
<div className="table_cell">Автомобиль</div>
<div className="table_cell">Гос.номер</div>
<div className="table_cell">Vin</div>
<div className="table_cell caret">Статус</div>
<div className={`table_cell caret ${ sort_status === "asc" ? "reverse" : "" }`} onClick={ this._handle_onChangeSort_status }>Статус</div>
<div className="table_cell">Следующий платеж</div>
</div>
<div className="table_row">
<div className="table_cell"><Link href={`/contract/${ "1234-2021" }/payments`}>Договор 1234-2021</Link></div>
<div className="table_cell">21.02.2021</div>
<div className="table_cell">Lada Granta седан Standard 1.6 87hp 5MT</div>
<div className="table_cell">Х 123 АМ 777</div>
<div className="table_cell">4USBT53544LT26841</div>
<div className="table_cell">
<p className="closed">Закрыт</p>
</div>
<div className="table_cell">
20.01.2021
<b className="price">45,000 р.</b>
</div>
</div>
{ contracts !== null && (
<>
{ contracts.length > 0 ? contracts.map((contract, index) => (
<div className="table_row" key={ index }>
<div className="table_cell"><Link href={`/contract/${ contract.number }/payments`}><a>Договор { contract.number }</a></Link></div>
<div className="table_cell">{ contract.date }</div>
<div className="table_cell">{ contract.car?.brand?.name } { contract.car?.model?.name }</div>
<div className="table_cell">{ contract.car?.reg_number !== null ? contract.car?.reg_number : "Без рег. номера" }</div>
<div className="table_cell">{ contract.car?.vin_number }</div>
<div className="table_cell"><p className={ contract_status[contract.status] }>{ contract.status }</p></div>
<div className="table_cell">
{ contract.current_payment_amount !== null ? (
<>{ contract.current_payment_date }<b className="price">{ numeral(contract.current_payment_amount).format('') } р.</b></>
) : "-" }
</div>
</div>
)) : (
<div className="table_row">
<div className="table_cell">-</div>
<div className="table_cell">-</div>
<div className="table_cell">-</div>
<div className="table_cell">-</div>
<div className="table_cell">-</div>
<div className="table_cell">-</div>
<div className="table_cell">-</div>
</div>
) }
</>
) }
{/*
<div className="table_row">
<div className="table_cell"><Link href={`/contract/${ "1234-2022" }/payments`}>Договор 1234-2022</Link></div>
<div className="table_cell">21.02.2021</div>
@ -120,36 +238,9 @@ class IndexPage extends React.Component
<b className="price">45,000 р.</b>
</div>
</div>
*/}
</div>
<div className="pagination">
<ul>
<li>
<a href="#">1</a>
</li>
<li>
<a href="#">2</a>
</li>
<li>
<a href="#">3</a>
</li>
<li>
<a href="#">4</a>
</li>
<li>
<a href="#">5</a>
</li>
<li>
<a href="#">6</a>
</li>
<li>........</li>
<li>
<a href="#">123</a>
</li>
<li>
<a href="#">{`>`}</a>
</li>
</ul>
</div>
<Pagination page={ page } pages={ pages } onPage={ this._handle_onPage }/>
</div>
</section>
</main>
@ -162,6 +253,7 @@ class IndexPage extends React.Component
function mapStateToProps(state, ownProps)
{
return {
company: state.company,
contracts: state.contracts.list,
page: state.contracts.page,
pages: state.contracts.pages,

View File

@ -1,143 +0,0 @@
import React from "react";
import Head from 'next/head';
import Image from 'next/image';
import Header from './components/Header';
import Footer from './components/Footer';
export default function SchedulePage()
{
return (
<React.Fragment>
<Head>
<title>ЛК Эволюция автолизинга</title>
<meta
name="description"
content="ЛК Эволюция автолизинга"
/>
</Head>
<Header/>
<main>
<section>
<div className="clear"></div>
<div className="container">
<div className="title_wrapper">
<div className="left">
<h1 className="section_title">Договор 1234/2021 от 10.01.2021</h1>
</div>
<div className="right">
<p align="right">
<b>ООО Друзья и КО</b><br />
ИНН: 12345678765 КПП: 13432-02
</p>
</div>
</div>
<div className="aside_container about">
<aside>
<ul className="aside_nav">
<li>
<a href="#" className="active">График платежей</a>
</li>
<li>
<a href="#">Дополнительные услуги</a>
</li>
<li>
<a href="#">Договор</a>
</li>
<li>
<a href="#">Документы по сделке</a>
</li>
</ul>
</aside>
<article>
<div className="contract_table schedule">
<div className="table_row table_header">
<div className="table_cell caret"> платежа</div>
<div className="table_cell caret">Дата лизингового
платежа</div>
<div className="table_cell caret">Лизинговый платеж
с НДС (рубли)</div>
<div className="table_cell caret">НДС, 20% (рубли)</div>
<div className="table_cell">Статус платежа</div>
<div className="table_cell">Платежное поручение</div>
</div>
<button className="show_more primary">Показать прошедшие платежи</button>
<div className="table_row" data-status="overpayment-2">
<div className="table_cell" data-title="№ платежа:">11</div>
<div className="table_cell" data-title="Дата лизингового платежа">21.02.2021</div>
<div className="table_cell" data-title="Лизинговый платеж с НДС (рубли)">239 724,05</div>
<div className="table_cell" data-title="НДС, 20% (рубли)">43 079,18</div>
<div className="table_cell" data-title="Статус платежа">Переплата 15 000,00 </div>
<div className="table_cell" data-title="Платежное поручение">18432 от 20/01/2021 на сумму 255 000,00 </div>
</div>
<div className="table_row" data-status="overpayment-1">
<div className="table_cell" data-title="№ платежа:">12</div>
<div className="table_cell" data-title="Дата лизингового платежа">21.02.2021</div>
<div className="table_cell" data-title="Лизинговый платеж с НДС (рубли)">239 724,05</div>
<div className="table_cell" data-title="НДС, 20% (рубли)">43 079,18</div>
<div className="table_cell" data-title="Статус платежа">Переплата 15 000,00 </div>
<div className="table_cell" data-title="Платежное поручение">18432 от 20/01/2021 на сумму 255 000,00 </div>
</div>
<div className="table_row" data-status="paid">
<div className="table_cell" data-title="№ платежа:">13</div>
<div className="table_cell" data-title="Дата лизингового платежа">21.02.2021</div>
<div className="table_cell" data-title="Лизинговый платеж с НДС (рубли)">239 724,05</div>
<div className="table_cell" data-title="НДС, 20% (рубли)">43 079,18</div>
<div className="table_cell" data-title="Статус платежа">Переплата 15 000,00 </div>
<div className="table_cell" data-title="Платежное поручение">18432 от 20/01/2021 на сумму 255 000,00 </div>
</div>
<div className="table_row">
<div className="table_cell">14</div>
<div className="table_cell">21.02.2021</div>
<div className="table_cell">239 724,05</div>
<div className="table_cell">43 079,18</div>
<div className="table_cell">Не оплачено </div>
<div className="table_cell">-</div>
</div>
</div>
</article>
</div>
</div>
</section>
<section id="order">
<div className="container wide">
<h2 className="section_title">Купить в лизинг?</h2>
<div className="order_form">
<div className="order_email">
<p>Напишите на <a href="mailto:">buy@domain.ru</a> или заполните форму</p>
</div>
<form>
<div className="form_field">
<input type="text" value="" placeholder="Имя" />
</div>
<div className="form_field">
<input type="tel" value="" placeholder="Телефон" />
</div>
<div className="form_field">
<input type="email" value="" placeholder="E-mail" />
</div>
<div className="form_field">
<input type="text" value="" placeholder="Организация" />
</div>
<div className="policy">
<input type="checkbox" name="policy" id="policy" hidden checked />
<label for="policy">Даю свое согласие на обработку моих персональных данных</label>
</div>
<button className="button">Отправить</button>
</form>
</div>
</div>
</section>
</main>
<Footer/>
</React.Fragment>
)
}

114
pages/settings.js Normal file
View File

@ -0,0 +1,114 @@
import React from "react";
import Head from 'next/head';
import Image from 'next/image';
import Link from "next/link";
import cookie from 'cookie';
import { connect } from "react-redux";
import numeral from "numeral";
import { withRouter } from 'next/router';
import { reduxWrapper } from '../store';
import Header from './components/Header';
import Footer from './components/Footer';
import Pagination from './components/Pagination';
import { logout } from '../actions';
class IndexPage extends React.Component
{
constructor(props)
{
super(props);
this.state = {
};
}
static getDerivedStateFromProps(nextProps, prevState)
{
return {
};
}
_handle_onLogout = () =>
{
logout({ dispatch: this.props.dispatch }).then().catch();
}
render()
{
const { loading, page, pages, search, date_from, date_from_type, date_to, date_to_type, contracts, sort_number, sort_date, sort_status } = this.state;
console.log("contracts");
console.log(contracts);
const contract_status = {
"Действующий": "opened",
"Закрыт": "closed",
};
return (
<React.Fragment>
<Head>
<title>ЛК Эволюция автолизинга</title>
<meta
name="description"
content="ЛК Эволюция автолизинга"
/>
</Head>
<Header { ...this.props }/>
<main>
<section>
<div className="clear"></div>
<div className="container">
<h1 className="section_title">Настройки</h1>
<button onClick={ this._handle_onLogout }>Выйти из личного кабинета</button>
</div>
</section>
</main>
<Footer/>
</React.Fragment>
)
}
}
function mapStateToProps(state, ownProps)
{
return {
}
}
export const getServerSideProps = reduxWrapper.getServerSideProps(store =>
async ({ req, res, query }) =>
{
let props = {};
if(req.headers.cookie !== undefined)
{
const cookies = cookie.parse(req.headers?.cookie ? req.headers?.cookie : "");
if(cookies.jwt === undefined || cookies.jwt === null)
{
res.statusCode = 302;
res.setHeader('Location', `/login`);
}
else
{
//const tokenValid = await checkToken(cookies.jwt);
const tokenValid = true;
if(!tokenValid)
{
res.statusCode = 302;
res.setHeader('Location', `/login`);
}
}
}
else
{
res.statusCode = 302;
res.setHeader('Location', `/login`);
}
return { props: props };
}
);
export default withRouter(connect(mapStateToProps)(IndexPage));

View File

@ -19,13 +19,13 @@ export default function TransactionPage()
<Header/>
<main>
<section>
<div class="clear"></div>
<div class="container">
<div class="title_wrapper">
<div class="left">
<h1 class="section_title">Договор 1234/2021 от 10.01.2021</h1>
<div className="clear"></div>
<div className="container">
<div className="title_wrapper">
<div className="left">
<h1 className="section_title">Договор 1234/2021 от 10.01.2021</h1>
</div>
<div class="right">
<div className="right">
<p align="right">
<b>ООО Друзья и КО</b><br />
ИНН: 12345678765 КПП: 13432-02
@ -34,9 +34,9 @@ export default function TransactionPage()
</div>
<div class="aside_container about">
<div className="aside_container about">
<aside>
<ul class="aside_nav">
<ul className="aside_nav">
<li>
<a href="#">График платежей</a>
</li>
@ -47,27 +47,27 @@ export default function TransactionPage()
<a href="#">Договор</a>
</li>
<li>
<a href="#" class="active">Документы по сделке</a>
<a href="#" className="active">Документы по сделке</a>
</li>
</ul>
</aside>
<article>
<div class="dropdown_blocks_list">
<div class="dropdown_block">
<div class="block_header">
<div className="dropdown_blocks_list">
<div className="dropdown_block">
<div className="block_header">
<p>
УПД по очередным платежам
</p>
<button class="block_toggle"></button>
<button className="block_toggle"></button>
</div>
<div class="block_body">
<div class="transaction_detail">
<div className="block_body">
<div className="transaction_detail">
<p> постановления: <b>3432434242334</b></p>
<ul>
<li>Сумма: <b>3 000,00 р.</b></li>
<li>Дата: <b>01/01/2020</b></li>
<li>Статус: <b class="success">Оплачен</b></li>
<li>Статус: <b className="success">Оплачен</b></li>
<li>Штраф: п. 1.15 - Несоблюдение правил парковки </li>
</ul>
</div>
@ -75,40 +75,40 @@ export default function TransactionPage()
</div>
<div class="dosc_list medium-icon">
<div class="row">
<p class="doc_name i-pdf i-medium">
<div className="dosc_list medium-icon">
<div className="row">
<p className="doc_name i-pdf i-medium">
Дополнительное соглашение 1
</p>
<a href="#" class="button button-blue">Скачать</a>
<a href="#" className="button button-blue">Скачать</a>
</div>
<div class="row">
<p class="doc_name i-pdf i-medium">
<div className="row">
<p className="doc_name i-pdf i-medium">
Дополнительное соглашение 2
</p>
<a href="#" class="button button-blue">Скачать</a>
<a href="#" className="button button-blue">Скачать</a>
</div>
<div class="row">
<p class="doc_name i-pdf i-medium">
<div className="row">
<p className="doc_name i-pdf i-medium">
Выкупные документы
</p>
<a href="#" class="button button-blue">Скачать</a>
<a href="#" className="button button-blue">Скачать</a>
</div>
</div>
<hr />
<div class="dropdown_block">
<div class="block_header">
<div className="dropdown_block">
<div className="block_header">
<p>
УПД по доп.услугам
</p>
<button class="block_toggle"></button>
<button className="block_toggle"></button>
</div>
<div class="block_body"></div>
<div className="block_body"></div>
</div>
</div>

2
public/robots.txt Normal file
View File

@ -0,0 +1,2 @@
User-agent: *
Disallow: /

View File

@ -0,0 +1,32 @@
import { HYDRATE } from 'next-redux-wrapper';
import * as actionTypes from '../constants/actionTypes';
import initialState from "./initialState";
const calendarReducer = (state = initialState.calendar, action) =>
{
switch (action.type)
{
case HYDRATE:
{
return {
...state,
...action.payload.calendar,
};
}
case actionTypes.CALENDAR:
{
return {
...state,
...action.data,
};
}
default: {
return state;
}
}
};
export default calendarReducer;

View File

@ -0,0 +1,32 @@
import { HYDRATE } from 'next-redux-wrapper';
import * as actionTypes from '../constants/actionTypes';
import initialState from "./initialState";
const contractReducer = (state = initialState.contract, action) =>
{
switch (action.type)
{
case HYDRATE:
{
return {
...state,
...action.payload.contract,
};
}
case actionTypes.CONTRACT:
{
return {
...state,
...action.data,
};
}
default: {
return state;
}
}
};
export default contractReducer;

View File

@ -9,15 +9,21 @@ export const defaultState = {
phone: "",
},
company: {
title: "ООО \"Тест\"",
inn: 770011223344,
kpp: 200301001
title: "",
inn: "",
kpp: "",
ogrn: "",
},
contracts:
{
list: null,
page: null,
pages: false,
page: 1,
pages: 1,
},
contract: null,
calendar: {
payments: null,
periods: null,
},
schedule:
{

View File

@ -5,12 +5,16 @@ import authReducer from '../reducers/authReducer';
import userReducer from '../reducers/userReducer';
import companyReducer from '../reducers/companyReducer';
import contractsReducer from '../reducers/contractsReducer';
import contractReducer from '../reducers/contractReducer';
import calendarReducer from '../reducers/calendarReducer';
const combinedReducer = combineReducers({
auth: authReducer,
user: userReducer,
company: companyReducer,
contracts: contractsReducer,
contract: contractReducer,
calendar: calendarReducer,
});
const makeStore = (context) =>

116
yarn.lock
View File

@ -121,6 +121,20 @@
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz#87de7af9c231826fdd68ac7258f77c429e0e5fcf"
integrity sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==
"@nano-sql/core@^2.3.7":
version "2.3.7"
resolved "https://registry.yarnpkg.com/@nano-sql/core/-/core-2.3.7.tgz#df4ea7916272cab7c4a4bf4294197dd64637fe59"
integrity sha512-B9nniPPRhPf5Hf2cyvy72SNEg4iKQEW6pig9nwrM4DJlmOMZudifOMPBoJuK6JcTaLATIOGRPkclfosNUALnLQ==
dependencies:
fast-deep-equal "^2.0.1"
levenshtein-edit-distance "^2.0.4"
really-small-events "^1.1.0"
snap-db "^1.1.1"
optionalDependencies:
chalk "^2.4.2"
chokidar "^3.0.2"
command-line-args "^5.1.1"
"@napi-rs/triples@^1.0.3":
version "1.0.3"
resolved "https://registry.yarnpkg.com/@napi-rs/triples/-/triples-1.0.3.tgz#76d6d0c3f4d16013c61e45dfca5ff1e6c31ae53c"
@ -373,7 +387,7 @@ ansi-styles@^4.1.0:
dependencies:
color-convert "^2.0.1"
anymatch@~3.1.1:
anymatch@~3.1.1, anymatch@~3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716"
integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==
@ -401,6 +415,11 @@ aria-query@^4.2.2:
"@babel/runtime" "^7.10.2"
"@babel/runtime-corejs3" "^7.10.2"
array-back@^3.0.1, array-back@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/array-back/-/array-back-3.1.0.tgz#b8859d7a508871c9a7b2cf42f99428f65e96bfb0"
integrity sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==
array-includes@^3.1.1, array-includes@^3.1.3, array-includes@^3.1.4:
version "3.1.4"
resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.4.tgz#f5b493162c760f3539631f005ba2bb46acb45ba9"
@ -473,6 +492,11 @@ ast-types@0.13.2:
resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.13.2.tgz#df39b677a911a83f3a049644fb74fdded23cea48"
integrity sha512-uWMHxJxtfj/1oZClOxDEV1sQ1HCDkA4MG8Gr69KKeBjEVH0R84WlejZ0y2DcwyBlpAEMltmVYkVgqfLFb2oyiA==
async@^3.2.2:
version "3.2.2"
resolved "https://registry.yarnpkg.com/async/-/async-3.2.2.tgz#2eb7671034bb2194d45d30e31e24ec7e7f9670cd"
integrity sha512-H0E+qZaDEfx/FY4t7iLRv1W2fFI6+pyCeTw1uN20AQPiwqwM6ojPxHxdLv4z8hi2DtnW9BOckSspLucW7pIE5g==
available-typed-arrays@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7"
@ -672,7 +696,7 @@ caniuse-lite@^1.0.30001202, caniuse-lite@^1.0.30001219, caniuse-lite@^1.0.300012
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001265.tgz#0613c9e6c922e422792e6fcefdf9a3afeee4f8c3"
integrity sha512-YzBnspggWV5hep1m9Z6sZVLOt7vrju8xWooFAgN6BA5qvy98qPAPb7vNUzypFaoh2pb3vlfzbDO8tB57UPGbtw==
chalk@2.4.2, chalk@^2.0.0:
chalk@2.4.2, chalk@^2.0.0, chalk@^2.4.2:
version "2.4.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
@ -712,6 +736,21 @@ chokidar@3.5.1:
optionalDependencies:
fsevents "~2.3.1"
chokidar@^3.0.2:
version "3.5.2"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75"
integrity sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==
dependencies:
anymatch "~3.1.2"
braces "~3.0.2"
glob-parent "~5.1.2"
is-binary-path "~2.1.0"
is-glob "~4.0.1"
normalize-path "~3.0.0"
readdirp "~3.6.0"
optionalDependencies:
fsevents "~2.3.2"
cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
version "1.0.4"
resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de"
@ -763,6 +802,16 @@ colorette@^1.2.2:
resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.4.0.tgz#5190fbb87276259a86ad700bff2c6d6faa3fca40"
integrity sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==
command-line-args@^5.1.1:
version "5.2.0"
resolved "https://registry.yarnpkg.com/command-line-args/-/command-line-args-5.2.0.tgz#087b02748272169741f1fd7c785b295df079b9be"
integrity sha512-4zqtU1hYsSJzcJBOcNZIbW5Fbk9BkjCp1pZVhQKoRaWL5J7N4XphDLwo8aWwdQpTugxwu+jf9u2ZhkXiqp5Z6A==
dependencies:
array-back "^3.1.0"
find-replace "^3.0.0"
lodash.camelcase "^4.3.0"
typical "^4.0.0"
commondir@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
@ -805,6 +854,14 @@ core-util-is@~1.0.0:
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85"
integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==
cors@^2.8.5:
version "2.8.5"
resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29"
integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==
dependencies:
object-assign "^4"
vary "^1"
create-ecdh@^4.0.0:
version "4.0.4"
resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e"
@ -1320,6 +1377,11 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3:
md5.js "^1.3.4"
safe-buffer "^5.1.1"
fast-deep-equal@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=
fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
version "3.1.3"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
@ -1384,6 +1446,13 @@ find-cache-dir@3.3.1:
make-dir "^3.0.2"
pkg-dir "^4.1.0"
find-replace@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/find-replace/-/find-replace-3.0.0.tgz#3e7e23d3b05167a76f770c9fbd5258b0def68c38"
integrity sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==
dependencies:
array-back "^3.0.1"
find-up@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7"
@ -1427,7 +1496,7 @@ fs.realpath@^1.0.0:
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
fsevents@~2.3.1:
fsevents@~2.3.1, fsevents@~2.3.2:
version "2.3.2"
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
@ -1466,7 +1535,7 @@ get-symbol-description@^1.0.0:
call-bind "^1.0.2"
get-intrinsic "^1.1.1"
glob-parent@^5.1.2, glob-parent@~5.1.0:
glob-parent@^5.1.2, glob-parent@~5.1.0, glob-parent@~5.1.2:
version "5.1.2"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
@ -1973,6 +2042,11 @@ language-tags@^1.0.5:
dependencies:
language-subtag-registry "~0.3.2"
levenshtein-edit-distance@^2.0.4:
version "2.0.5"
resolved "https://registry.yarnpkg.com/levenshtein-edit-distance/-/levenshtein-edit-distance-2.0.5.tgz#a066eca8afb350e4d9054aed9ffeef66e78ffc83"
integrity sha512-Yuraz7QnMX/JENJU1HA6UtdsbhRzoSFnGpVGVryjQgHtl2s/YmVgmNYkVs5yzVZ9aAvQR9wPBUH3lG755ylxGA==
levn@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade"
@ -2014,6 +2088,11 @@ locate-path@^5.0.0:
dependencies:
p-locate "^4.1.0"
lodash.camelcase@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY=
lodash.includes@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f"
@ -2331,7 +2410,7 @@ numeral@^2.0.6:
resolved "https://registry.yarnpkg.com/numeral/-/numeral-2.0.6.tgz#4ad080936d443c2561aed9f2197efffe25f4e506"
integrity sha1-StCAk21EPCVhrtnyGX7//iX05QY=
object-assign@^4.1.1:
object-assign@^4, object-assign@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
@ -2772,6 +2851,18 @@ readdirp@~3.5.0:
dependencies:
picomatch "^2.2.1"
readdirp@~3.6.0:
version "3.6.0"
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"
integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==
dependencies:
picomatch "^2.2.1"
really-small-events@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/really-small-events/-/really-small-events-1.1.0.tgz#ad35eb0afa956c76838c926c8f6734db8524e946"
integrity sha512-iyh4pULyDYBMecekEYcP3ToJD3ZUdIPfZV9nx1C1lJfMguElkDAZvEMJegy8uE7eIROCuLsqh5r44fVro9nKFg==
redux-persist@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/redux-persist/-/redux-persist-6.0.0.tgz#b4d2972f9859597c130d40d4b146fecdab51b3a8"
@ -2955,6 +3046,11 @@ slash@^3.0.0:
resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
snap-db@^1.1.1:
version "1.1.6"
resolved "https://registry.yarnpkg.com/snap-db/-/snap-db-1.1.6.tgz#ee223c79dcfb4945af29b6ae32c9562988623d5d"
integrity sha512-KxsO5RnY70J48f6poy0qVm2WS8ZbqG0PUVP2fjd7dvlaCMZ/DxtDv5fhhIVwkP2lOmNQ9QsTFfDuCA7N+TF3qg==
source-map@0.7.3:
version "0.7.3"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383"
@ -3246,6 +3342,11 @@ type-fest@^0.7.1:
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.7.1.tgz#8dda65feaf03ed78f0a3f9678f1869147f7c5c48"
integrity sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==
typical@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/typical/-/typical-4.0.0.tgz#cbeaff3b9d7ae1e2bbfaf5a4e6f11eccfde94fc4"
integrity sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==
unbox-primitive@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471"
@ -3336,6 +3437,11 @@ v8-compile-cache@^2.0.3:
resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee"
integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==
vary@^1:
version "1.1.2"
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
vm-browserify@1.1.2, vm-browserify@^1.0.1:
version "1.1.2"
resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0"