Add coupon to web app
This commit is contained in:
parent
8d7f61538b
commit
44f0a41fed
@ -106,6 +106,10 @@
|
|||||||
background-color: $color-brightest;
|
background-color: $color-brightest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&-coupon {
|
||||||
|
width: 7rem;
|
||||||
|
}
|
||||||
|
|
||||||
&-checkout-title {
|
&-checkout-title {
|
||||||
font-weight: $font-weight-semibold;
|
font-weight: $font-weight-semibold;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
@ -13,6 +13,7 @@ import { StorageService } from '../shared/services/storage.service';
|
|||||||
|
|
||||||
import { Observable, Observer, Subject } from 'rxjs';
|
import { Observable, Observer, Subject } from 'rxjs';
|
||||||
import { map, catchError, tap } from 'rxjs/operators';
|
import { map, catchError, tap } from 'rxjs/operators';
|
||||||
|
import { ICoupon } from '../shared/models/coupon.model';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class BasketService {
|
export class BasketService {
|
||||||
@ -95,6 +96,26 @@ export class BasketService {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
checkValidationCoupon(code: string): Observable<ICoupon> {
|
||||||
|
let url = this.purchaseUrl + `/cp/api/v1/coupon/${code}`;
|
||||||
|
|
||||||
|
return this.service
|
||||||
|
.get(url)
|
||||||
|
.pipe<ICoupon>(map<Response, ICoupon>((response) => {
|
||||||
|
console.log(`Coupon: ${response.json()} (${response.ok})`);
|
||||||
|
var item = <ICoupon>response.json[0];
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
item.message = "Valid coupon";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
item.message = "The coupon is not valid or has already been used";
|
||||||
|
}
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
mapBasketInfoCheckout(order: IOrder): IBasketCheckout {
|
mapBasketInfoCheckout(order: IOrder): IBasketCheckout {
|
||||||
let basketCheckout = <IBasketCheckout>{};
|
let basketCheckout = <IBasketCheckout>{};
|
||||||
|
|
||||||
@ -108,6 +129,8 @@ export class BasketService {
|
|||||||
basketCheckout.cardsecuritynumber = order.cardsecuritynumber;
|
basketCheckout.cardsecuritynumber = order.cardsecuritynumber;
|
||||||
basketCheckout.cardtypeid = order.cardtypeid;
|
basketCheckout.cardtypeid = order.cardtypeid;
|
||||||
basketCheckout.cardholdername = order.cardholdername;
|
basketCheckout.cardholdername = order.cardholdername;
|
||||||
|
basketCheckout.coupon = order.coupon;
|
||||||
|
basketCheckout.discount = order.discount;
|
||||||
basketCheckout.total = 0;
|
basketCheckout.total = 0;
|
||||||
basketCheckout.expiration = order.expiration;
|
basketCheckout.expiration = order.expiration;
|
||||||
|
|
||||||
|
@ -34,6 +34,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
|
<div class="d-flex align-items-center justify-content-end mt-4 mb-4 text-uppercase">
|
||||||
|
<div>Subtotal</div>
|
||||||
|
<div class="ml-3">${{order.subtotal | number:'.2-2'}}</div>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex align-items-center justify-content-end mt-4 mb-4 text-uppercase">
|
||||||
|
<div>{{order.coupon}}</div>
|
||||||
|
<div class="ml-3">- ${{order.discount | number:'.2-2'}}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="d-flex align-items-center justify-content-end mt-4 mb-4 text-uppercase u-text-xl">
|
<div class="d-flex align-items-center justify-content-end mt-4 mb-4 text-uppercase u-text-xl">
|
||||||
<div>Total</div>
|
<div>Total</div>
|
||||||
<div class="ml-3">${{order.total | number:'.2-2'}}</div>
|
<div class="ml-3">${{order.total | number:'.2-2'}}</div>
|
||||||
|
@ -84,9 +84,41 @@
|
|||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
|
<div class="d-flex align-items-center justify-content-end mt-4 mb-4 text-uppercase">
|
||||||
|
<div>Subtotal</div>
|
||||||
|
<div class="ml-3">${{order.total | number:'.2-2'}}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="d-flex flex-nowrap justify-content-between align-items-center mb-3 mt-3">
|
||||||
|
<div>
|
||||||
|
<div *ngIf="!coupon">
|
||||||
|
<div class="u-text-uppercase">Have a discount code?</div>
|
||||||
|
<div class="d-flex flex-nowrap justify-content-between align-items-center mt-1">
|
||||||
|
<input #discountcode
|
||||||
|
class="esh-orders_new-coupon mr-2 form-control"
|
||||||
|
type="text"
|
||||||
|
placeholder="Coupon number"
|
||||||
|
(keydown)="keyDownValidationCoupon($event, discountcode.value)">
|
||||||
|
<button type="button"
|
||||||
|
(click)="checkValidationCoupon(discountcode.value)"
|
||||||
|
class="btn btn-secondary u-minwidth-unset">
|
||||||
|
Apply
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="mt-1" *ngIf="couponValidationMessage">{{couponValidationMessage}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex align-items-center justify-content-end text-uppercase">
|
||||||
|
<div *ngIf="coupon?.code">{{coupon?.code}}</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-right ml-3" *ngIf="coupon?.discount">-${{coupon?.discount | number:'.2-2'}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="divider d-flex align-items-center justify-content-end mb-4 pt-4 text-uppercase u-text-xl">
|
<div class="divider d-flex align-items-center justify-content-end mb-4 pt-4 text-uppercase u-text-xl">
|
||||||
<div>Total</div>
|
<div>Total</div>
|
||||||
<div class="ml-3">${{ order.total | number:'.2-2'}}</div>
|
<div class="ml-3">${{ (coupon?.discount ? ((order.total - coupon?.discount) < 0 ? 0 : (order.total - coupon?.discount)) : order.total) | number:'.2-2'}}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="esh-orders_new-buttons d-flex justify-content-end align-items-center">
|
<div class="esh-orders_new-buttons d-flex justify-content-end align-items-center">
|
||||||
|
@ -33,6 +33,10 @@
|
|||||||
width: auto;
|
width: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&-coupon {
|
||||||
|
width: 15rem;
|
||||||
|
}
|
||||||
|
|
||||||
&-buttons {
|
&-buttons {
|
||||||
margin-top: 5rem;
|
margin-top: 5rem;
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,8 @@ import { BasketService } from '../../basket/basket.service';
|
|||||||
import { IOrder } from '../../shared/models/order.model';
|
import { IOrder } from '../../shared/models/order.model';
|
||||||
import { BasketWrapperService } from '../../shared/services/basket.wrapper.service';
|
import { BasketWrapperService } from '../../shared/services/basket.wrapper.service';
|
||||||
|
|
||||||
|
import { ICoupon } from '../../shared/models/coupon.model';
|
||||||
|
|
||||||
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
|
|
||||||
@ -20,6 +22,9 @@ export class OrdersNewComponent implements OnInit {
|
|||||||
isOrderProcessing: boolean;
|
isOrderProcessing: boolean;
|
||||||
errorReceived: boolean;
|
errorReceived: boolean;
|
||||||
order: IOrder;
|
order: IOrder;
|
||||||
|
coupon: ICoupon;
|
||||||
|
discountCode: string;
|
||||||
|
couponValidationMessage: string;
|
||||||
|
|
||||||
constructor(private orderService: OrdersService, private basketService: BasketService, fb: FormBuilder, private router: Router) {
|
constructor(private orderService: OrdersService, private basketService: BasketService, fb: FormBuilder, private router: Router) {
|
||||||
// Obtain user profile information
|
// Obtain user profile information
|
||||||
@ -39,6 +44,23 @@ export class OrdersNewComponent implements OnInit {
|
|||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
keyDownValidationCoupon(event: KeyboardEvent, discountCode: string) {
|
||||||
|
if (event.keyCode === 13) {
|
||||||
|
event.preventDefault();
|
||||||
|
this.checkValidationCoupon(discountCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
checkValidationCoupon(discountCode: string) {
|
||||||
|
this.couponValidationMessage = null;
|
||||||
|
this.coupon = null;
|
||||||
|
this.orderService
|
||||||
|
.checkValidationCoupon(discountCode)
|
||||||
|
.subscribe(
|
||||||
|
coupon => this.coupon = coupon,
|
||||||
|
error => this.couponValidationMessage = 'The coupon is not valid or it\'s been redeemed already!');
|
||||||
|
}
|
||||||
|
|
||||||
submitForm(value: any) {
|
submitForm(value: any) {
|
||||||
this.order.street = this.newOrderForm.controls['street'].value;
|
this.order.street = this.newOrderForm.controls['street'].value;
|
||||||
this.order.city = this.newOrderForm.controls['city'].value;
|
this.order.city = this.newOrderForm.controls['city'].value;
|
||||||
@ -49,6 +71,14 @@ export class OrdersNewComponent implements OnInit {
|
|||||||
this.order.cardholdername = this.newOrderForm.controls['cardholdername'].value;
|
this.order.cardholdername = this.newOrderForm.controls['cardholdername'].value;
|
||||||
this.order.cardexpiration = new Date(20 + this.newOrderForm.controls['expirationdate'].value.split('/')[1], this.newOrderForm.controls['expirationdate'].value.split('/')[0]);
|
this.order.cardexpiration = new Date(20 + this.newOrderForm.controls['expirationdate'].value.split('/')[1], this.newOrderForm.controls['expirationdate'].value.split('/')[0]);
|
||||||
this.order.cardsecuritynumber = this.newOrderForm.controls['securitycode'].value;
|
this.order.cardsecuritynumber = this.newOrderForm.controls['securitycode'].value;
|
||||||
|
|
||||||
|
if (this.coupon) {
|
||||||
|
console.log(`Coupon: ${this.coupon.code} (${this.coupon.discount})`);
|
||||||
|
|
||||||
|
this.order.coupon = this.coupon.code;
|
||||||
|
this.order.discount = this.coupon.discount;
|
||||||
|
}
|
||||||
|
|
||||||
let basketCheckout = this.basketService.mapBasketInfoCheckout(this.order);
|
let basketCheckout = this.basketService.mapBasketInfoCheckout(this.order);
|
||||||
this.basketService.setBasketCheckout(basketCheckout)
|
this.basketService.setBasketCheckout(basketCheckout)
|
||||||
.pipe(catchError((errMessage) => {
|
.pipe(catchError((errMessage) => {
|
||||||
|
@ -10,6 +10,7 @@ import { BasketWrapperService } from '../shared/services/basket.wrapper.service'
|
|||||||
|
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { tap, map } from 'rxjs/operators';
|
import { tap, map } from 'rxjs/operators';
|
||||||
|
import { ICoupon } from '../shared/models/coupon.model';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class OrdersService {
|
export class OrdersService {
|
||||||
@ -48,6 +49,14 @@ export class OrdersService {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
checkValidationCoupon(code: string): Observable<ICoupon> {
|
||||||
|
let url = this.ordersUrl + `/cp/api/v1/coupon/${code}`;
|
||||||
|
|
||||||
|
return this.service.get(url).pipe<ICoupon>(tap((response: any) => {
|
||||||
|
return response;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
mapOrderAndIdentityInfoNewOrder(): IOrder {
|
mapOrderAndIdentityInfoNewOrder(): IOrder {
|
||||||
let order = <IOrder>{};
|
let order = <IOrder>{};
|
||||||
let basket = this.basketService.basket;
|
let basket = this.basketService.basket;
|
||||||
|
@ -12,5 +12,7 @@
|
|||||||
cardtypeid: number;
|
cardtypeid: number;
|
||||||
buyer: string;
|
buyer: string;
|
||||||
ordernumber: string;
|
ordernumber: string;
|
||||||
|
coupon: string;
|
||||||
total: number;
|
total: number;
|
||||||
|
discount: number;
|
||||||
}
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
export interface ICoupon {
|
||||||
|
discount: number;
|
||||||
|
code: string;
|
||||||
|
message: string
|
||||||
|
}
|
@ -10,6 +10,9 @@ export interface IOrderDetail {
|
|||||||
state: string;
|
state: string;
|
||||||
zipcode: string;
|
zipcode: string;
|
||||||
country: number;
|
country: number;
|
||||||
|
subtotal: number;
|
||||||
|
coupon: string;
|
||||||
|
discount: number;
|
||||||
total: number;
|
total: number;
|
||||||
orderitems: IOrderItem[];
|
orderitems: IOrderItem[];
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,9 @@ export interface IOrder {
|
|||||||
cardtypeid: number;
|
cardtypeid: number;
|
||||||
buyer: string;
|
buyer: string;
|
||||||
ordernumber: string;
|
ordernumber: string;
|
||||||
|
subtotal: number,
|
||||||
|
coupon: string;
|
||||||
|
discount: number;
|
||||||
total: number;
|
total: number;
|
||||||
orderItems: IOrderItem[];
|
orderItems: IOrderItem[];
|
||||||
}
|
}
|
||||||
|
@ -82,7 +82,7 @@ export class SecurityService {
|
|||||||
let client_id = 'js';
|
let client_id = 'js';
|
||||||
let redirect_uri = location.origin + '/';
|
let redirect_uri = location.origin + '/';
|
||||||
let response_type = 'id_token token';
|
let response_type = 'id_token token';
|
||||||
let scope = 'openid profile orders basket webshoppingagg orders.signalrhub';
|
let scope = 'openid profile orders basket webshoppingagg orders.signalrhub coupon';
|
||||||
let nonce = 'N' + Math.random() + '' + Date.now();
|
let nonce = 'N' + Math.random() + '' + Date.now();
|
||||||
let state = Date.now() + '' + Math.random();
|
let state = Date.now() + '' + Math.random();
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user