initial docker setup

This commit is contained in:
GotPPay
2018-06-14 16:49:28 +02:00
parent bc80b7342e
commit b5f87f27f8
3023 changed files with 985078 additions and 1 deletions

View File

@@ -0,0 +1,49 @@
import React, {Component} from 'react';
import {connect} from 'react-redux';
import {Form, FormGroup, Label, Input, Button} from 'reactstrap';
import {addProject} from '../../../actions/orderProjects/orderProjectsActions';
class AddOrderProject extends Component {
constructor(props) {
super(props);
this.state = {
projectName: ''
}
this.onProjectAdd = this.onProjectAdd.bind(this);
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
const field = event.target.name;
const newProjectData = Object.assign({}, this.state);
newProjectData[field] = event.target.value;
this.setState(newProjectData);
}
onProjectAdd(){
this.props.dispatch(addProject(this.state));
}
render() {
return (<Form>
<FormGroup>
<Label for="projectName">Project Name <span className="required-icon">*</span></Label>
<Input
type="text"
onChange={this.handleChange}
name="projectName"
id="projectName"
value={this.state.projectName}
placeholder="Project Name"/>
</FormGroup>
<FormGroup>
<Button onClick={this.onProjectAdd}>Add Project</Button>
</FormGroup>
</Form>);
}
}
export default connect()(AddOrderProject);

View File

@@ -0,0 +1,40 @@
import React, {Component} from 'react';
import {connect} from 'react-redux';
import {Button} from 'reactstrap';
import { WiaasTableRow, WiaasTableCol} from '../../../mainComponents/table/WiaasTable.jsx';
import {setBid} from '../../../actions/bids/bidsActions';
import {cartTexts} from '../../../constants/cartConstants';
class BidItem extends Component {
constructor(props) {
super(props);
this.onBidSelect = this.onBidSelect.bind(this);
}
onBidSelect(idBid){
this.props.dispatch(setBid(idBid, this.props.idCart));
}
render() {
const {bid, idSelectedBid} = this.props;
return (
<WiaasTableRow className="bid-item">
<WiaasTableCol header={cartTexts.labels.BID_NUMBER}>{bid.bidNumber}</WiaasTableCol>
<WiaasTableCol header={cartTexts.labels.START_DATE}>{bid.startDate}</WiaasTableCol>
<WiaasTableCol header={cartTexts.labels.END_DATE}>{bid.endDate}</WiaasTableCol>
<WiaasTableCol header={cartTexts.labels.FIXED}>{bid.fixedPrice}</WiaasTableCol>
<WiaasTableCol header={cartTexts.labels.RECURRENT}>{bid.recurrentPrice}</WiaasTableCol>
<WiaasTableCol header={cartTexts.labels.SERVICES}>{bid.servicesPrice}</WiaasTableCol>
<WiaasTableCol header={cartTexts.labels.ACTIONS}>
{
idSelectedBid === bid.idBid
? <Button onClick={()=>{this.onBidSelect(null)}}><span className="fa fa-times remove-item"></span> {cartTexts.buttons.REMOVE}</Button>
: <Button onClick={()=>{this.onBidSelect(bid.idBid)}}>{cartTexts.buttons.USE}</Button>
}
</WiaasTableCol>
</WiaasTableRow>
);
}
}
export default connect()(BidItem);

View File

@@ -0,0 +1,34 @@
import React, {Component} from 'react';
import BidItem from './BidItem.jsx';
import {cartTexts} from '../../../constants/cartConstants';
import {WiaasTable, WiaasTableHeader, WiaasTableBody} from '../../../mainComponents/table/WiaasTable.jsx';
class BidsList extends Component {
getHeaders(){
return [
cartTexts.labels.BID_NUMBER,
cartTexts.labels.START_DATE,
cartTexts.labels.END_DATE,
cartTexts.labels.FIXED,
cartTexts.labels.RECURRENT,
cartTexts.labels.SERVICES,
cartTexts.labels.ACTIONS
];
}
render() {
const {bids, idCart, idSelectedBid} = this.props.params;
return (
<WiaasTable id="bids-list">
<WiaasTableHeader headers={this.getHeaders()}/>
<WiaasTableBody>
{
bids.map(bid => <BidItem key={'bid-' + bid.idBid} idSelectedBid={idSelectedBid} idCart={idCart} bid={bid}/>)
}
</WiaasTableBody>
</WiaasTable>
);
}
}
export default BidsList;

