RomainMarecat/slate

View on GitHub
src/shared/cart/cart-payment/cart-payment.component.ts

Summary

Maintainability
A
3 hrs
Test Coverage
File `cart-payment.component.ts` has 294 lines of code (exceeds 250 allowed). Consider refactoring.
import { HttpErrorResponse } from '@angular/common/http';
import {
AfterViewInit,
ChangeDetectorRef,
Component,
ElementRef,
EventEmitter,
Input,
OnDestroy,
OnInit,
Output,
ViewChild
} from '@angular/core';
import { DocumentReference } from '@angular/fire/firestore';
import { FormGroup, NgForm } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import { FirebaseError } from 'firebase';
import { User } from 'firebase/app';
import {
ElementOptions,
Elements,
ElementsOptions,
Error,
StripeCardComponent,
StripeService,
TokenResult
} from 'ngx-stripe';
import { Subscription } from 'rxjs';
import { take } from 'rxjs/operators';
import { LoaderService } from '../../loader/loader.service';
import { Order, OrderItem } from '../../order/shared/order';
import { OrderService } from '../../order/shared/order.service';
import { Payment } from '../../payment/shared/payment';
import { PaymentService } from '../../payment/shared/payment.service';
import { AlertService } from '../../popup/alert.service';
import { Product } from '../../product/shared/product';
import { ProductService } from '../../product/shared/product.service';
import { UserService } from '../../user/shared/user.service';
import { onlineStatus$ } from '../../util/online-status';
import { RoutingState } from '../../util/routing-state';
import { Cart } from '../shared/cart';
import { CartService } from '../shared/cart.service';
import { Delivery } from '../shared/delivery';
import { DeliveryService } from '../shared/delivery.service';
 
