@rnga/orders
Version:
## Get schema from @prisma-cms 1. yarn get-api-schema -e http://localhost:4000 2. yarn build-api-fragments
1,277 lines (882 loc) • 27.2 kB
JavaScript
/* eslint-disable no-script-url */
/* eslint-disable jsx-a11y/anchor-is-valid */
import React, { Fragment } from 'react'
import PropTypes from 'prop-types'
import { graphql, compose } from 'react-apollo';
// import gql from 'graphql-tag';
import moment from "moment";
import OrderItem from "./OrderItem";
import {
// order,
updateOrderProcessor,
// updateUserProcessor,
} from 'query';
import EditableView from 'apollo-cms/lib/DataView/Object/Editable';
import Modal from "../../../Modal";
import { withStyles } from 'material-ui';
import { CircularProgress } from 'material-ui/Progress';
import green from 'material-ui/colors/green';
import NumberFormat from 'react-number-format';
const styles = {
buttonWrapper: {
position: "relative",
display: "inline-block",
},
buttonLoading: {
opacity: 0.2,
},
buttonProgress: {
color: green[500],
position: 'absolute',
top: '50%',
left: '50%',
marginTop: -12,
marginLeft: -12,
},
link: {
cursor: "pointer",
},
}
export class OrdersOrder extends EditableView {
static propTypes = {
// eslint-disable-next-line react/forbid-foreign-prop-types
...EditableView.propTypes,
services: PropTypes.array,
// match: PropTypes.object.isRequired,
// View: PropTypes.func.isRequired,
// order: PropTypes.object.isRequired,
classes: PropTypes.object.isRequired,
}
static defaultProps = {
...EditableView.defaultProps,
// View,
}
constructor(props) {
super(props);
const {
opened = false,
confirmOpened = false,
showSuccess = false,
// loading = false,
} = props;
this.state = {
...this.state,
opened,
confirmOpened,
showSuccess,
};
}
renderHeader() {
return null;
}
updateItem(item, data) {
let itemsDirty = this.getItemsDirty() || [];
const {
id: itemId,
} = item;
let existsItem = itemsDirty.find(n => n.id === itemId) || itemsDirty[itemsDirty.push({
id: itemId,
}) - 1];
Object.assign(existsItem, data);
this.updateObject({
itemsDirty,
});
}
getItemsDirty(activeOnly = false) {
let {
itemsDirty,
} = this.state._dirty || {}
// return itemsDirty;
return activeOnly === true ? itemsDirty ? itemsDirty.filter(n => {
// n.selectedServices && n.selectedServices.findIndex(n => n._selected === true) !== -1
let dirty = false;
if (!n) {
return false;
}
const {
// id: dirtyItemId,
selectedServices,
// ...other
} = n;
// if (
// dirtyItemId === id
// ) {
if (
(selectedServices && selectedServices.find(n => n._selected === true))
// || (other && Object.keys(other).length)
) {
dirty = true;
}
// }
return dirty;
}) : []
: itemsDirty;
}
printOrder() {
this.setState({
opened: true,
}, () => {
setTimeout(() => {
// const {
// orderTable,
// } = this.refs;
const {
orderTableRef: orderTable,
} = this;
if (!orderTable) {
return;
}
const clone = orderTable.cloneNode(true);
// const wrapper = <div
// className={"print-wrapper"}
// >
// {this.renderOrderTable()}
// </div>
const wrapper = global.document.querySelector(".print-wrapper");
if (!wrapper) {
return;
}
wrapper.innerHTML = null;
wrapper.appendChild(clone)
// $(this).closest('.open-tab-wrapper').find('.selection-block').removeClass('open');
// var thisOrder = $(this).closest('.open-tab-wrapper.client-order');
// var userName = $(this).closest('.orders-wrapper').attr('data-login');
// var userFullName = $(this).closest('.orders-wrapper').attr('data-username');
// var orderNum = $(this).closest('.orders-wrapper').find('.open-tab-title').attr('data-order');
// var orderDate = $(this).closest('.orders-wrapper').find('.open-tab-title').attr('data-orderdate');
// $('.print-wrapper').empty();
// $('title').empty();
// $('title').append('Личный кабинет пользователя ' + userName + ' заказ № ' + orderNum + ' от ' + orderDate);
// $(thisOrder).clone().appendTo('.print-wrapper');
// window.print();
// $(this).closest('.open-tab-wrapper').find('.selection-block').removeClass('open');
// var thisOrder = $(this).closest('.open-tab-wrapper.client-order');
// var userName = $(this).closest('.orders-wrapper').attr('data-login');
// var userFullName = $(this).closest('.orders-wrapper').attr('data-username');
// var orderNum = $(this).closest('.orders-wrapper').find('.open-tab-title').attr('data-order');
// var orderDate = $(this).closest('.orders-wrapper').find('.open-tab-title').attr('data-orderdate');
// $('.print-wrapper').empty();
// $('title').empty();
// $('title').append('Личный кабинет пользователя ' + userName + ' заказ № ' + orderNum + ' от ' + orderDate);
// $(thisOrder).clone().appendTo('.print-wrapper');
window.print();
}, 500)
});
}
renderEditableView() {
return this.renderDefaultView();
}
canOrderSlab(item, showErrors = true) {
const {
preGrade,
// sheldon_grade,
} = item;
if (this.notGradable(item)) {
showErrors && this.addError("Нельзя заказать услугу для этой монеты");
return false;
}
if (!preGrade) {
showErrors && this.addError("Дождитесь получения прегрейда.");
return false;
}
return true;
}
notGradable(item) {
const {
preGrade,
sheldon_grade,
} = item || {};
return (
preGrade === "NOTGENUINE"
|| preGrade === "NOTGRADABLE"
|| sheldon_grade === "NOTGENUINE"
|| sheldon_grade === "NOTGRADABLE"
);
}
addError(error) {
super.addError(error);
return false;
}
getDirty(item) {
const {
_dirty,
} = item;
return _dirty;
}
isSlabServiceOrdered(item) {
const {
selectedServices,
} = this.getDirty(item) || {};
const slabServiceSelected = (selectedServices && selectedServices.find(n => n.code === "slab" && n._selected === true)) ? true : false;
const {
ServiceOrders,
} = item;
let SlabServiceOrder = ServiceOrders.find(n => n.Service.code === "slab");
/**
* Определяем выбран ли заказ на слаб.
* Если да, но не выбран тариф, надо подсветить тариф
*/
// let SlabServiceOrdered = true;
// let SlabServiceOrdered = slabServiceSelected ? true : false;
let SlabServiceOrdered = SlabServiceOrder || slabServiceSelected ? true : false;
return SlabServiceOrdered;
}
/**
* Выбираем услугу
*/
setService(item, service) {
const canEdit = this.canEdit();
// console.log("setService service", service);
// console.log("canEdit", canEdit);
if (!canEdit) {
return;
}
/**
* Когда пользователь отменяет выбор тарифа,
* удаляем его из массива
*/
// if (!selectedService._selected) {
// selectedServices.splice(selectedServices.indexOf(selectedService), 1);
// }
const {
id: serviceId,
code,
} = service;
let {
selectedServices,
} = this.getDirty(item) || {}
selectedServices = selectedServices || [];
// const index = selectedServices.findIndex(n => n.id === serviceId);
let selectedService = selectedServices.find(n => n.id === serviceId);
if (!selectedService) {
selectedService = {
...service,
};
/**
* Проверяем если выбирает слабирование, то должен быть указан прегрейд
*/
switch (code) {
case "slab":
if (!this.canOrderSlab(item)) {
return false;
}
break;
default: ;
}
selectedServices.push(selectedService);
}
selectedService._selected = selectedService._selected ? false : true;
this.updateItem(item, {
selectedServices,
});
}
canEdit = () => {
const order = this.getObjectWithMutations() || {};
const {
archived,
} = order;
let canEdit = archived === false || archived === null ? true : false;
return canEdit;
}
getItems(options = {}) {
const order = this.getObjectWithMutations();
if (!order) {
return [];
}
const {
services,
// classes,
} = this.props;
const {
diffsOnly,
} = options;
const {
// id: orderId,
// date,
// number,
Items,
// archived,
} = order;
let itemsDirty = this.getItemsDirty() || [];
return Items && Items.length ? Items.map(n => {
const {
id,
price: itemPrice,
ServiceOrders,
InvoiceItems = [],
} = n;
// if(ServiceOrders && ServiceOrders.length) {
// dirty = true;
// }
// else {
// }
let dirtyItem = itemsDirty.find(n => {
let dirty = false;
if (!n) {
return null;
}
// if (ServiceOrders && ServiceOrders.length) {
// dirty = true;
// }
// else {
const {
id: dirtyItemId,
selectedServices,
...other
} = n;
if (
dirtyItemId === id
) {
if (
(selectedServices && selectedServices.find(n => n._selected === true))
|| (other && Object.keys(other).length)
) {
dirty = true;
}
// }
}
return dirty;
});
if (diffsOnly && (!dirtyItem && (!ServiceOrders || !ServiceOrders.length))) {
return null;
}
let amount = InvoiceItems.reduce((a, { cost: b }) => a + b, 0);
const {
selectedServices,
slabTarif,
} = dirtyItem || {}
let slabSelected = ServiceOrders && ServiceOrders.find(n => n.Service.code === "slab") ? true : false;
let dirtySlab = (selectedServices && selectedServices.find(n => n.code === "slab" && n._selected === true)) || null;
// console.log("selectedServices", selectedServices);
// console.log("dirtySlab", dirtySlab);
if (dirtySlab) {
slabSelected = true;
}
/**
* Высчитываем стоимость данного изделия.
* Для этого проходим по каждой услуге и проверяем выбранные.
*
* Считать надо:
* - Услугу
* - Тариф
*/
// ServiceOrders
services.map(i => {
const {
id: serviceId,
// name,
// short_name,
// Tarifs,
code,
} = i;
let service;
let tarif;
let selectedService = (selectedServices && selectedServices.find(s => s.id === serviceId && s._selected === true));
/**
* Флаг того, что услуга в отказе
*/
// let rejected;
/**
* Надо брать данные из базы данных (самой услуги)
*/
let serviceOrderAmount;
switch (code) {
case "photo":
/**
* Если заказано слабирование, то фото бесплатно
*/
if (slabSelected) {
return null;
}
break;
default: ;
}
if (selectedService) {
service = selectedService;
// tarif = selectedService.Tarif;
const {
code,
Tarifs,
} = service;
if (code === "slab") {
tarif = slabTarif ? Tarifs.find(t => t.id === slabTarif) : undefined;
}
}
else {
const ServiceOrder = ServiceOrders.find(i => i.Service.id === serviceId);
if (ServiceOrder) {
let {
Service,
Tarif,
amount,
} = ServiceOrder;
serviceOrderAmount = amount;
service = Service;
tarif = Tarif;
}
}
if (serviceOrderAmount !== undefined) {
if (serviceOrderAmount) {
amount += serviceOrderAmount;
}
}
else if (service) {
const {
price,
priceCooficient,
} = service
if (tarif) {
amount += tarif.price;
}
if (priceCooficient) {
if (itemPrice) {
amount += itemPrice * (priceCooficient / 100);
}
}
else if (price) {
amount += price;
}
}
return null;
});
// total += price ? parseFloat(price) : 0;
amount = (amount && parseInt(amount)) || 0;
// total += amount;
return {
item: {
...n,
_dirty: dirtyItem,
},
services,
amount,
};
// return <OrderItem
// key={id}
// item={{
// ...n,
// _dirty: dirtyItem,
// }}
// services={services}
// amount={amount}
// classes={classes}
// updateItem={(item, data) => this.updateItem(item, data)}
// canEdit={() => this.canEdit()}
// canOrderSlab={item => this.canOrderSlab(item)}
// notGradable={item => this.notGradable(item)}
// getDirty={item => this.getDirty(item)}
// setService={(item, service) => this.setService(item, service)}
// />
}).filter(n => n) : [];
}
renderOrderTable(options = {}) {
const {
diffsOnly,
} = options;
const order = this.getObjectWithMutations();
if (!order) {
return null;
}
const {
opened,
// confirmOpened,
} = this.state;
const {
// services,
classes,
} = this.props;
// let canEdit = archived === false || archived === null ? true : false;
// console.log("canEdit", canEdit, archived);
let total = 0;
let items = this.getItems(options).map(n => {
const {
item,
services,
amount,
} = n;
if (amount) {
total += amount;
}
return <OrderItem
key={item.id}
item={item}
services={services}
amount={amount}
classes={classes}
updateItem={(item, data) => this.updateItem(item, data)}
canEdit={() => this.canEdit()}
canOrderSlab={item => this.canOrderSlab(item)}
notGradable={item => this.notGradable(item)}
getDirty={item => this.getDirty(item)}
isSlabServiceOrdered={item => this.isSlabServiceOrdered(item)}
setService={(item, service) => this.setService(item, service)}
/>
});
const hasActiveItems = this.getItemsDirty(true).length;
// let servicesTitles = services && services.map(n => {
// const {
// id,
// name,
// short_name,
// } = n;
// return <th
// key={id}
// >
// {short_name || name}
// </th>
// }) || [];
const tableServicesTitles = this.getTableServicesTitles("Заказ услуг");
const tableServicesTitles2 = this.getTableServicesTitles("Готовность");
return <div
className="client-order"
// ref={!diffsOnly ? "orderTable" : undefined}
ref={element => {
if (!diffsOnly) {
this.orderTableRef = element
}
}}
>
<div
className="open-tab-content"
style={{
display: "block",
}}
>
<table
className={["order-table", ""].join(" ")}
border="0" cellSpacing="0" cellPadding="0" id="103595180"
style={{
maxWidth: "100%",
minWidth: 1000,
}}
>
<tbody>
{opened && items ?
<Fragment>
<tr>
<th className={["num-th", ""].join(" ")}>№</th>
<th className={["name-th", ""].join(" ")}>Предмет</th>
<th className={["year-th", ""].join(" ")}>Год</th>
<th className={["metal-th", ""].join(" ")}>Металл</th>
<th className={["otsenka-th", ""].join(" ")}>Оценка (руб.)</th>
{/* <th className={["service-th", ""].join(" ")}>Услуги</th> */}
<th className={["pregdare-th", ""].join(" ")}>Прегрейд</th>
{/* {servicesTitles} */}
{tableServicesTitles}
{/* <th className={["tarif-th", ""].join(" ")}>Тариф</th> */}
{/* <th>Дата заказа</th> */}
<th className={["graid-th", ""].join(" ")}>Грейд по Шелдону</th>
<th className={["tarif-th", ""].join(" ")}>
Тариф
</th>
<th className={["order-date-th", ""].join(" ")}>
Дата заказа
</th>
{tableServicesTitles2}
<th className={["price-th", ""].join(" ")}>Стоимость (руб.)</th>
</tr>
{items}
<tr className="result-order-row">
<td colSpan="11"><span className="text-block">Итого</span></td>
<td><span className="text-block">
<NumberFormat
value={total || 0}
displayType="text"
thousandSeparator=" "
/>
</span></td>
</tr>
</Fragment>
: null}
{!diffsOnly && hasActiveItems
?
<tr className="accept-grade-button-wrapper" style={{
display: !this.isDirty() ? "none" : undefined,
}}>
<td className="accept-grade-block" colSpan="15">
<div
className="accept-grade-button confirm_order"
title="Подтвердить выбранные позиции"
onClick={event => {
// this.save();
this.setState({
confirmOpened: true,
});
}}
>
Подтвердить
</div>
<div
className="refuse-accept-grade-button" title="Очистить выбранные позиции"
onClick={event => {
this.resetEdit();
}}
>
x
</div>
</td>
</tr>
: null}
</tbody>
</table>
</div>
</div>
;
}
getTableServicesTitles(title) {
// const {
// classes,
// } = this.props;
return <th className={["service-th service-ready", ""].join(" ")}>
<div className="service-ready-title">
{title}
</div>
<div className="tab-block services ready-service">
<div
title="Слабировать все"
className={["service_accept "].join(" ")}
// className={["service_accept ", classes.link].join(" ")}
>
<a
href="javascript:;"
// className={classes.link}
style={{
cursor: "pointer",
}}
onClick={event => {
if (window.confirm("Заказать слабирование по всем позициям?")) {
this.orderAllSlabs();
}
}}
>
Слаб
</a>
</div>
<div title="Экспертное заключение" className="service_accept ">
Эксп
</div>
<div title="Фото" className="service_accept ">
Фото
</div>
<div title="Оценка" className="service_accept ">
Оценка
</div>
</div>
</th>
}
orderAllSlabs() {
// const items = this.getItems().map(({ item }) => item);
const items = this.getItems();
// console.log("orderAllSlabs items", items);
items.map(n => {
const {
item,
services,
} = n;
const slabService = services && services.find(n => n.code === "slab");
if (slabService && this.canOrderSlab(item, false) && !this.isSlabServiceOrdered(item)) {
// console.log("orderAllSlabs item", item);
// console.log("orderAllSlabs services", services);
this.setService(item, slabService);
}
return null;
});
}
renderDefaultView() {
const order = this.getObjectWithMutations();
console.log("renderDefaultView order", order);
if (!order) {
return null;
}
const {
classes,
} = this.props;
const {
opened,
confirmOpened,
showSuccess,
loading,
} = this.state;
const {
number,
date,
} = order;
// if(!order){
// return null;
// }
let orderTitle = `Заказ № ${number} ${(date && moment(date).format('DD.MM.YY')) || ""}`;
let orderTable = this.renderOrderTable();
let confirmModal;
if (confirmOpened) {
confirmModal = <div
className="order-profile"
>
<Modal
opened={true}
handleClose={event => {
this.setState({
confirmOpened: false,
});
}}
title={orderTitle}
// className="popup2"
>
<div
className="window"
style={{
width: "auto",
padding: 0,
}}
>
{this.renderOrderTable({
diffsOnly: true,
})}
<div className="confirm-send-wrapper" style={{
display: "block",
}}>
<div className="confirm-send-cansel-wrapper">
<div
className="confirm-button confirm_cansel"
onClick={event => {
event.preventDefault();
this.setState({
confirmOpened: false,
});
}}
>
Отменить
</div>
<div
className={classes.buttonWrapper}
>
<div
className={["confirm-button confirm_send", loading ? classes.buttonLoading : ""].join(" ")}
onClick={async event => {
event.preventDefault();
await this.save()
.then(r => {
const {
response,
} = r.data || {}
const {
success,
} = response || {}
if (success) {
this.setState({
confirmOpened: false,
});
this.setState({
showSuccess: true,
});
setTimeout(() => {
this.setState({
showSuccess: false,
});
}, 3000);
}
});
}}
>
Отправить
</div>
{loading ? <CircularProgress size={24} className={classes.buttonProgress} /> : null}
</div>
</div>
</div>
</div>
</Modal>
</div>
}
let successMessage;
if (showSuccess) {
successMessage = <div
className="order-profile"
>
<Modal
opened={true}
handleClose={event => {
this.setState({
confirmOpened: false,
});
}}
title={"Успешно"}
// className="popup2"
>
<div
className="window"
// style={{
// width: "auto",
// padding: 0,
// }}
>
<div className="insText">
<p>Спасибо за Ваш заказ.<br />Мы с Вами обязательно свяжемся.</p>
</div>
</div>
</Modal>
</div>
}
return <Fragment>
<div className="orders-wrapper" >
<div className="open-tab-wrapper client-order">
<div
className={["open-tab-title", opened ? "open" : ""].join(" ")}
onClick={event => {
this.setState({
opened: !opened,
});
}}
>
{orderTitle}
<i
className="menu-expand"
></i>
</div>
<div
className="print_order print-button" title="Распечатать заказ"
onClick={event => this.printOrder()}
></div>
<div
className="open-tab-content"
style={{
display: "block",
}}
>
{orderTable}
<div className="popup-grade">Подтвердить</div>
</div>
</div>
</div>
{confirmModal}
{successMessage}
</Fragment>
// return (<View
// // object={order}
// // data={data}
// // saveObject={this.saveOrder}
// // {...other}
// data={{
// }}
// />)
}
}
export default compose(
// graphql(order, {
// // name: 'order',
// }),
graphql(updateOrderProcessor, {
// name: 'updateOrder',
options: () => {
return {
variables: {
orderGetItems: false,
},
}
},
}),
// graphql(updateUserProcessor, {
// name: 'updateUser',
// }),
)(withStyles(styles)(props => <OrdersOrder
{...props}
/>));
// export default OrdersOrder;