View File

@@ -0,0 +1,23 @@
import React, {Component} from 'react';
import {cartTexts} from '../../../constants/cartConstants';
class CartIcon extends Component {
render() {
let {cartCount} = this.props;
cartCount = parseInt(cartCount, 10);
return (
<span id="cart-count" className="items-cart-count">
{ cartCount === 0
? <span>{cartTexts.labels.EMPTY_CART_ICON}</span>
: cartCount === 1
? <span>1 item in cart</span>
: <span>{cartCount} {cartTexts.labels.ITEMS_IN_CART_ICON}</span>
}
</span>
);
}
}
export default CartIcon;

View File

@@ -0,0 +1,272 @@
import React, {Component} from 'react';
import {connect} from 'react-redux';
import {Input, Tooltip, Row, Col} from 'reactstrap';
import '../style/Cart.css';
import {updateMessages} from '../../../actions/notification/notificationActions';
import {updateQuantity, removeCartItem} from '../../../actions/cart/cartActions';
import {setDialogContent, setDialogOpenFlag} from '../../../actions/dialog/dialogActions';
import {cartMessages, cartTexts} from '../../../constants/cartConstants';
import PackageBids from './PackageBids.jsx';
class CartItem extends Component {
constructor(props) {
super(props);
this.state = {
tooltipOpen: false,
itemQuantity: 1,
idCart: 0
};
this.toggleTooltip = this.toggleTooltip.bind(this);
this.removeItemFromCart = this.removeItemFromCart.bind(this);
this.resetQuantity = this.resetQuantity.bind(this);
this.sumPrices = this.sumPrices.bind(this);
}
componentWillReceiveProps(nextProps) {
this.setState({itemQuantity: nextProps.cartItem.quantity});
this.sumPrices(nextProps.cartItem, nextProps.cartItem.quantity);
}
componentDidMount() {
this.setState({itemQuantity: this.props.cartItem.quantity});
this.sumPrices(this.props.cartItem, this.props.cartItem.quantity);
}
isQuantityValid(quantity) {
return quantity > 0 && quantity <= 100;
}
updateQuantity(cartItem, quantity) {
if(quantity) {
this.setState({itemQuantity: quantity});
if(this.isQuantityValid(quantity)) {
this.sumPrices(cartItem, quantity);
this.props.dispatch(updateQuantity(cartItem, quantity));
} else {
this.props.dispatch(updateMessages([{code: 'error', message: 'INVALID_QUANTITY'}], cartMessages));
}
} else {
this.setState({itemQuantity: ''});
}
}
resetQuantity(cartItem) {
if(!this.state.itemQuantity || !this.isQuantityValid(this.state.itemQuantity)) {
this.updateQuantity(cartItem, 1);
}
}
removeItemFromCart() {
this.props.dispatch(removeCartItem(this.state.idCart));
}
setDialogParams(cartItem, dialogContent) {
this.setState({idCart: cartItem.idCart});
this.props.dispatch(setDialogOpenFlag(true));
dialogContent.bodyVariable = cartItem.packageName;
this.props.dispatch(setDialogContent(dialogContent));
}
toggleTooltip() {
this.setState({
tooltipOpen: !this.state.tooltipOpen
});
}
sumPrices(cartItem, quantity) {
let total = 0;
let oldTotal = null;
let totalRecurrent = 0;
let oldTotalRecurrent = null;
const selectedBid = cartItem.bids.find((bid) => {
return cartItem.idSelectedBid === bid.idBid;
});
if(selectedBid){
total += selectedBid.fixedPrice;
totalRecurrent += selectedBid.servicesPrice + selectedBid.recurrentPrice;
oldTotal = cartItem.fixedPrice;
oldTotalRecurrent = cartItem.servicesPrice + cartItem.recurentPrice;
}else{
total += cartItem.fixedPrice;
totalRecurrent += cartItem.servicesPrice + cartItem.recurentPrice;
}
if(cartItem.options.length) {
cartItem.options.forEach((packageOption) => {
if(Object.keys(packageOption.prices).length) {
total += parseFloat(packageOption.prices.fixedExtra);
totalRecurrent += parseFloat(packageOption.prices.recurentExtra) + parseFloat(packageOption.prices.servicesExtra);
}
});
}
if(cartItem.additionalPackages.length) {
cartItem.additionalPackages.forEach((additionalPackage) => {
if(Object.keys(additionalPackage).length) {
total += parseFloat(additionalPackage.prices.fixedExtra);
totalRecurrent += parseFloat(additionalPackage.prices.recurentExtra) + parseFloat(additionalPackage.prices.servicesExtra);
}
});
}
this.setState({
fixedPrice: total * quantity,
recurrentPrice: totalRecurrent * quantity,
fixedOldPrice: oldTotal !== null ? oldTotal * quantity : null,
recurrentOldPrice: oldTotalRecurrent !== null ? oldTotalRecurrent * quantity: null
});
}
getPriceClass(price){
return price !== null ? 'new-price' : 'price';
}
render() {
const dialogContent = {
buttons: [
{
color: 'success',
action: this.removeItemFromCart,
name: cartTexts.buttons.YES,
id: 'remove-item-confirmation'
}, {
color: 'secondary',
name: cartTexts.buttons.CANCEL,
id: 'cancel-remove-item'
}
],
header: cartTexts.labels.REMOVE_ITEM_HEADER,
body: cartTexts.labels.REMOVE_ITEM_TEXT
};
const {cartItem, isFormDisabled} = this.props;
const cartItemNo = this.props.cartItemNo ? this.props.cartItemNo + 1 : 1;
return (
<div id={"item-row-in-cart-" + cartItem.idCart} className="cart-show-items">
<Row className="cart-item-details">
<Col id={"item-package-name-" + cartItem.idCart}
xl="8" lg="8" md="7" sm="12" xs="12"
className="item-name">
{cartItemNo}. {cartItem.packageName}
<PackageBids idSelectedBid={cartItem.idSelectedBid} idCart={cartItem.idCart} bids={cartItem.bids}/>
</Col>
<Col xl="3" lg="3" md="3" sm="9" xs="9" id={"item-quantity-" + cartItem.idCart}>
{ isFormDisabled
? cartItem.quantity === 1
? cartItem.quantity + ' pc'
: cartItem.quantity + ' pcs'
: <Input className="quantity-field"
value={this.state.itemQuantity}
type="number"
step="1"
onChange={e => this.updateQuantity(cartItem, e.target.value)}
onBlur={e => this.resetQuantity(cartItem, e.target.value)}
/>
}
</Col>
<Col id={"item-remove-btn-" + cartItem.idCart} xl="1" lg="1" md="1" sm="1" xs="1">
<i id={'remove-item-' + cartItem.idCart + '-' + cartItem.idPackage}
className="fa fa-times remove-item"
aria-hidden="true"
onClick={() => this.setDialogParams(cartItem, dialogContent) }></i>
<Tooltip target={'remove-item-' + cartItem.idCart + '-' + cartItem.idPackage}
placement="bottom"
isOpen={this.state.tooltipOpen}
toggle={this.toggleTooltip}>
{cartTexts.labels.REMOVE_FROM_CART}
</Tooltip>
</Col>
</Row>
{ (!cartItem.areAdditionalAvailable || !cartItem.areOptionsAvailable || cartItem.status === 'not-available') &&
<Row className="cart-item-small-details">
<Col id={"item-warning-sign-remove-package-name-" + cartItem.idPackage}
xl="12" lg="12" md="12" sm="12" xs="12"
className="not-available">
{cartTexts.labels.PACKAGE_UNAVAILABLE}
</Col>
</Row>
}
{cartItem.options.length > 0 &&
cartItem.options.map((packageOption) =>
<Row className="cart-item-small-details" key={"package-option-" + cartItem.idCart + "-" + packageOption.idOptionPackage}>
<Col lg={{offset: 1, size: 4}} xs={{offset: 1, size: 4}}>
{packageOption.groupName}:
</Col>
<Col lg="7" xs="7" id={"item-option-" + cartItem.idCart + "-" + packageOption.idOptionPackage}>
{packageOption.packageName}
</Col>
</Row>
)
}
{cartItem.additionalPackages.length > 0 &&
cartItem.additionalPackages.map((additionalPackage) =>
<Row className="cart-item-small-details" key={"additional-package-" + cartItem.idCart + "-" + additionalPackage.idAdditionalPackage}>
<Col lg={{offset: 1, size: 4}} xs={{offset:1, size: 4}}>
{cartTexts.labels.ADDITIOONAL_PACKAGE}:
</Col>
<Col lg="7" xs="7" id={"item-additional-" + cartItem.idCart + "-" + additionalPackage.idAdditionalPackage}>
{additionalPackage.packageName}
</Col>
</Row>
)
}
<Row className="cart-item-small-details">
<Col lg={{offset: 1, size: 4}} xs={{offset:1, size: 4}}>Payment type:</Col>
<Col lg="7" xs="7" id={"item-payment-type-" + cartItem.idCart}>
{cartItem.payType}
</Col>
</Row>
<Row className="cart-item-small-details">
<Col lg={{offset: 1, size: 4}} xs={{offset:1, size: 4}}>Price:</Col>
<Col lg="7" xs="7" id={"item-price-" + cartItem.idCart}>
<table className="price-table">
<thead>
<tr>
<th>{cartTexts.labels.ON_DELIVERY}</th>
<th>{cartTexts.labels.MONTHLY}</th>
</tr>
</thead>
<tbody>
<tr>
<td>
{
this.state.fixedPrice &&
<div>
{
this.state.fixedOldPrice !== null &&
<div className="old-price">{this.state.fixedOldPrice}</div>
}
<div className={this.getPriceClass(this.state.fixedOldPrice)}>
{this.state.fixedPrice.toLocaleString() + ' ' + cartItem.country.currency}
</div>
</div>
}
</td>
<td>
{
this.state.recurrentPrice &&
<div>
{
this.state.recurrentOldPrice !== null &&
<div className="old-price">{this.state.recurrentOldPrice}</div>
}
<div className={this.getPriceClass(this.state.recurrentOldPrice)}>
{this.state.recurrentPrice.toLocaleString() + ' ' + cartItem.country.currency}
</div>
</div>
}
</td>
</tr>
</tbody>
</table>
</Col>
</Row>
</div>
);
}
}
export default connect()(CartItem);