@Component({
selector: 'app-cart-payment',
templateUrl: './cart-payment.component.html',
styleUrls: ['./cart-payment.component.scss']
})
export class CartPaymentComponent implements OnInit, AfterViewInit, OnDestroy {
@ViewChild('cardInfo', {static: false}) cardInfo: ElementRef;
 
_cart: Cart;
 
@Input() user: User;
 
@Input() delivery: Delivery;
 
onLine: boolean;
 
error: Error | FirebaseError;
 
@Output() paid: EventEmitter<any> = new EventEmitter<any>();
 
@Output() cancelled: EventEmitter<boolean> = new EventEmitter<boolean>();
 
elements: Elements;
 
@ViewChild(StripeCardComponent, {static: false}) card: StripeCardComponent;
 
elementsOptions: ElementsOptions = {
locale: 'fr'
};
cardOptions: ElementOptions = {
style: {
base: {
iconColor: '#666EE8',
color: '#31325F',
lineHeight: '40px',
fontWeight: 300,
fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
fontSize: '18px',
'::placeholder': {
color: '#CFD7E0'
}
}
}
};
 
cardHandler = this.onChange.bind(this);
 
form: FormGroup = new FormGroup({});
payment: Payment;
 
// Url
previousRoute: string;
 
disablePayButton = false;
 
constructor(private paymentService: PaymentService,
private orderService: OrderService,
private userService: UserService,
private alertService: AlertService,
private activatedRoute: ActivatedRoute,
private cartService: CartService,
private router: Router,
private routingState: RoutingState,
private cd: ChangeDetectorRef,
private stripeService: StripeService,
private productService: ProductService,
private loaderService: LoaderService,
private deliveryService: DeliveryService) {
}
 
ngOnInit() {
this.previousRoute = this.routingState.getPreviousUrl() || '/cart';
onlineStatus$().subscribe((online: boolean) => {
this.onLine = online;
});
}
 
ngAfterViewInit() {
}
 
ngOnDestroy() {
}
 
@Input() set cart(cart: Cart) {
if (cart) {
this._cart = cart;
this.getDelivery(cart);
}
}
 
get cart(): Cart {
return this._cart;
}
 
getDelivery(cart: Cart) {
this.deliveryService.filters$.next([
{
column: 'cart',
operator: 'array-contains',
value: cart.key
}
]);
const subscription: Subscription = this.deliveryService.getDeliveries()
.subscribe((deliveries: Delivery[]) => {
if (deliveries && deliveries.length) {
this.delivery = deliveries[0];
}
if (subscription) {
subscription.unsubscribe();
}
}, () => {
this.alertService.openAlertMessage(
{title: '', message: 'cart-payment.errors.delivery'},
{panelClass: 'alert-danger'}
);
});
}
 
cancel() {
this.router.navigate([this.previousRoute]);
this.cancelled.emit(true);
}
 
onChange(event: any) {
if (event && event.event && event.event.error) {
this.error = event.event.error;
} else {
this.error = null;
}
this.cd.detectChanges();
}
 
onSubmit(form: NgForm) {
this.loaderService.show();
this.togglePayButton();
if (this.userService.getUser() &&
this.userService.getUser().uid &&
this.cart &&
this.delivery &&
this.cart.total) {
this.createToken();
} else {
// Undefined cart or undefined total
this.alertService.openAlertMessage(
{title: '', message: 'cart-payment.errors.cart'},
{panelClass: 'alert-danger'}
);
this.togglePayButton();
this.loaderService.hide();
}
}
 
createToken(): void {
this.stripeService
.createToken(this.card.getCard(), {name: this.userService.getUser().email})
.subscribe((result: TokenResult) => {
if (result.token) {
const order = this.createOrder(result);
this.saveOrder(order);
} else if (result.error) {
// Error creating the token
this.handleErrorResponse(result.error);
this.togglePayButton();
}
});
}
 
saveOrder(order: Order) {
// Never never process charge here with access token from your secret key
// send the token to the your backend to process the charge
this.orderService.createOrder(order)
.subscribe((createdOrder) => {
order.key = createdOrder.id;
this.orderService.updateOrder(order)
.subscribe(() => {
this.payment.order = order.key;
this.savePayment(order);
}, (err) => {
this.handleErrorResponse(err);
this.togglePayButton();
});
}, (err) => {
this.handleErrorResponse(err);
this.togglePayButton();
});
}
 
savePayment(order: Order) {
this.paymentService.createPayment(this.payment)
.subscribe((createdPayment: DocumentReference) => {
this.payment.key = createdPayment.id;
this.paymentService.updatePayment(this.payment)
.subscribe(() => {
this.cart.state = 'confirmation';
this.cart.order = order.key;
 
this.updateCart(order);
 
this.togglePayButton();
}, (err) => {
this.handleErrorResponse(err);
this.togglePayButton();
});
}, (err) => {
this.handleErrorResponse(err);
this.togglePayButton();
});
}
 
updateCart(order: Order) {
this.cartService.updateCart(this.cart)
.subscribe(() => {
this.paid.emit(this.payment);
this.paymentService.payment$.next(this.payment);
this.updateDelivery(order);
 
this.updateOrderedProducts(order);
 
this.loaderService.hide();
}, (err) => {
this.handleErrorResponse(err);
this.togglePayButton();
});
}
 
updateDelivery(order: Order) {
if (!this.delivery.order) {
this.delivery.order = [];
}
if (!this.delivery.order.includes(order.key)) {
this.delivery.order.push(order.key);
}
this.deliveryService.updateDelivery(this.delivery)
.subscribe(() => {
// async save delivery order key
},
(err) => {
this.handleErrorResponse(err);
});
}
 
createOrder(result: TokenResult): Order {
// Use the token to create a charge or a customer
// https://stripe.com/docs/charges
const order: Order = {
cart: this.cart.key,
total: this.cart.total,
user: this.cart.user,
items: this.cart.items,
status: 'capture_authorized',
delivery_fee: 0,
delivery: this.delivery.key,
created_at: new Date(),
updated_at: new Date(),
};
 
this.payment = {
token: result.token,
created_at: new Date(),
updated_at: new Date(),
};
 
return order;
}
 
updateOrderedProducts(order: Order) {
order.items.forEach((orderItem: OrderItem) => {
this.productService.updateProductByKey(orderItem.code, {ordered: orderItem.quantity} as Product)
.pipe(
take(1)
)
.subscribe(() => {
});
});
}
 
 
togglePayButton() {
this.disablePayButton = !this.disablePayButton;
}
 
handleErrorResponse(err: HttpErrorResponse | FirebaseError | Error) {
if (typeof err.message === 'string') {
this.error = err as FirebaseError | Error;
 
this.alertService.openAlertMessage(
{title: '', message: err.message},
{panelClass: 'alert-danger'}
);
}
if (err instanceof HttpErrorResponse) {
this.alertService.openAlertMessage(
{title: '', message: err.error.message},
{panelClass: 'alert-danger'}
);
}
this.loaderService.hide();
}
}