Browse Source

Add coupon to web app

pull/2020/head
facepalm 2 years ago
parent
commit
44f0a41fed
12 changed files with 126 additions and 2 deletions
  1. +4
    -0
      src/Web/WebSPA/Client/src/modules/basket/basket.component.scss
  2. +23
    -0
      src/Web/WebSPA/Client/src/modules/basket/basket.service.ts
  3. +9
    -0
      src/Web/WebSPA/Client/src/modules/orders/orders-detail/orders-detail.component.html
  4. +33
    -1
      src/Web/WebSPA/Client/src/modules/orders/orders-new/orders-new.component.html
  5. +4
    -0
      src/Web/WebSPA/Client/src/modules/orders/orders-new/orders-new.component.scss
  6. +30
    -0
      src/Web/WebSPA/Client/src/modules/orders/orders-new/orders-new.component.ts
  7. +9
    -0
      src/Web/WebSPA/Client/src/modules/orders/orders.service.ts
  8. +2
    -0
      src/Web/WebSPA/Client/src/modules/shared/models/basketCheckout.model.ts
  9. +5
    -0
      src/Web/WebSPA/Client/src/modules/shared/models/coupon.model.ts
  10. +3
    -0
      src/Web/WebSPA/Client/src/modules/shared/models/order-detail.model.ts
  11. +3
    -0
      src/Web/WebSPA/Client/src/modules/shared/models/order.model.ts
  12. +1
    -1
      src/Web/WebSPA/Client/src/modules/shared/services/security.service.ts

+ 4
- 0
src/Web/WebSPA/Client/src/modules/basket/basket.component.scss View File

@ -106,6 +106,10 @@
background-color: $color-brightest;
}
&-coupon {
width: 7rem;
}
&-checkout-title {
font-weight: $font-weight-semibold;
text-align: center;


+ 23
- 0
src/Web/WebSPA/Client/src/modules/basket/basket.service.ts View File

@ -13,6 +13,7 @@ import { StorageService } from '../shared/services/storage.service';
import { Observable, Observer, Subject } from 'rxjs';
import { map, catchError, tap } from 'rxjs/operators';
import { ICoupon } from '../shared/models/coupon.model';
@Injectable()
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 {
let basketCheckout = <IBasketCheckout>{};
@ -108,6 +129,8 @@ export class BasketService {
basketCheckout.cardsecuritynumber = order.cardsecuritynumber;
basketCheckout.cardtypeid = order.cardtypeid;
basketCheckout.cardholdername = order.cardholdername;
basketCheckout.coupon = order.coupon;
basketCheckout.discount = order.discount;
basketCheckout.total = 0;
basketCheckout.expiration = order.expiration;


+ 9
- 0
src/Web/WebSPA/Client/src/modules/orders/orders-detail/orders-detail.component.html View File

@ -34,6 +34,15 @@
</div>
</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>Total</div>
<div class="ml-3">${{order.total | number:'.2-2'}}</div>


+ 33
- 1
src/Web/WebSPA/Client/src/modules/orders/orders-new/orders-new.component.html View File

@ -84,9 +84,41 @@
</div>
</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>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 class="esh-orders_new-buttons d-flex justify-content-end align-items-center">


+ 4
- 0
src/Web/WebSPA/Client/src/modules/orders/orders-new/orders-new.component.scss View File

@ -33,6 +33,10 @@
width: auto;
}
&-coupon {
width: 15rem;
}
&-buttons {
margin-top: 5rem;
}


+ 30
- 0
src/Web/WebSPA/Client/src/modules/orders/orders-new/orders-new.component.ts View File

@ -7,6 +7,8 @@ import { BasketService } from '../../basket/basket.service';
import { IOrder } from '../../shared/models/order.model';
import { BasketWrapperService } from '../../shared/services/basket.wrapper.service';
import { ICoupon } from '../../shared/models/coupon.model';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { Router } from '@angular/router';
@ -20,6 +22,9 @@ export class OrdersNewComponent implements OnInit {
isOrderProcessing: boolean;
errorReceived: boolean;
order: IOrder;
coupon: ICoupon;
discountCode: string;
couponValidationMessage: string;
constructor(private orderService: OrdersService, private basketService: BasketService, fb: FormBuilder, private router: Router) {
// Obtain user profile information
@ -39,6 +44,23 @@ export class OrdersNewComponent implements OnInit {
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) {
this.order.street = this.newOrderForm.controls['street'].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.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;
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);
this.basketService.setBasketCheckout(basketCheckout)
.pipe(catchError((errMessage) => {


+ 9
- 0
src/Web/WebSPA/Client/src/modules/orders/orders.service.ts View File

@ -10,6 +10,7 @@ import { BasketWrapperService } from '../shared/services/basket.wrapper.service'
import { Observable } from 'rxjs';
import { tap, map } from 'rxjs/operators';
import { ICoupon } from '../shared/models/coupon.model';
@Injectable()
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 {
let order = <IOrder>{};
let basket = this.basketService.basket;


+ 2
- 0
src/Web/WebSPA/Client/src/modules/shared/models/basketCheckout.model.ts View File

@ -12,5 +12,7 @@
cardtypeid: number;
buyer: string;
ordernumber: string;
coupon: string;
total: number;
discount: number;
}

+ 5
- 0
src/Web/WebSPA/Client/src/modules/shared/models/coupon.model.ts View File

@ -0,0 +1,5 @@
export interface ICoupon {
discount: number;
code: string;
message: string
}

+ 3
- 0
src/Web/WebSPA/Client/src/modules/shared/models/order-detail.model.ts View File

@ -10,6 +10,9 @@ export interface IOrderDetail {
state: string;
zipcode: string;
country: number;
subtotal: number;
coupon: string;
discount: number;
total: number;
orderitems: IOrderItem[];
}

+ 3
- 0
src/Web/WebSPA/Client/src/modules/shared/models/order.model.ts View File

@ -14,6 +14,9 @@ export interface IOrder {
cardtypeid: number;
buyer: string;
ordernumber: string;
subtotal: number,
coupon: string;
discount: number;
total: number;
orderItems: IOrderItem[];
}

+ 1
- 1
src/Web/WebSPA/Client/src/modules/shared/services/security.service.ts View File

@ -82,7 +82,7 @@ export class SecurityService {
let client_id = 'js';
let redirect_uri = location.origin + '/';
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 state = Date.now() + '' + Math.random();


Loading…
Cancel
Save