View File

@@ -0,0 +1,79 @@
import React, {Component} from 'react';
import {connect} from 'react-redux';
import {Col} from 'reactstrap';
import {uploadOrderDocument, badFile} from '../../../actions/cart/cartActions';
import Dropzone from 'react-dropzone';
import {API_SERVER} from '../../../config';
import FileDownloader from '../../../helpers/FileDownloader';
import {cartTexts} from '../../../constants/cartConstants';
const fileHandler = new FileDownloader();
const documentTypes = {
2 : 'Customer Questionnaire',
7 : 'Customer Agreement'
};
class CartUploadDocument extends Component {
constructor(props) {
super(props);
this.uploadFile = this.uploadFile.bind(this);
}
uploadFile(idPackage, idDocumentType,acceptedFiles, rejectedFiles, packages){
const self = this;
acceptedFiles.forEach(file => {
self.props.dispatch(uploadOrderDocument(idPackage, idDocumentType, file, packages));
});
if(rejectedFiles && rejectedFiles.length) {
this.props.dispatch(badFile());
}
}
downloadDocument(document){
const fileUrl = `${API_SERVER}/utils/api/downloadFile?idDocument=${document.idDocument}&fileName=${document.documentName}.${document.extension}`
const fileName = document.documentName + '.' + document.extension;
fileHandler.download(fileUrl, fileName);
}
render() {
const {idDocumentType, cartItem, uploadedDocument, templateDocument, packages} = this.props;
return (<Col lg="6">
{
templateDocument &&
<div>
<Dropzone className="upload-file-drop-zone"
accept=".pdf,.docx,.doc,.xlsx,.xls,.odt,.ods"
onDrop={(acceptedFiles, rejectedFiles)=>{this.uploadFile(cartItem.idPackage, idDocumentType, acceptedFiles, rejectedFiles, packages)}}>
{
uploadedDocument
? <h6 className="drop-zone-text uploaded">{cartTexts.labels.FILE_UPLOADED_TEXT} {documentTypes[idDocumentType]} {cartTexts.labels.FILE}</h6>
: <h6 className="drop-zone-text">{cartTexts.labels.NO_FILE_UPLOAD_TEXT_1} {documentTypes[idDocumentType]} {cartTexts.labels.NO_FILE_UPLOAD_TEXT_2}</h6>
}
</Dropzone>
{
uploadedDocument &&
<div>
<div className="cart-subtitle">{cartTexts.labels.UPLOADED}:</div>
<div className="document-link" onClick={() => {this.downloadDocument(uploadedDocument)}}>
<i className="fa fa-file" aria-hidden="true"></i>
{' ' + uploadedDocument.documentName + ' (' + uploadedDocument.extension + ')'}
</div>
</div>
}
<div className="cart-subtitle">{cartTexts.labels.TEMPLATES}:</div>
<div className="document-link" onClick={() => {this.downloadDocument(templateDocument)}}>
<i className="fa fa-file" aria-hidden="true"></i>
{' ' + templateDocument.documentName + ' (' + templateDocument.extension + ')'}
</div>
</div>
}
</Col>);
}
}
export default connect()(CartUploadDocument);

