Add support for package payment methods and basic checkout proccess

This commit is contained in:
Almira Krdzic
2018-08-29 07:56:37 +02:00
parent 5ac3bfff36
commit 438d92e16e
35 changed files with 1600 additions and 309 deletions

View File

@@ -57,24 +57,21 @@ export const receiveCustomerDetails = (json) => ({
export const fetchCartCount = () => {
return dispatch => {
dispatch(requestShopCartCount());
//TODO : fetch cart count from woocommerce (requires plugin)
dispatch(receiveShopCartCount(0));
/*
return client.fetch({url: `${API_SERVER}/cart/api/getCartCount`}).then(response => {
if (typeof response.data !== 'undefined' && 'cartItemsCount' in response.data) {
dispatch(receiveShopCartCount(response.data.cartItemsCount));
return client.fetch({url: `${API_SERVER}/wp-json/wiaas/cart/count`}).then(response => {
if (typeof response.data !== 'undefined' && 'count' in response.data) {
dispatch(receiveShopCartCount(response.data.count));
}
}).catch(error => {
client.onError(error, dispatch);
});
*/
}
}
export const fetchCartItems = (isForSteps = false) => {
return dispatch => {
dispatch(requestShopCartItems());
return client.fetch({url: `${API_SERVER}/cart/api/getCartItems`}).then(response => {
return client.fetch({url: `${API_SERVER}/wp-json/wiaas/cart/items`}).then(response => {
if (typeof response.data !== 'undefined' && 'cartItems' in response.data) {
dispatch(receiveShopCartItems(response.data.cartItems));
dispatch(fetchCartDocuments(response.data.cartItems.map((cartItem) => cartItem.idPackage), isForSteps));
@@ -95,6 +92,7 @@ const updateCartItems = (newItem)=>(
export const updateQuantity = (cartItem, quantity, updateCartAllItems) => {
const params = {
idPackage: cartItem.idPackage || 0,
package_item_key: cartItem.key,
idCustomerInstance: cartItem.idCustomerInstance || 0,
idPrice: cartItem.idPrice || 0,
quantity
@@ -102,7 +100,7 @@ export const updateQuantity = (cartItem, quantity, updateCartAllItems) => {
return dispatch => {
return client.fetch({
url: `${API_SERVER}/cart/api/updateQuantity`,
url: `${API_SERVER}/wp-json/wiaas/cart/update-quantity`,
method: 'post',
data: params
}).then(response => {
@@ -124,12 +122,14 @@ export const updateQuantity = (cartItem, quantity, updateCartAllItems) => {
}
}
export const removeCartItem = (idCart) => {
export const removeCartItem = (cartItemKey) => {
return dispatch => {
return client.fetch({
url: `${API_SERVER}/cart/api/removeFromCart`,
url: `${API_SERVER}/wp-json/wiaas/cart/remove`,
method: 'post',
data: {idCart}
data: {
package_item_key: cartItemKey
}
}).then(response => {
if (typeof response.data !== 'undefined' && 'messages' in response.data) {
dispatch(updateMessages(response.data.messages, cartMessages));
@@ -180,15 +180,46 @@ const resetSteps = () => ({type: RESET_STEPS});
export const getCustomerDetails = () => {
return dispatch => {
return client.fetch({url: `${API_SERVER}/cart/api/getCustomerDetails`})
.then(response => {
if (typeof response.data !== 'undefined' && response.data.customerDetails) {
const customerDetails = response.data.customerDetails;
dispatch(receiveCustomerDetails(customerDetails));
}
}).catch(error => {
client.onError(error, dispatch);
});
dispatch(receiveCustomerDetails({
"companyName": "Coor Service Management AB",
"vatCode": "556084-6783",
"details": {
"idBillingAddress": null,
"idDeliveryAddress": null,
"idProject": null,
"reference": null,
"tender": null
},
"billing": [
{
"id": 1,
"city": "Göteborg",
"countryName": "SE",
"detailedAddress": "Lilla Bommen 2",
"firstName": "Customer",
"lastName": "User",
"zipCode": "12323"
}
],
"deliveryAddresses": [
{
"id": 1,
"city": "Göteborg",
"countryName": "Göteborg",
"detailedAddress": "Lilla Bommen 2",
"zipCode": "12323"
}
]
}));
// return client.fetch({url: `${API_SERVER}/wp-json/wiaas/cart/customer-details`})
// .then(response => {
// if (typeof response.data !== 'undefined' && response.data.customerDetails) {
// const customerDetails = response.data.customerDetails;
// dispatch(receiveCustomerDetails(customerDetails));
// }
// }).catch(error => {
// client.onError(error, dispatch);
// });
}
}
@@ -239,8 +270,8 @@ export const fetchCartDocuments = (packages, isForSteps = false) => {
dispatch(requestCartDocuments());
return client.fetch({
url: `${API_SERVER}/cart/api/getCartDocuments`,
method: 'post',
url: `${API_SERVER}/wp-json/wiaas/cart/documents`,
method: 'get',
data: {packages}
}).then(response => {
if (response.data) {
@@ -262,18 +293,20 @@ export const selectCountryBilling = (country) => ({type: SELECT_COUNTRY_BILLING,
export const saveOrderDetails = (orderDetails, cartItems) => {
const orderInfo = {orderDetails, cartItems};
return dispatch => {
return client.fetch({
url: `${API_SERVER}/cart/api/saveOrderDetails`,
method: 'post',
data: {orderDetails, cartItems}
}).then(response => {
if (typeof response.data !== 'undefined' && 'messages' in response.data) {
dispatch(getCustomerDetails());
dispatch(setOrderInfo(orderInfo));
}
}).catch(error => {
client.onError(error, dispatch);
});
dispatch(getCustomerDetails());
dispatch(setOrderInfo(orderInfo));
// return client.fetch({
// url: `${API_SERVER}/cart/api/saveOrderDetails`,
// method: 'post',
// data: {orderDetails, cartItems}
// }).then(response => {
// if (typeof response.data !== 'undefined' && 'messages' in response.data) {
// dispatch(getCustomerDetails());
// dispatch(setOrderInfo(orderInfo));
// }
// }).catch(error => {
// client.onError(error, dispatch);
// });
}
}
@@ -286,9 +319,9 @@ export const placeOrder = (orderInfo) => {
const {orderDetails, cartItems} = orderInfo;
return dispatch => {
return client.fetch({
url: `${API_SERVER}/cart/api/placeOrder`,
url: `${API_SERVER}/wp-json/wiaas/cart/place-order`,
method: 'post',
data: {orderDetails, cartItems}
data: orderDetails
}).then(response => {
if (typeof response.data !== 'undefined' && 'messages' in response.data) {
dispatch(updateMessages(response.data.messages, cartMessages));

View File

@@ -16,6 +16,7 @@ import {
} from '../../constants/coMarketConstants';
import {updateMessages} from '../notification/notificationActions';
import {fetchCartCount} from '../cart/cartActions';
import { fromWCPackage } from '../../helpers/PackageHelper';
const client = new HtmlClient();
const priceHelper = new PriceHelper();
@@ -41,28 +42,27 @@ export const fetchPackageDetails = (params) => {
return dispatch => {
dispatch(requestPackageDetails());
return client.fetch({
url: `${API_SERVER}/coMarket/api/getShopPackageDetails`,
method: 'post',
data: params
url: `${API_SERVER}/wp-json/wc/v2/products/${params.idPackage}`,
method: 'get'
})
.then(response => {
if(response.data){
const jsonData = response.data;
const packageData = fromWCPackage(response.data);
dispatch(clearSelections());
if(jsonData.prices && jsonData.prices.length){
dispatch(selectAgreement(jsonData.prices[0]));
if(packageData.prices && packageData.prices.length){
dispatch(selectAgreement(packageData.prices[0]));
}
if(jsonData.groups){
Object.keys(jsonData.groups).forEach((idGroup) => {
const defaultOption = jsonData.groups[idGroup].options.find((option) => {return parseInt(option.isDefault, 10) === 1});
if(packageData.groups){
Object.keys(packageData.groups).forEach((idGroup) => {
const defaultOption = packageData.groups[idGroup].options.find((option) => {return parseInt(option.isDefault, 10) === 1});
if(defaultOption){
dispatch(selectOption(idGroup, defaultOption));
}
});
}
dispatch(recievePackageDetails(jsonData));
dispatch(recievePackageDetails(packageData));
}
})
.catch(error => {
@@ -104,25 +104,25 @@ const requestAddToCart = () => ({
});
export const addToCart = (addParams) => {
const options = generateOptions(addParams.selectedOptions, addParams.selectedAdditionals, addParams.selectedAgreement);
// const options = generateOptions(addParams.selectedOptions, addParams.selectedAdditionals, addParams.selectedAgreement);
const params = {
idPackage: addParams.selectedPackage.packageInfo.idPackage,
idPrice: addParams.selectedAgreement.idPrice,
options: options.extraPackages
'package_id': addParams.selectedPackage.id,
'price_id': addParams.selectedAgreement.idPrice,
//options: options.extraPackages
};
if(options.unavailablePackages.length){
const unavailable = options.unavailablePackages.map((unavailable) =>{return unavailable.optionName || unavailable.packageName;});
const message = coMarketMessages.UNAVAILABLE_PACKAGES + ' ' + unavailable.join();
return dispatch => {dispatch(updateMessages([{code: 'warning', message}], coMarketMessages))};
}
// if(options.unavailablePackages.length){
// const unavailable = options.unavailablePackages.map((unavailable) =>{return unavailable.optionName || unavailable.packageName;});
// const message = coMarketMessages.UNAVAILABLE_PACKAGES + ' ' + unavailable.join();
//
// return dispatch => {dispatch(updateMessages([{code: 'warning', message}], coMarketMessages))};
// }
return dispatch => {
dispatch(requestAddToCart());
return client.fetch({
url: `${API_SERVER}/coMarket/api/addToCart`,
url: `${API_SERVER}/wp-json/wiaas/cart/add`,
method: 'post',
data: params
})

View File

@@ -49,8 +49,36 @@ export const validateAccessToken = (token) => {
// const serverTime = response.data.serverTime || 1;
dispatch(loggedIn({
accessToken: token
// userInfo: response.data.userInfo
accessToken: token,
userInfo: {
"id": 2,
"name": "Customer User",
"mail": "customer@mail.com",
"phone": "",
"userType": "customer",
"vatCode": "556084-6783",
"companyName": "Coor Service Management AB",
"billingAddresses": [
{
"id": 1,
"city": "fsdfcsdfcs",
"countryName": "SE",
"detailedAddress": "sdfcsvfsdf, fdfvds, fdfvds",
"firstName": "Customer",
"lastName": "User",
"zipCode": "323232"
}
],
"profileAddresses": [
{
"id": 1,
"city": "fsdfcsdfcs",
"countryName": "fsdfcsdfcs",
"detailedAddress": "sdfcsvfsdf, fdfvds, fdfvds",
"zipCode": "323232"
}
]
}
}));
// refreshToken = response.data.refreshToken;
// startRefreshTimer(dispatch, serverTime);

View File

@@ -33,18 +33,41 @@ const generateOptions = (orderProjects) => {
export const getOrderProjects = () => {
return dispatch => {
dispatch(requestOrderProjects());
return htmlClient.fetch({
url: `${API_SERVER}/orderProjects/api/getOrderProjects`
})
.then(response => {
if (response.data) {
const orderProjects = generateOptions(response.data);
dispatch(recieveOrderProjects(orderProjects));
}
})
.catch(error => {
htmlClient.onError(error, dispatch);
});
dispatch(recieveOrderProjects(generateOptions([
{
"idProject": 1,
"projectName": "Innovation Center",
"isAvailable": 1
},
{
"idProject": 2,
"projectName": "Demo01",
"isAvailable": 1
},
{
"idProject": 3,
"projectName": "Kontorsrådet",
"isAvailable": 1
},
{
"idProject": 4,
"projectName": "PerProj01",
"isAvailable": 1
}
])));
// return htmlClient.fetch({
// url: `${API_SERVER}/orderProjects/api/getOrderProjects`
// })
// .then(response => {
// if (response.data) {
// const orderProjects = generateOptions(response.data);
// dispatch(recieveOrderProjects(orderProjects));
// }
// })
// .catch(error => {
// htmlClient.onError(error, dispatch);
// });
}
}

View File

@@ -29,19 +29,49 @@ export const recieveProfileInfo = (json) => ({
export const fetchProfileInfo = (idUser) => {
return dispatch => {
dispatch(requestProfileInfo());
return client.fetch({
url: `${API_SERVER}/profileSettings/api/getProfileInfo`,
method: 'post',
data: {idUser}
})
.then(response => {
if(response.data){
dispatch(recieveProfileInfo(response.data));
dispatch(recieveProfileInfo({
"id": 2,
"name": "Customer User",
"mail": "customer@mail.com",
"phone": "",
"userType": "customer",
"vatCode": "556084-6783",
"companyName": "Coor Service Management AB",
"billingAddresses": [
{
"id": 1,
"city": "Göteborg",
"countryName": "SE",
"detailedAddress": "Lilla Bommen 2",
"firstName": "Customer",
"lastName": "User",
"zipCode": "12323"
}
})
.catch(error => {
client.onError(error, dispatch);
});
],
"profileAddresses": [
{
"id": 1,
"city": "Göteborg",
"countryName": "Göteborg",
"detailedAddress": "Lilla Bommen 2",
"zipCode": "12323"
}
]
}));
// return client.fetch({
// url: `${API_SERVER}/wp-json/wiaas/cart/customer-info`,
// method: 'get',
// data: {idUser}
// })
// .then(response => {
// if(response.data){
// dispatch(recieveProfileInfo(response.data));
// }
// })
// .catch(error => {
// client.onError(error, dispatch);
// });
}
};
@@ -107,17 +137,32 @@ const recieveCountries = (json) => ({
export const fetchCountries = () => {
return dispatch => {
dispatch(requestCountries());
return client.fetch({
url: `${API_SERVER}/profileSettings/api/getCoutnries`,
method: 'get'
})
.then(response => {
if(response.data){
dispatch(recieveCountries(response.data));
}
})
.catch(error => {
client.onError(error, dispatch);
});
dispatch(recieveCountries([
{
"idCountry": 3,
"countryName": "Denmark"
},
{
"idCountry": 4,
"countryName": "Finland"
},
{
"idCountry": 2,
"countryName": "Sweden"
}
]));
// return client.fetch({
// url: `${API_SERVER}/profileSettings/api/getCoutnries`,
// method: 'get'
// })
// .then(response => {
// if(response.data){
// dispatch(recieveCountries(response.data));
// }
// })
// .catch(error => {
// client.onError(error, dispatch);
// });
}
};

View File

@@ -96,7 +96,7 @@ export const coMarketTexts = {
AVAILABLE_IN: 'Available in',
DOCUMENTS: 'Documents',
NEW_PRODUCTS: 'New Products',
SEARCH_PACKAGE: 'search package...',
SEARCH_PACKAGE: 'Search...',
COMMERCIAL_HEADER_1: 'Next-generation Collaboration',
COMMERCIAL_HEADER_2: `Ricoh is now launching Huddle Concept - a stylishly designed,
multifunctional workspace that integrates video conferencing

View File

@@ -45,7 +45,8 @@ class CartCustomerDetailsContainer extends Component {
this.props.dispatch(fetchCartItems());
this.props.dispatch(setNextActionFct(this.handleNextAction));
this.props.dispatch(setPrevActionFct(this.handlePrevAction));
this.props.dispatch(fetchProfileInfo(this.props.userInfo.wiaas_id_user));
//this.props.dispatch(fetchProfileInfo(this.props.userInfo.wiaas_id_user));
this.props.dispatch(fetchProfileInfo());
this.props.dispatch(fetchCountries());
}
@@ -191,7 +192,7 @@ class CartCustomerDetailsContainer extends Component {
(profileInfo && !isProfileLoading) &&
<ProfileAddressesContainer
params={{location: 'cart', handleDeliveryChange: this.handleDeliveryChange, idSelectedDeliveryAddress: this.state.delivery.id}}
idUser={this.props.userInfo.wiaas_id_user}/>
idUser={0}/>
}
</Form>
</div>
@@ -205,7 +206,7 @@ class CartCustomerDetailsContainer extends Component {
<BillingAddressesContainer
idCompany={profileInfo.idCompany}
params={{location: 'cart', handleBillingChange: this.handleBillingChange, idSelectedBillingAddress: this.state.billing.id}}
idUser={this.props.userInfo.wiaas_id_user}/>
idUser={0}/>
}
</Form>
</div>

View File

@@ -4,17 +4,11 @@ import {cartTexts} from '../../../constants/cartConstants';
class CartIcon extends Component {
render() {
let {cartCount} = this.props;
cartCount = parseInt(cartCount, 10);
cartCount = parseInt(cartCount, 10) || 0;
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>
}
{cartCount}
</span>
);
}

View File

@@ -14,7 +14,7 @@ class CartItem extends Component {
this.state = {
tooltipOpen: false,
itemQuantity: 1,
idCart: 0
key: 0
};
this.toggleTooltip = this.toggleTooltip.bind(this);
@@ -58,11 +58,11 @@ class CartItem extends Component {
}
removeItemFromCart() {
this.props.dispatch(removeCartItem(this.state.idCart));
this.props.dispatch(removeCartItem(this.state.key));
}
setDialogParams(cartItem, dialogContent) {
this.setState({idCart: cartItem.idCart});
this.setState({key: cartItem.key});
this.props.dispatch(setDialogOpenFlag(true));
dialogContent.bodyVariable = cartItem.packageName;
this.props.dispatch(setDialogContent(dialogContent));
@@ -144,91 +144,98 @@ class CartItem extends Component {
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 id={"item-row-in-cart-" + cartItem.key} className="cart-show-items">
<Col className="">
<Row className="cart-item-details justify-content-between">
<Col id={"item-package-name-" + cartItem.key}
xl="8" lg="8" md="7" sm="12"
className="item-name">
{cartItem.packageName}
<PackageBids idSelectedBid={cartItem.idSelectedBid} key={cartItem.key} bids={cartItem.bids}/>
</Col>
<Col xl="4" lg="4" md="5" sm="12">
<Row className="flex-nowrap justify-content-end">
<Col
id={"item-quantity-" + cartItem.key}
className="item-quantity col-auto"
>
{ 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>
{ !isFormDisabled && <div className="wiaas-divider"></div> }
{
!isFormDisabled && (<Col className="d-flex align-items-center col-auto">
<i id={'remove-item-' + cartItem.key + '-' + cartItem.idPackage}
className="fa fa-trash-o remove-item"
aria-hidden="true"
onClick={() => this.setDialogParams(cartItem, dialogContent) }></i>
<Tooltip target={'remove-item-' + cartItem.key + '-' + cartItem.idPackage}
placement="bottom"
isOpen={this.state.tooltipOpen}
toggle={this.toggleTooltip}>
{cartTexts.labels.REMOVE_FROM_CART}
</Tooltip>
</Col>)
}
</Row>
</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">
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.length > 0 &&
cartItem.options.map((packageOption) =>
<Row className="cart-item-small-details" key={"package-option-" + cartItem.idCart + "-" + packageOption.idOptionPackage}>
<Row className="cart-item-small-details" key={"package-option-" + cartItem.key + "-" + 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}>
<Col lg="7" xs="7" id={"item-option-" + cartItem.key + "-" + packageOption.idOptionPackage}>
{packageOption.packageName}
</Col>
</Row>
)
}
{cartItem.additionalPackages.length > 0 &&
}
{cartItem.additionalPackages.length > 0 &&
cartItem.additionalPackages.map((additionalPackage) =>
<Row className="cart-item-small-details" key={"additional-package-" + cartItem.idCart + "-" + additionalPackage.idAdditionalPackage}>
<Row className="cart-item-small-details" key={"additional-package-" + cartItem.key + "-" + 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}>
<Col lg="7" xs="7" id={"item-additional-" + cartItem.key + "-" + 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>
}
<Row className="cart-item-small-details justify-content-between item-price">
<Col className="d-flex align-items-center">
<span className="item-payment-type">{cartItem.payType}:</span>
</Col>
<Col className="d-flex col-auto">
<table className="price-table">
<thead>
<tr>
<th>{cartTexts.labels.ON_DELIVERY}</th>
<th>{cartTexts.labels.MONTHLY}</th>
</tr>
</thead>
<tbody>
</thead>
<tbody>
<tr>
<td>
{
@@ -260,11 +267,12 @@ class CartItem extends Component {
}
</td>
</tr>
</tbody>
</table>
</Col>
</Row>
</div>
</tbody>
</table>
</Col>
</Row>
</Col>
</Row>
);
}
}

View File

@@ -2,6 +2,10 @@
#cart-count {
vertical-align: middle;
color: $cart-count-color;
font-size: 1.5rem;
border-radius: 1rem;
font-family: arial,sans-serif;
}
#cart-container {
@@ -12,7 +16,7 @@
border-radius: $box-radius;
.cart-show-items {
padding-top: 1rem;
padding: 1rem;
}
.quantity-field {
@@ -22,7 +26,7 @@
}
.remove-item {
color: $redColor;
color: #111;
cursor: pointer;
font-size: 1.3rem;
padding-top: 0.375rem;
@@ -42,6 +46,30 @@
font-weight: $font-weight;
}
.cart-item-details {
.item-name {
}
.item-quantity {
}
.wiaas-divider {
height: 40px;
margin: 0 20px;
min-width: 1px;
}
}
.item-payment-type {
font-weight: 600;
}
.item-price {
background-color: $hoverColor;
margin-top: 1rem;
border-radius: $box-radius;
}
.cart-total-price {
padding: 1rem 0;
font-size: $font-size-big;
@@ -163,6 +191,11 @@
.cart-address-box {
margin-top: 2rem;
}
#order-projects .actions-button, .add-address-btn, .address-icons {
opacity: 0.3;
pointer-events: none;
}
}
#cart-customer-main-information-container {

View File

@@ -22,12 +22,13 @@ class CoMarketNavContainer extends Component {
render() {
return (
<Row className="co-market-nav">
<Col xl="4" lg="3" md="3" sm="12" xs="12" className="co-market-nav-buttons">
<Col className="col-auto co-market-nav-buttons">
<div className="co-market-nav-div">
{coMarketTexts.labels.NEW_PRODUCTS}
</div>
<div className="wiaas-divider"></div>
</Col>
<Col xl="4" lg="4" md="4" xs="12" className="search-layer">
<Col className="search-layer">
<div className="co-market-nav-div">
<i className="search-package-icon fa fa-search" aria-hidden="true"></i>
<Input className="wiaas-input" onChange={this.handleSearchChange} value={this.state.searchValue} placeholder={coMarketTexts.labels.SEARCH_PACKAGE}/>

View File

@@ -54,14 +54,16 @@ class CoMarketPackageDetailsContainer extends Component {
<Row>
<Col xl="6" lg="5" md="12" xs="12">
<PackageInfo
packageInfo={selectedPackage.packageInfo}
name={selectedPackage.name}
reference={selectedPackage.reference}
shortDescription={selectedPackage.shortDescription}
country={selectedPackage.country}
countryCode={selectedPackage.countryCode}
documents={selectedPackage.documents} />
</Col>
<Col xl="6" lg="7" md="12" xs="12">
<div id="shop-package-buy-info">
<PackagePrice
country={selectedPackage.country} />
{
selectedPackage.groups && Object.keys(selectedPackage.groups).length > 0 && selectedAgreement &&
<PackageOptions
@@ -76,14 +78,16 @@ class CoMarketPackageDetailsContainer extends Component {
}
<AgreementOptions
prices={selectedPackage.prices}
country={selectedPackage.country}/>
<Button id="add-to-cart-btn"
className="add-to-cart-btn"
onClick={this.handleAddToCart}
color="secondary">
<i className="fa fa-shopping-cart" aria-hidden="true"></i>
{' '}{coMarketTexts.buttons.ADD_TO_CART}
</Button>
currency={selectedPackage.currency}/>
<Row className="justify-content-end" style={{ marginTop: 30 }}>
<Button id="add-to-cart-btn"
className="add-to-cart-btn"
onClick={this.handleAddToCart}
color="secondary">
<i className="fa fa-shopping-cart" aria-hidden="true"></i>
{' '}{coMarketTexts.buttons.ADD_TO_CART}
</Button>
</Row>
{messages && <span>{messages[0].message}</span>}
</div>
</Col>

View File

@@ -1,6 +1,6 @@
import React, {Component} from 'react';
import {connect} from 'react-redux';
import {Label, Popover, PopoverBody, Input, Col} from 'reactstrap';
import {Label, Popover, PopoverBody, Input, Col, Row} from 'reactstrap';
import {selectAgreement} from '../../../actions/coMarket/coMarketPackageDetailsActions';
import PriceHelper from '../../../helpers/coMarket/PriceHelper';
import {coMarketTexts} from '../../../constants/coMarketConstants';
@@ -35,49 +35,39 @@ class AgreementOptionItem extends Component {
}
render() {
const {price, selectedAgreement, country} = this.props;
const {price, selectedAgreement, currency} = this.props;
return (
<Col xl="4" lg="4" md="6" xs="6" className="option-value">
<div className={'option-selection ' + this.getClass(selectedAgreement, price)}>
<Label check>
<Row
className={`option-selection ${this.getClass(selectedAgreement, price)}`}
>
<Label check className="row flex-grow-1 no-wrap">
<Col className="d-flex align-items-center">
<Input type="radio"
name="price-type"
onChange={this.handleOptionChange}
checked={selectedAgreement.idPaymentType === price.idPaymentType}
value={price.idPaymentType}
className="price-type-option"/>
<div className="option-name">{price.payType}</div>
<div className="option-prices">
<table className="price-table option-price-table">
<thead>
<tr>
<th>{coMarketTexts.labels.ON_DELIVERY}</th>
<th>{coMarketTexts.labels.MONTHLY}</th>
</tr>
</thead>
<tbody>
<tr>
<td>{price.fixedExtra.toLocaleString()} {country.currency}</td>
<td>
{
priceHelper.hasRecurrentPrice(price)
? <div className="option-value-text monthly-price">
{priceHelper.sumPrices([price.recurentExtra, price.servicesExtra]).toLocaleString()} {country.currency}
</div>
: <div className="option-value-text monthly-price"> 0 </div>
}
</td>
</tr>
</tbody>
</table>
</div>
</Label>
<i className="price-info-btn fa fa-info-circle"
aria-hidden="true"
id={'info-additonal-' + price.idPaymentType}
onClick={this.toggle}></i>
</div>
<span className="option-name">{price.payType}</span>
</Col>
<Col className="d-flex align-items-center">
<span>{price.fixedExtra.toLocaleString()} {currency}</span>
</Col>
<Col className="d-flex align-items-center">
<span className="option-value-text monthly-price">
{
priceHelper.hasRecurrentPrice(price)
? `${priceHelper.sumPrices([price.recurentExtra, price.servicesExtra]).toLocaleString()} ${currency}`
: '0'
}
</span>
</Col>
</Label>
<i className="price-info-btn fa fa-info-circle d-flex align-items-center"
aria-hidden="true"
id={'info-additonal-' + price.idPaymentType}
onClick={this.toggle}></i>
<Popover placement="bottom"
isOpen={this.state.popoverOpen}
target={'info-additonal-' + price.idPaymentType}
@@ -90,7 +80,7 @@ class AgreementOptionItem extends Component {
price.recurentExtra > 0 &&
<div className="package-price-recurrent">
<span className="price-info-title">{coMarketTexts.labels.RECURRENT_PRICE}: </span>
{(price.recurentExtra).toLocaleString()} {country.currency} / {price.periodUnit}
{(price.recurentExtra).toLocaleString()} {currency} / {price.periodUnit}
{
price.packagePayPeriod > 0 &&
<span>
@@ -103,7 +93,7 @@ class AgreementOptionItem extends Component {
price.servicesExtra > 0 &&
<div className="services-price-recurrent">
<span className="price-info-title">{coMarketTexts.labels.SERVICE_PRICE}: </span>
{(price.servicesExtra).toLocaleString()} {country.currency} / {price.periodUnit}
{(price.servicesExtra).toLocaleString()} {currency} / {price.periodUnit}
{
price.servicesContractPeriod > 0 &&
<span>
@@ -115,7 +105,7 @@ class AgreementOptionItem extends Component {
</div>
</PopoverBody>
</Popover>
</Col>
</Row>
);
}
}

View File

@@ -1,24 +1,86 @@
import React, {Component} from 'react';
import {Row} from 'reactstrap';
import {Row, Col} from 'reactstrap';
import AgreementOptionItemContainer from './AgreementOptionItemContainer.jsx';
import {coMarketTexts} from '../../../constants/coMarketConstants';
import {connect} from "react-redux";
class AgreementOptions extends Component {
constructor(props) {
super(props);
this.getFinalPrice = this.getFinalPrice.bind(this);
this.filterByAgreement = this.filterByAgreement.bind(this);
}
filterByAgreement(price) {
return price.idPaymentType === this.props.selectedAgreement.idPaymentType;
}
getExtra(selected, priceType) {
const extraPriceObj = selected.prices.find(this.filterByAgreement);
const extraPrice = extraPriceObj ? extraPriceObj[priceType] : 0;
return extraPrice;
}
getFinalPrice(selectedAgreement, selectedOptions, selectedAdditionals, priceType) {
let price = selectedAgreement ? selectedAgreement[priceType] : 0;
if(selectedAgreement && selectedOptions) {
Object.keys(selectedOptions).forEach((idGroup) => {
price += this.getExtra(selectedOptions[idGroup], priceType);
});
}
if(selectedAgreement && selectedAdditionals) {
selectedAdditionals.forEach((additional) => {
price += this.getExtra(additional, priceType);
});
}
return price;
}
render() {
const {prices, country} = this.props;
const {prices, currency, selectedAgreement, selectedOptions, selectedAdditionals} = this.props;
return (
<div className="shop-package-options">
<h6 className="shop-package-label options-header">{coMarketTexts.labels.AGREEMENT_OPTIONS}:</h6>
<Row>
<div className="shop-package-pricing">
<Row className="justify-content-end">
<Col className="col-4">
<h6 className="shop-package-label options-header">{coMarketTexts.labels.ON_DELIVERY}</h6>
</Col>
<Col className="col-4">
<h6 className="shop-package-label options-header">{coMarketTexts.labels.MONTHLY}</h6>
</Col>
</Row>
<div className="shop-package-options">
{
prices && prices.map((price) => {
return <AgreementOptionItemContainer key={'agreement-' + price.idPaymentType} country={country} price={price}/>
return (<AgreementOptionItemContainer key={'agreement-' + price.idPaymentType} currency={currency} price={price}/>)
})
}
</div>
<Row className="justify-content-end shop-package-calculated-price">
<Col>
<h6>Price:</h6>
</Col>
<Col className="col-4">
{this.getFinalPrice(selectedAgreement, selectedOptions, selectedAdditionals, 'fixedExtra').toLocaleString()} {currency}
</Col>
<Col className="col-4">
{(this.getFinalPrice(selectedAgreement, selectedOptions, selectedAdditionals, 'recurentExtra')
+ this.getFinalPrice(selectedAgreement, selectedOptions, selectedAdditionals, 'servicesExtra')).toLocaleString()}
{' '}{currency}
</Col>
</Row>
</div>
);
}
}
export default AgreementOptions;
const mapStateToProps = (state) => ({
selectedAgreement: state.coMarketPackageDetailsReducer.selectedAgreement,
selectedOptions: state.coMarketPackageDetailsReducer.selectedOptions,
selectedAdditionals: state.coMarketPackageDetailsReducer.selectedAdditionals
});
export default connect(mapStateToProps) (AgreementOptions);

View File

@@ -14,28 +14,26 @@ class PackageInfo extends Component {
}
render() {
const {packageInfo, documents} = this.props;
const { name, reference, shortDescription, country, countryCode, documents } = this.props;
return (
<div id="shop-package-general-info" className="shop-package-general-info">
{ packageInfo &&
<span>
<Col lg="12"
className="shop-package-title"><h4>{packageInfo.name}</h4></Col>
<Col lg="12"
className="shop-package-reference"><h6>{packageInfo.reference}</h6></Col>
<Col lg="12"
dangerouslySetInnerHTML={{__html: packageInfo.shortDescription}}
className="shop-package-full-description"></Col>
<Col lg="12"
className="shop-package-details-country">
<div className="shop-package-label">{coMarketTexts.labels.AVAILABLE_IN}:</div>
<div className="shop-package-text">
{packageInfo.country} <span className={'flag-icon flag-icon-' + packageInfo.countryCode}></span>
</div>
</Col>
</span>
}
<span>
<Col lg="12"
className="shop-package-title"><h4>{name}</h4></Col>
<Col lg="12"
className="shop-package-reference"><h6>{reference}</h6></Col>
<Col lg="12"
dangerouslySetInnerHTML={{__html: shortDescription}}
className="shop-package-full-description"></Col>
<Col lg="12"
className="shop-package-details-country">
<div className="shop-package-label">{coMarketTexts.labels.AVAILABLE_IN}:</div>
<div className="shop-package-text">
{country} <span className={'flag-icon flag-icon-' + countryCode}></span>
</div>
</Col>
</span>
{
documents && documents.length > 0 &&
<Col lg="12"

View File

@@ -39,7 +39,7 @@ class PackagePrice extends Component {
}
render() {
const {country, selectedAgreement, selectedOptions, selectedAdditionals} = this.props;
const {currency, selectedAgreement, selectedOptions, selectedAdditionals} = this.props;
return (
<div className="selection-price">
@@ -55,12 +55,12 @@ class PackagePrice extends Component {
<tbody>
<tr>
<td>
{this.getFinalPrice(selectedAgreement, selectedOptions, selectedAdditionals, 'fixedExtra').toLocaleString()} {country.currency}
{this.getFinalPrice(selectedAgreement, selectedOptions, selectedAdditionals, 'fixedExtra').toLocaleString()} {currency}
</td>
<td>
{(this.getFinalPrice(selectedAgreement, selectedOptions, selectedAdditionals, 'recurentExtra')
+ this.getFinalPrice(selectedAgreement, selectedOptions, selectedAdditionals, 'servicesExtra')).toLocaleString()}
{' '}{country.currency}
{' '}{currency}
</td>
</tr>
</tbody>

View File

@@ -11,13 +11,14 @@ class ShopItem extends Component {
render() {
const {shopPackage, idCommercialLead} = this.props;
return (
<Col xl="3" lg="4" md="6" sm="12" xs="12">
<Col xl="3" lg="3" md="4" sm="6" xs="12">
<Card className="shop-package-item">
<div
className="shop-image-photo"
style={{'backgroundImage': `url(${shopPackage.image})`}}
/>
<img
className="card-img-top shop-image-photo"
src={shopPackage.image}
alt="Card image cap"/>
<CardBody>
<CardTitle className="shop-package-title">
<Link to={`/co-market/${idCommercialLead}/${shopPackage.id}`}>

View File

@@ -56,8 +56,18 @@
margin-left: 0.2rem;
}
.wiaas-box-header {
padding: 1rem;
align-items: center;
display: flex;
.wiaas-box-visibility-icon {
top: 50%;
transform: translateY(-50%);
}
}
.co-market-nav {
font-size: $font-size-msmall;
font-size: $font-size-small;
text-align: left;
color: $warmGreyColor;
vertical-align: middle;
@@ -77,17 +87,20 @@
.search-layer div{
position: relative;
flex-grow: 1;
padding-right: 1rem;
}
.wiaas-input {
border-radius: 3.125rem;
border-radius: 4rem;
background-color: $whiteColor;
border: solid 1px $borderColor;
padding: 0.2rem 1.4rem;
font-size: $font-size-xsmal;
padding: 0.2rem 3rem;
font-size: $font-size-small;
font-weight: 300;
text-align: left;
color: $warmGreyColor;
height: 2.2rem;
}
input:focus {
@@ -96,16 +109,15 @@
.search-package-icon {
position: absolute;
font-size: $font-size-xsmal;
left: 0.4rem;
top: 0.3rem;
font-size: $font-size-normal;
left: 1.6rem;
top: 0.6rem;
color: $warmGreyColor;
}
.shop-image-photo{
width:100%;
height:129px;
background-size: cover;
object-fit: cover;
}
}

View File

@@ -55,6 +55,16 @@
#shop-package-buy-info{
padding: 2rem;
.shop-package-pricing {
> div.row {
margin: 0 32px 0 0;
}
}
.shop-package-calculated-price {
font-weight: $font-weight;
}
.shop-package-options{
margin: 1rem 0;
border-bottom: 2px solid $title-color;
@@ -71,7 +81,7 @@
.price-info-btn {
color: $info-color;
cursor: pointer;
margin-left: 0.2rem;
padding: 0.5rem;
}
.add-to-cart-btn {
@@ -83,32 +93,39 @@
}
.selected-option {
font-weight: $font-weight;
background: $hoverColor;
border-radius: $box-radius;
}
.option-selection {
display: inline-block;
vertical-align: top;
padding: 0.5rem;
padding: 0.5rem 0;
margin: 0;
flex-wrap: nowrap;
> label {
cursor: pointer;
margin: 0;
flex-wrap: nowrap;
}
input.price-type-option {
position: relative;
margin: 0 10px 0 0;
}
span.option-name {
font-size: $font-size-small;
}
}
.option-selection:hover {
background: $footer-background;
color: $whiteColor;
border-radius: $box-radius;
}
.option-selection:hover .price-info-btn {
color: $whiteColor;
}
.option-name {
font-size: $font-size-msmall;
height: 2rem;
}
.option-description {
padding-top: 0.5rem;
font-size: $font-size-msmall;
@@ -131,11 +148,6 @@
font-weight: bold;
}
.option-prices {
margin-top: 0.5rem;
border-radius: $box-radius;
}
.price-table {
width: 8rem;
}

View File

@@ -7,7 +7,7 @@ import '../style/Orders.css';
class OrderPackage extends Component {
calculateRecuringPrice(packageDetails) {
return packageDetails.units * (parseFloat(packageDetails.packageRecuringPrice) + parseFloat(packageDetails.packageServicePrice));
return packageDetails.quantity * (parseFloat(packageDetails.recurringPrice) + parseFloat(packageDetails.servicePrice));
}
calculateQuantityPrice(quantity, price, recurringPrice = 0) {
@@ -68,7 +68,7 @@ class OrderPackage extends Component {
({orderPackage.paymentType})
</WiaasTableCol>
<WiaasTableCol header="Services and support">
{this.calculateQuantityPrice(orderPackage.quantity, orderPackage.servicePrice, orderPackage.recurringPrice).toLocaleString() + ' / ' + orderPackage.periodUnit + ' '}
{this.calculateRecuringPrice(orderPackage).toLocaleString() + ' / ' + orderPackage.periodUnit + ' '}
{orderTexts.labels.EXTEND} {orderPackage.periodUnit} (Max {orderPackage.maxContractPeriod})
</WiaasTableCol>
<WiaasTableCol>

View File

@@ -16,7 +16,7 @@ export const fromWCOrder = (WCOrder) => {
dateCreated: formatDate(WCOrder['date_created']),
dateCompleted: formatDate(WCOrder['date_completed']),
estimatedDeliveryDate: undefined,
reference: 'reference field',
reference: WCOrder['reference'],
assignedTo: 'assigned to',
fixedPrice: WCOrder.total,
recurringPrice: 0,

View File

@@ -6,11 +6,27 @@ export const fromWCPackage = wcPackage => {
id: wcPackage.id,
reference: wcPackage.slug,
image: wcPackage.images[0].src || DEFAULT_PACKAGE_IMG,
hasImage: !!wcPackage.images.length,
name: wcPackage.name,
country: 'Sweden',
countryCode: 'se',
currency: 'SEK',
documents: [],
shortDescription: wcPackage.description,
prices: wcPackage.prices.map(price => ({
idPrice: price.id,
idPaymentType: price.id,
payType: price['payment_type'],
isSameCompanyAsCl: false,
idPackage: wcPackage.id,
periodUnit: price['period_unit'],
maxContractPeriod: price['max_contract_period'],
packagePayPeriod: price['package_pay_period'],
servicesContractPeriod: price['services_contract_period'],
fixedExtra: price['minimal_fixed_price'],
servicesExtra: price['minimal_services_price'],
recurentExtra: price['recurrent_price']
})) || [],
groups: [],
}
};

View File

@@ -84,11 +84,13 @@ class Menu extends Component {
)
}
</Nav>
<div className="wiaas-divider nav-btn-cart-divider"></div>
<Nav className="nav-btn-cart navbar-right" navbar>
<NavItem id="nav-button-cart">
<NavLink tag={Link} to="/cart">
<span className="fa fa-shopping-cart cart-icon"></span>
<CartIcon cartCount={this.props.cartCount} />
<span className="fa fa-shopping-cart cart-icon"></span>
<span className="cart-label">Cart</span>
</NavLink>
</NavItem>
</Nav>

View File

@@ -58,18 +58,29 @@
.nav-btn-cart {
padding: 0.2rem;
background-color: rgba(113, 194, 191, 0.5);
width: 11.5rem;
&:hover {
background-color: rgba(113, 194, 191, 0.5);
}
}
.cart-icon {
font-size: 1.2rem;
font-size: 1.6rem;
vertical-align: middle;
}
.cart-label {
margin-left: 0.5rem;
font-size: 0.8rem;
vertical-align: sub;
}
.items-cart-count {
margin-left: 1rem;
width: 12rem;
margin-right: 0.5rem;
padding-left: 0.5rem;
}
.nav-btn-cart-divider {
height: 2.4rem !important;
}
.navbar-collapse {

View File

@@ -35,8 +35,8 @@ const calculateTotalPrice = (cartItems) => {
return {
fixedPrice,
recurrentPrice: priceHelper.sumPrices([recurrentPrice, servicesPrice]),
periodUnit: cartItems[0].periodUnit,
currency: cartItems[0].country.currency
periodUnit: cartItems[0] ? cartItems[0].periodUnit : '',
currency: cartItems[0] ? cartItems[0].country.currency : ''
}
}

View File

@@ -57,3 +57,5 @@ $warm-grey: #7e7e7e;
$info-color: #337ab7;
$danger: #F70D1A;
$warning: #FF8040;
$cart-count-color: #FFD3A1;