From 829e76ca68d6d5d3698cd3e5a926e8c79a1933ee Mon Sep 17 00:00:00 2001 From: Charles Showalter Date: Thu, 26 May 2022 14:26:27 -0700 Subject: [PATCH] Added View Orders and Order Details to Users --- client/src/app/app-routing.module.ts | 1 + client/src/app/app.module.ts | 1 - client/src/app/basket/basket.service.ts | 6 + .../checkout-payments.component.html | 2 +- .../checkout-payments.component.ts | 37 +++++- .../app/checkout/checkout-routing.module.ts | 6 +- .../checkout-success.component.html | 10 +- .../checkout-success.component.ts | 9 +- .../src/app/checkout/checkout.component.html | 2 +- client/src/app/checkout/checkout.service.ts | 5 + .../order-details.component.html | 66 +++++++++++ .../order-details.component.scss | 0 .../order-details/order-details.component.ts | 29 +++++ .../src/app/orders/orders-routing.module.ts | 15 +++ client/src/app/orders/orders.component.html | 24 ++++ client/src/app/orders/orders.component.scss | 0 client/src/app/orders/orders.component.ts | 27 +++++ client/src/app/orders/orders.module.ts | 19 ++++ client/src/app/orders/orders.service.ts | 20 ++++ .../basket-summary.component.html | 105 +++++++++--------- client/src/app/shared/models/order.ts | 28 +++++ 21 files changed, 352 insertions(+), 60 deletions(-) create mode 100644 client/src/app/orders/order-details/order-details.component.html create mode 100644 client/src/app/orders/order-details/order-details.component.scss create mode 100644 client/src/app/orders/order-details/order-details.component.ts create mode 100644 client/src/app/orders/orders-routing.module.ts create mode 100644 client/src/app/orders/orders.component.html create mode 100644 client/src/app/orders/orders.component.scss create mode 100644 client/src/app/orders/orders.component.ts create mode 100644 client/src/app/orders/orders.module.ts create mode 100644 client/src/app/orders/orders.service.ts create mode 100644 client/src/app/shared/models/order.ts diff --git a/client/src/app/app-routing.module.ts b/client/src/app/app-routing.module.ts index 39ac0c4..9cd086f 100644 --- a/client/src/app/app-routing.module.ts +++ b/client/src/app/app-routing.module.ts @@ -14,6 +14,7 @@ const routes: Routes = [ {path: 'shop', loadChildren: ()=> import('./shop/shop.module').then(mod => mod.ShopModule), data: {breadcrumb: 'Shop'}}, {path: 'basket', loadChildren: ()=> import('./basket/basket.module').then(mod => mod.BasketModule), data: {breadcrumb: 'Shopping Cart'}}, {path: 'checkout', canActivate: [AuthGuard], loadChildren: ()=> import('./checkout/checkout.module').then(mod => mod.CheckoutModule), data: {breadcrumb: 'Checkout'}}, + {path: 'orders', canActivate: [AuthGuard], loadChildren: ()=> import('./orders/orders.module').then(mod => mod.OrdersModule), data: {breadcrumb: 'Orders'}}, {path: 'account', loadChildren: ()=> import('./account/account.module').then(mod => mod.AccountModule), data: {breadcrumb: {skip: true}}}, {path: '**', redirectTo: 'not-found', pathMatch: 'full'} ]; diff --git a/client/src/app/app.module.ts b/client/src/app/app.module.ts index f8bebfb..717b825 100644 --- a/client/src/app/app.module.ts +++ b/client/src/app/app.module.ts @@ -6,7 +6,6 @@ import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { CoreModule } from './core/core.module'; -import { ShopModule } from './shop/shop.module'; import { HomeModule } from './home/home.module'; import { ErrorInterceptor } from './core/interceptors/error.interceptor'; import { NgxSpinnerModule } from 'ngx-spinner'; diff --git a/client/src/app/basket/basket.service.ts b/client/src/app/basket/basket.service.ts index 6e0431a..9eb3ade 100644 --- a/client/src/app/basket/basket.service.ts +++ b/client/src/app/basket/basket.service.ts @@ -85,6 +85,12 @@ export class BasketService { } } + deleteLocalBasket(id: string){ + this.basketSource.next(null); + this.basketTotalSource.next(null); + localStorage.removeItem('basket_id'); + } + deleteBasket(basket: IBasket) { return this.http.delete(this.baseUrl + 'basket?id=' + basket.id).subscribe({ next: () => { diff --git a/client/src/app/checkout/checkout-payments/checkout-payments.component.html b/client/src/app/checkout/checkout-payments/checkout-payments.component.html index e5a3d92..264ebb6 100644 --- a/client/src/app/checkout/checkout-payments/checkout-payments.component.html +++ b/client/src/app/checkout/checkout-payments/checkout-payments.component.html @@ -3,7 +3,7 @@ - diff --git a/client/src/app/checkout/checkout-payments/checkout-payments.component.ts b/client/src/app/checkout/checkout-payments/checkout-payments.component.ts index 54d8370..1f2c98d 100644 --- a/client/src/app/checkout/checkout-payments/checkout-payments.component.ts +++ b/client/src/app/checkout/checkout-payments/checkout-payments.component.ts @@ -1,4 +1,11 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, Input, OnInit } from '@angular/core'; +import { FormGroup } from '@angular/forms'; +import { NavigationExtras, Router } from '@angular/router'; +import { ToastrService } from 'ngx-toastr'; +import { BasketService } from 'src/app/basket/basket.service'; +import { IBasket } from 'src/app/shared/models/baskset'; +import { IOrder } from 'src/app/shared/models/order'; +import { CheckoutService } from '../checkout.service'; @Component({ selector: 'app-checkout-payments', @@ -6,10 +13,36 @@ import { Component, OnInit } from '@angular/core'; styleUrls: ['./checkout-payments.component.scss'] }) export class CheckoutPaymentsComponent implements OnInit { + @Input() checkoutForm: FormGroup; - constructor() { } + constructor(private basketService: BasketService, private checkoutService: CheckoutService, private toastr: ToastrService, private router: Router) { } ngOnInit(): void { } + submitOrder(){ + const basket = this.basketService.getCurrentBasketValue(); + const orderToCreate = this.getOrderToCreate(basket); + this.checkoutService.createOrder(orderToCreate).subscribe({ + next: (order: IOrder) => { + this.toastr.success('Order created successfully'); + this.basketService.deleteLocalBasket(basket.id); + const navigationExtras: NavigationExtras = {state: order}; + this.router.navigate(['checkout/success'], navigationExtras); + }, + error: (e: any) => { + this.toastr.error(e.message); + console.log(e); + }, + complete: () => { console.log('completed') } + }); + } + + private getOrderToCreate(basket: IBasket) { + return { + basketId: basket.id, + deliveryMethodId: +this.checkoutForm.get('deliveryForm').get('deliveryMethod').value, + shipToAddress: this.checkoutForm.get('addressForm').value + }; + } } diff --git a/client/src/app/checkout/checkout-routing.module.ts b/client/src/app/checkout/checkout-routing.module.ts index 54b0bb9..1e46463 100644 --- a/client/src/app/checkout/checkout-routing.module.ts +++ b/client/src/app/checkout/checkout-routing.module.ts @@ -2,10 +2,12 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { CheckoutComponent } from './checkout.component'; import { RouterModule, Routes } from '@angular/router'; +import { CheckoutSuccessComponent } from './checkout-success/checkout-success.component'; const routes: Routes = [ - {path: '', component: CheckoutComponent} -] + {path: '', component: CheckoutComponent}, + {path: 'success', component: CheckoutSuccessComponent } +]; @NgModule({ declarations: [], diff --git a/client/src/app/checkout/checkout-success/checkout-success.component.html b/client/src/app/checkout/checkout-success/checkout-success.component.html index c858743..027722b 100644 --- a/client/src/app/checkout/checkout-success/checkout-success.component.html +++ b/client/src/app/checkout/checkout-success/checkout-success.component.html @@ -1 +1,9 @@ -

checkout-success works!

+
+
+ +
+

This you. Your order is confirmed

+

Your order number is: {{order?.id}}

+ + +
diff --git a/client/src/app/checkout/checkout-success/checkout-success.component.ts b/client/src/app/checkout/checkout-success/checkout-success.component.ts index 9919583..1fee42d 100644 --- a/client/src/app/checkout/checkout-success/checkout-success.component.ts +++ b/client/src/app/checkout/checkout-success/checkout-success.component.ts @@ -1,4 +1,6 @@ import { Component, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; +import { IOrder } from 'src/app/shared/models/order'; @Component({ selector: 'app-checkout-success', @@ -6,8 +8,13 @@ import { Component, OnInit } from '@angular/core'; styleUrls: ['./checkout-success.component.scss'] }) export class CheckoutSuccessComponent implements OnInit { + order: IOrder; - constructor() { } + constructor(private router: Router) { + const navigation = this.router.getCurrentNavigation(); + const state = navigation && navigation.extras && navigation.extras.state; + if(state) { this.order = state as IOrder; } + } ngOnInit(): void { } diff --git a/client/src/app/checkout/checkout.component.html b/client/src/app/checkout/checkout.component.html index d69c2e3..630ac7d 100644 --- a/client/src/app/checkout/checkout.component.html +++ b/client/src/app/checkout/checkout.component.html @@ -12,7 +12,7 @@ - + diff --git a/client/src/app/checkout/checkout.service.ts b/client/src/app/checkout/checkout.service.ts index bf6c0f6..5df1a54 100644 --- a/client/src/app/checkout/checkout.service.ts +++ b/client/src/app/checkout/checkout.service.ts @@ -3,6 +3,7 @@ import { Injectable } from '@angular/core'; import { map } from 'rxjs'; import { environment } from 'src/environments/environment'; import { IDeliveryMethods } from '../shared/models/deliveryMethods'; +import { IOrderToCreate } from '../shared/models/order'; @Injectable({ providedIn: 'root' @@ -12,6 +13,10 @@ export class CheckoutService { constructor(private http: HttpClient) { } + createOrder(order: IOrderToCreate){ + return this.http.post(this.baseUrl + 'orders', order); + } + getDeliveryMethods(){ return this.http.get(this.baseUrl + 'orders/deliveryMethods').pipe( map((dm: IDeliveryMethods[]) => { diff --git a/client/src/app/orders/order-details/order-details.component.html b/client/src/app/orders/order-details/order-details.component.html new file mode 100644 index 0000000..c797faa --- /dev/null +++ b/client/src/app/orders/order-details/order-details.component.html @@ -0,0 +1,66 @@ +
+
+
+
+
+ + + + + + + + + + + + + + + + + +
+
Product
+
+
Price
+
+
quantity
+
+
Total
+
+
+ {{item.productName}} + +
+
{{item.price | currency}}{{item.quantity}}{{item.price * item.quantity | currency}}
+
+
+
+
+
+ Order Summary +
+
+
    +
  • + Subtotal + {{order.subtotal | currency}} +
  • +
  • + Shipping and Handling + {{order.shippingPrice | currency}} +
  • +
  • + Total + {{order.total | currency}} +
  • +
+
+
+
+
diff --git a/client/src/app/orders/order-details/order-details.component.scss b/client/src/app/orders/order-details/order-details.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/client/src/app/orders/order-details/order-details.component.ts b/client/src/app/orders/order-details/order-details.component.ts new file mode 100644 index 0000000..9cc74e5 --- /dev/null +++ b/client/src/app/orders/order-details/order-details.component.ts @@ -0,0 +1,29 @@ +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { IOrder } from 'src/app/shared/models/order'; +import { BreadcrumbService } from 'xng-breadcrumb'; +import { OrdersService } from '../orders.service'; + +@Component({ + selector: 'app-order-details', + templateUrl: './order-details.component.html', + styleUrls: ['./order-details.component.scss'] +}) +export class OrderDetailsComponent implements OnInit { + order: IOrder; + + constructor(private route: ActivatedRoute, private breadCrumbService: BreadcrumbService, private orderService: OrdersService) { + this.breadCrumbService.set('@OrderDetails', ' '); + } + + ngOnInit(): void { + this.orderService.getOrderDetails(+this.route.snapshot.paramMap.get('id')).subscribe({ + next: (order: IOrder) => { + this.order = order; + this.breadCrumbService.set('@OrderDetails', `Order# ${order.id} - ${order.status}`); + }, + error: (e: any) => { console.log(e); }, + complete: () => { console.log('completed'); } + }) + } +} diff --git a/client/src/app/orders/orders-routing.module.ts b/client/src/app/orders/orders-routing.module.ts new file mode 100644 index 0000000..0323d1a --- /dev/null +++ b/client/src/app/orders/orders-routing.module.ts @@ -0,0 +1,15 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { OrderDetailsComponent } from './order-details/order-details.component'; +import { OrdersComponent } from './orders.component'; + +const routes: Routes = [ + {path: '', component: OrdersComponent}, + {path: ':id', component: OrderDetailsComponent, data: {breadcrumb: {alias: 'OrderDetails'}}}, +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class OrdersRoutingModule { } diff --git a/client/src/app/orders/orders.component.html b/client/src/app/orders/orders.component.html new file mode 100644 index 0000000..3c5279f --- /dev/null +++ b/client/src/app/orders/orders.component.html @@ -0,0 +1,24 @@ +
+
+
+ + + + + + + + + + + + + + + + + +
OrderTotalDateStatus
# {{order.id}}{{order.orderDate | date: 'medium'}}{{order.total | currency}}{{order.status}}
+
+
+
diff --git a/client/src/app/orders/orders.component.scss b/client/src/app/orders/orders.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/client/src/app/orders/orders.component.ts b/client/src/app/orders/orders.component.ts new file mode 100644 index 0000000..ddfdd42 --- /dev/null +++ b/client/src/app/orders/orders.component.ts @@ -0,0 +1,27 @@ +import { Component, OnInit } from '@angular/core'; +import { IOrder } from '../shared/models/order'; +import { OrdersService } from './orders.service'; + +@Component({ + selector: 'app-orders', + templateUrl: './orders.component.html', + styleUrls: ['./orders.component.scss'] +}) +export class OrdersComponent implements OnInit { + orders: IOrder[]; + + constructor(private orderService: OrdersService) { } + + ngOnInit(): void { + this.getOrders(); + } + + getOrders(){ + this.orderService.getOrdersForUser().subscribe({ + next: (orders: IOrder[]) => { this.orders = orders; }, + error: (e: any) => { console.log(e); }, + complete: () => { console.log('Orders'); } + }); + } + +} diff --git a/client/src/app/orders/orders.module.ts b/client/src/app/orders/orders.module.ts new file mode 100644 index 0000000..5b4927a --- /dev/null +++ b/client/src/app/orders/orders.module.ts @@ -0,0 +1,19 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { OrderDetailsComponent } from './order-details/order-details.component'; +import { OrdersComponent } from './orders.component'; +import { OrdersRoutingModule } from './orders-routing.module'; + + + +@NgModule({ + declarations: [ + OrdersComponent, + OrderDetailsComponent + ], + imports: [ + CommonModule, + OrdersRoutingModule + ] +}) +export class OrdersModule { } diff --git a/client/src/app/orders/orders.service.ts b/client/src/app/orders/orders.service.ts new file mode 100644 index 0000000..3e0fa3d --- /dev/null +++ b/client/src/app/orders/orders.service.ts @@ -0,0 +1,20 @@ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { environment } from 'src/environments/environment'; + +@Injectable({ + providedIn: 'root' +}) +export class OrdersService { + baseUrl = environment.apiUrl; + + constructor(private http: HttpClient) { } + + getOrdersForUser(){ + return this.http.get(this.baseUrl + 'orders'); + } + + getOrderDetails(id: number){ + return this.http.get(this.baseUrl + 'orders/' + id); + } +} diff --git a/client/src/app/shared/basket-summary/basket-summary.component.html b/client/src/app/shared/basket-summary/basket-summary.component.html index 710c997..f6ec044 100644 --- a/client/src/app/shared/basket-summary/basket-summary.component.html +++ b/client/src/app/shared/basket-summary/basket-summary.component.html @@ -1,52 +1,55 @@ -
- - - - - - - - - - - - - + + + + + + +
-
Product
-
-
Price
-
-
quantity
-
-
Total
-
-
Remove
-
-
- {{item.productName}} -
-
- {{item.productName}} -
- Type: {{item.type}} + +
+ + + + + + + + + + + + + - - - - - - -
+
Product
+
+
Price
+
+
quantity
+
+
Total
+
+
Remove
+
+
+ {{item.productName}} +
+
+ {{item.productName}} +
+ Type: {{item.type}} +
- -
{{item.price | currency}} -
- - {{item.quantity}} - -
-
{{item.price * item.quantity | currency}} - - - -
-
+
{{item.price | currency}} +
+ + {{item.quantity}} + +
+
{{item.price * item.quantity | currency}} + + + +
+
+ + diff --git a/client/src/app/shared/models/order.ts b/client/src/app/shared/models/order.ts new file mode 100644 index 0000000..0333016 --- /dev/null +++ b/client/src/app/shared/models/order.ts @@ -0,0 +1,28 @@ +import { IAddress } from "./address"; + +export interface IOrderToCreate { + basketId: string; + deliveryMethodId: number; + shipToAddress: IAddress; +} + +export interface IOrderItem { + productId: number; + productName: string; + pictureUrl: string; + price: number; + quantity: number; +} + +export interface IOrder { + id: number; + buyerEmail: string; + orderDate: Date; + shipToAddress: IAddress; + deliveryMethod: string; + shippingPrice: number; + orderItems: IOrderItem[]; + subtotal: number; + total: number; + status: string; +}