View File

@@ -0,0 +1,71 @@
import React, {Component} from 'react';
import {connect} from 'react-redux';
import {Button, Row, Col} from 'reactstrap';
import Select from 'react-select';
import AddOrderProject from './AddOrderProject.jsx';
import {getOrderProjects} from '../../../actions/orderProjects/orderProjectsActions';
import {setDialogOpenFlag, setDialogContent} from '../../../actions/dialog/dialogActions';
import '../style/OrderProjects.css';
class OrderProjectsSelect extends Component {
constructor(props) {
super(props);
this.openDialog = this.openDialog.bind(this);
}
componentDidMount(){
this.props.dispatch(getOrderProjects());
}
openDialog(){
const dialogContent = {
header: 'Add Project',
TagName: AddOrderProject,
class: 'user-dialog',
hasCloseIcon: true
};
this.props.dispatch(setDialogOpenFlag(true));
this.props.dispatch(setDialogContent(dialogContent));
}
render() {
const {orderProjects, isLoading, idProject, handleChange} = this.props;
return (<Col md={4} id="order-projects">
{
isLoading &&
<div className="loader">
<i className="fa fa-spinner fa-spin fa-3x" aria-hidden="true"></i>
</div>
}
{orderProjects && !isLoading &&
<Row>
<Col md={10}>
<Select value={idProject}
name="idProject"
className="order-project-select"
placeholder="Project..."
options={orderProjects}
clearable={true}
onChange={(project) => {handleChange(project)}}/>
</Col>
<Col md={2}>
<Button onClick={this.openDialog} className="actions-button">
<i className="fa fa-plus" aria-hidden="true"></i>
</Button>
</Col>
</Row>
}
</Col>);
}
}
const mapStateToProps = (state) => ({
orderProjects: state.orderProjectsReducer.orderProjects,
isLoading: state.orderProjectsReducer.isLoading
});
export default connect(mapStateToProps)(OrderProjectsSelect);

View File

@@ -0,0 +1,47 @@
import React, {Component} from 'react';
import {connect} from 'react-redux';
import {cartTexts} from '../../../constants/cartConstants';
import {setDialogOpenFlag, setDialogContent} from '../../../actions/dialog/dialogActions';
import BidsList from './BidsList.jsx';
import '../style/PacakgeBids.css';
class PackageBids extends Component {
constructor(props){
super(props);
this.openDialog = this.openDialog.bind(this);
}
openDialog(){
const dialogContent = {
header: cartTexts.labels.AVAILABLE_BIDS,
TagName: BidsList,
class: 'bid-dialog',
hasCloseIcon: true,
params: {
bids: this.props.bids,
idCart: this.props.idCart,
idSelectedBid: this.props.idSelectedBid
}
};
this.props.dispatch(setDialogOpenFlag(true));
this.props.dispatch(setDialogContent(dialogContent));
}
render() {
const {bids} = this.props;
return (
<div id="cart-bids" className="cart-bids ">
{
bids && bids.length > 0 &&
<span onClick={this.openDialog} className="cart-bids-text">
{cartTexts.labels.BID_AVAILABLE}
{' '}<span className="fa fa-arrow-circle-left"></span>
</span>
}
</div>);
}
}
export default connect()(PackageBids);

View File

@@ -0,0 +1,50 @@
import React, {Component} from 'react';
import {FormGroup, Input} from 'reactstrap';
class SelectBillingAddress extends Component {
constructor(props) {
super(props);
this.handleOptionChange = this.handleOptionChange.bind(this);
}
handleOptionChange(){
this.props.handleBillingChange(this.props.billingAddress);
}
render() {
const {billingAddress, openAddressDialog, idSelectedBillingAddress} = this.props;
return (
<div className="address-row">
<FormGroup check>
<div>
<div className="address-text">
<Input id={'billing-addres-check-' + billingAddress.id} checked={idSelectedBillingAddress === billingAddress.id} type="radio" onChange={this.handleOptionChange} name="billingAddress" />
<div className="small-address-title">
{billingAddress.firstName} {billingAddress.lastName}
{
billingAddress.invoiceMail &&
<span>( {billingAddress.invoiceMail} )</span>
}
</div>
<div>
{billingAddress.countryName}, {billingAddress.city}, {billingAddress.detailedAddress}, {billingAddress.zipCode}
</div>
</div>
<div className="address-icons">
<i className="fa fa-pencil control-icon edit-address-btn"
onClick={()=> {openAddressDialog('edit', billingAddress)}}
id="edit-address-btn"
aria-hidden="true"></i>
</div>
</div>
</FormGroup>
</div>
);
}
}
export default SelectBillingAddress;

View File

@@ -0,0 +1,41 @@
import React, {Component} from 'react';
import {FormGroup, Input} from 'reactstrap';
class SelectDeliveryAddress extends Component {
constructor(props) {
super(props);
this.handleOptionChange = this.handleOptionChange.bind(this);
}
handleOptionChange(){
this.props.handleDeliveryChange(this.props.profileAddress);
}
render() {
const {profileAddress, openAddressDialog, idSelectedDeliveryAddress} = this.props;
return (
<div className="address-row">
<FormGroup check>
<div>
<div className="address-text">
<Input id={'delivery-addres-check-' + profileAddress.id} checked={idSelectedDeliveryAddress === profileAddress.id} type="radio" onChange={this.handleOptionChange} name="deliveryAddress" />
{profileAddress.countryName}, {profileAddress.city}, {profileAddress.detailedAddress}, {profileAddress.zipCode}
</div>
<div className="address-icons">
<i className="fa fa-pencil control-icon edit-address-btn"
onClick={()=> {openAddressDialog('edit', profileAddress)}}
id="edit-address-btn"
aria-hidden="true"></i>
</div>
</div>
</FormGroup>
</div>
);
}
}
export default SelectDeliveryAddress;