;
13 |
14 | constructor(private basketService: BasketService) { }
15 |
16 | ngOnInit(): void {
17 | this.basket$ = this.basketService.basket$;
18 | }
19 |
20 | removeBasketItem(item: BasketItem) {
21 | this.basketService.removeItemFromBasket(item);
22 | }
23 |
24 | incrementItemQuantity(item: BasketItem) {
25 | this.basketService.incrementItemQuantity(item);
26 | }
27 |
28 | decrementItemQuantity(item: BasketItem) {
29 | this.basketService.decrementItemQuantity(item);
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/client/src/app/basket/basket.module.ts:
--------------------------------------------------------------------------------
1 | import { SharedModule } from './../shared/shared.module';
2 | import { NgModule } from '@angular/core';
3 | import { CommonModule } from '@angular/common';
4 |
5 | import { BasketRoutingModule } from './basket-routing.module';
6 | import { BasketComponent } from './basket.component';
7 |
8 |
9 | @NgModule({
10 | declarations: [BasketComponent],
11 | imports: [
12 | CommonModule,
13 | BasketRoutingModule,
14 | SharedModule
15 | ]
16 | })
17 | export class BasketModule { }
18 |
--------------------------------------------------------------------------------
/client/src/app/checkout/checkout-address/checkout-address.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Shipping Address
4 |
9 |
10 |
11 |
14 |
17 |
20 |
23 |
26 |
29 |
30 |
31 |
32 |
33 |
36 |
39 |
--------------------------------------------------------------------------------
/client/src/app/checkout/checkout-address/checkout-address.component.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobinHaider/An-E-commerce-app-with-.Net-Core-and-Angular/3f4ef5cae6b426b9cf0411324bc6674ec7e06551/client/src/app/checkout/checkout-address/checkout-address.component.scss
--------------------------------------------------------------------------------
/client/src/app/checkout/checkout-address/checkout-address.component.ts:
--------------------------------------------------------------------------------
1 | import { Address } from './../../shared/models/address';
2 | import { ToastrService } from 'ngx-toastr';
3 | import { AccountService } from './../../account/account.service';
4 | import { FormGroup } from '@angular/forms';
5 | import { Component, OnInit, Input } from '@angular/core';
6 |
7 | @Component({
8 | selector: 'app-checkout-address',
9 | templateUrl: './checkout-address.component.html',
10 | styleUrls: ['./checkout-address.component.scss']
11 | })
12 | export class CheckoutAddressComponent implements OnInit {
13 | @Input() checkoutForm: FormGroup;
14 |
15 | constructor(private accountService: AccountService, private toastr: ToastrService) { }
16 |
17 | ngOnInit(): void {
18 | }
19 |
20 | saveUserAddress(){
21 | this.accountService.updateUserAddress(this.checkoutForm.get('addressForm').value)
22 | .subscribe((address: Address) => {
23 | this.toastr.success('Address Saved');
24 | this.checkoutForm.get('addressForm').reset(address);
25 | }, error => {
26 | this.toastr.error(error.message);
27 | console.log(error);
28 | });
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/client/src/app/checkout/checkout-delivery/checkout-delivery.component.html:
--------------------------------------------------------------------------------
1 |
2 |
Choose Your Delivery Method
3 |
4 |
5 |
13 |
18 |
19 |
20 |
21 |
22 |
23 |
26 |
29 |
--------------------------------------------------------------------------------
/client/src/app/checkout/checkout-delivery/checkout-delivery.component.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobinHaider/An-E-commerce-app-with-.Net-Core-and-Angular/3f4ef5cae6b426b9cf0411324bc6674ec7e06551/client/src/app/checkout/checkout-delivery/checkout-delivery.component.scss
--------------------------------------------------------------------------------
/client/src/app/checkout/checkout-delivery/checkout-delivery.component.ts:
--------------------------------------------------------------------------------
1 | import { BasketService } from './../../basket/basket.service';
2 | import { IDeliveryMethod } from './../../shared/models/deliveryMethod';
3 | import { FormGroup } from '@angular/forms';
4 | import { CheckoutService } from './../checkout.service';
5 | import { Component, OnInit, Input } from '@angular/core';
6 |
7 | @Component({
8 | selector: 'app-checkout-delivery',
9 | templateUrl: './checkout-delivery.component.html',
10 | styleUrls: ['./checkout-delivery.component.scss']
11 | })
12 | export class CheckoutDeliveryComponent implements OnInit {
13 | @Input() checkoutForm: FormGroup;
14 | deliveryMethods: IDeliveryMethod[];
15 |
16 | constructor(private checkoutService: CheckoutService, private basketService: BasketService) { }
17 |
18 | ngOnInit(): void {
19 | this.checkoutService.getDeliveryMethods().subscribe((dm: IDeliveryMethod[]) => {
20 | this.deliveryMethods = dm;
21 | }, error => {
22 | console.log(error);
23 | });
24 | }
25 |
26 | setShippingPrice(deliveryMethod: IDeliveryMethod){
27 | this.basketService.setShippingPrice(deliveryMethod);
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/client/src/app/checkout/checkout-payment/checkout-payment.component.html:
--------------------------------------------------------------------------------
1 |
20 |
21 |
22 |
25 |
34 |
--------------------------------------------------------------------------------
/client/src/app/checkout/checkout-payment/checkout-payment.component.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobinHaider/An-E-commerce-app-with-.Net-Core-and-Angular/3f4ef5cae6b426b9cf0411324bc6674ec7e06551/client/src/app/checkout/checkout-payment/checkout-payment.component.scss
--------------------------------------------------------------------------------
/client/src/app/checkout/checkout-review/checkout-review.component.html:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
9 |
12 |
--------------------------------------------------------------------------------
/client/src/app/checkout/checkout-review/checkout-review.component.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobinHaider/An-E-commerce-app-with-.Net-Core-and-Angular/3f4ef5cae6b426b9cf0411324bc6674ec7e06551/client/src/app/checkout/checkout-review/checkout-review.component.scss
--------------------------------------------------------------------------------
/client/src/app/checkout/checkout-review/checkout-review.component.ts:
--------------------------------------------------------------------------------
1 | import { CdkStepper } from '@angular/cdk/stepper';
2 | import { ToastrService } from 'ngx-toastr';
3 | import { BasketService } from './../../basket/basket.service';
4 | import { Component, OnInit, Input } from '@angular/core';
5 |
6 | @Component({
7 | selector: 'app-checkout-review',
8 | templateUrl: './checkout-review.component.html',
9 | styleUrls: ['./checkout-review.component.scss']
10 | })
11 | export class CheckoutReviewComponent implements OnInit {
12 | @Input() appStepper: CdkStepper;
13 |
14 | constructor(private basketService: BasketService, private toastr: ToastrService) { }
15 |
16 | ngOnInit(): void {
17 | }
18 |
19 | createPaymentIntent(){
20 | return this.basketService.createPaymentIntent().subscribe((response: any) => {
21 | // this.toastr.success('Payment Intent Created');
22 | this.appStepper.next();
23 | }, error => {
24 | console.log(error);
25 | // this.toastr.error(error.message);
26 | });
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/client/src/app/checkout/checkout-routing.module.ts:
--------------------------------------------------------------------------------
1 | import { CheckoutSuccessComponent } from './checkout-success/checkout-success.component';
2 | import { CheckoutComponent } from './checkout.component';
3 | import { NgModule } from '@angular/core';
4 | import { Routes, RouterModule } from '@angular/router';
5 |
6 |
7 | const routes: Routes = [
8 | {path: '', component: CheckoutComponent},
9 | {path: 'success', component: CheckoutSuccessComponent}
10 | ];
11 |
12 | @NgModule({
13 | imports: [RouterModule.forChild(routes)],
14 | exports: [RouterModule]
15 | })
16 | export class CheckoutRoutingModule { }
17 |
--------------------------------------------------------------------------------
/client/src/app/checkout/checkout-success/checkout-success.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Thank you, Your order is confirmed
4 |
Your order hasn't shipped yet, but this is to be expected as we are not a real store!
5 |
6 |
7 |
--------------------------------------------------------------------------------
/client/src/app/checkout/checkout-success/checkout-success.component.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobinHaider/An-E-commerce-app-with-.Net-Core-and-Angular/3f4ef5cae6b426b9cf0411324bc6674ec7e06551/client/src/app/checkout/checkout-success/checkout-success.component.scss
--------------------------------------------------------------------------------
/client/src/app/checkout/checkout-success/checkout-success.component.ts:
--------------------------------------------------------------------------------
1 | import { IOrder } from './../../shared/models/order';
2 | import { Component, OnInit } from '@angular/core';
3 | import { Router } from '@angular/router';
4 |
5 | @Component({
6 | selector: 'app-checkout-success',
7 | templateUrl: './checkout-success.component.html',
8 | styleUrls: ['./checkout-success.component.scss']
9 | })
10 | export class CheckoutSuccessComponent implements OnInit {
11 | order: IOrder;
12 |
13 | constructor(private router: Router) {
14 | const navigation = this.router.getCurrentNavigation();
15 | const state = navigation && navigation.extras && navigation.extras.state;
16 | if(state){
17 | this.order = state as IOrder;
18 | }
19 | }
20 |
21 | ngOnInit(): void {
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/client/src/app/checkout/checkout.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
22 |
23 |
--------------------------------------------------------------------------------
/client/src/app/checkout/checkout.component.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobinHaider/An-E-commerce-app-with-.Net-Core-and-Angular/3f4ef5cae6b426b9cf0411324bc6674ec7e06551/client/src/app/checkout/checkout.component.scss
--------------------------------------------------------------------------------
/client/src/app/checkout/checkout.component.ts:
--------------------------------------------------------------------------------
1 | import { BasketService } from './../basket/basket.service';
2 | import { AccountService } from './../account/account.service';
3 | import { FormGroup, FormBuilder, Validators } from '@angular/forms';
4 | import { Component, OnInit } from '@angular/core';
5 |
6 | @Component({
7 | selector: 'app-checkout',
8 | templateUrl: './checkout.component.html',
9 | styleUrls: ['./checkout.component.scss']
10 | })
11 | export class CheckoutComponent implements OnInit {
12 | checkoutForm: FormGroup;
13 |
14 | constructor(private fb: FormBuilder, private accountService: AccountService, private basketService: BasketService) { }
15 |
16 | ngOnInit(): void {
17 | this.createCheckoutForm();
18 | this.getAddressFormValue();
19 | this.getDeliveryMethodValue();
20 | }
21 |
22 | createCheckoutForm(){
23 | this.checkoutForm = this.fb.group({
24 | addressForm: this.fb.group({
25 | firstName: [null, Validators.required],
26 | lastName: [null, Validators.required],
27 | street: [null, Validators.required],
28 | city: [null, Validators.required],
29 | state: [null, Validators.required],
30 | zipcode: [null, Validators.required],
31 | }),
32 | deliveryForm: this.fb.group({
33 | deliveryMethod: [null, Validators.required]
34 | }),
35 | paymentForm: this.fb.group({
36 | nameOnCard: [null, Validators.required]
37 | })
38 | });
39 | }
40 |
41 | getAddressFormValue(){
42 | this.accountService.getUserAddress().subscribe(address => {
43 | if(address){
44 | this.checkoutForm.get('addressForm').patchValue(address);
45 | }
46 | }, error => {
47 | console.log(error);
48 | });
49 | }
50 |
51 | getDeliveryMethodValue(){
52 | const basket = this.basketService.getCurrentBasketValue();
53 | if(basket.deliveryMethodId !== null){
54 | this.checkoutForm.get('deliveryForm').get('deliveryMethod').patchValue(basket.deliveryMethodId.toString());
55 | }
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/client/src/app/checkout/checkout.module.ts:
--------------------------------------------------------------------------------
1 | import { SharedModule } from './../shared/shared.module';
2 | import { NgModule } from '@angular/core';
3 | import { CommonModule } from '@angular/common';
4 |
5 | import { CheckoutRoutingModule } from './checkout-routing.module';
6 | import { CheckoutComponent } from './checkout.component';
7 | import { CheckoutAddressComponent } from './checkout-address/checkout-address.component';
8 | import { CheckoutDeliveryComponent } from './checkout-delivery/checkout-delivery.component';
9 | import { CheckoutReviewComponent } from './checkout-review/checkout-review.component';
10 | import { CheckoutPaymentComponent } from './checkout-payment/checkout-payment.component';
11 | import { CheckoutSuccessComponent } from './checkout-success/checkout-success.component';
12 |
13 |
14 | @NgModule({
15 | declarations: [CheckoutComponent, CheckoutAddressComponent, CheckoutDeliveryComponent, CheckoutReviewComponent, CheckoutPaymentComponent, CheckoutSuccessComponent],
16 | imports: [
17 | CommonModule,
18 | CheckoutRoutingModule,
19 | SharedModule
20 | ]
21 | })
22 | export class CheckoutModule { }
23 |
--------------------------------------------------------------------------------
/client/src/app/checkout/checkout.service.ts:
--------------------------------------------------------------------------------
1 | import { IOrderToCreate } from './../shared/models/order';
2 | import { IDeliveryMethod } from './../shared/models/deliveryMethod';
3 | import { map } from 'rxjs/operators';
4 | import { Injectable } from '@angular/core';
5 | import { environment } from 'src/environments/environment';
6 | import { HttpClient } from '@angular/common/http';
7 |
8 | @Injectable({
9 | providedIn: 'root'
10 | })
11 | export class CheckoutService {
12 | baseUrl = environment.apiUrl;
13 |
14 | constructor(private http: HttpClient) { }
15 |
16 | createOrder(order: IOrderToCreate){
17 | return this.http.post(this.baseUrl + 'orders', order);
18 | }
19 |
20 | getDeliveryMethods(){
21 | return this.http.get(this.baseUrl + 'orders/deliveryMethods').pipe(
22 | map((dm: IDeliveryMethod[]) => {
23 | return dm.sort((a, b) => b.price - a.price);
24 | })
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/client/src/app/core/Guards/auth.guard.ts:
--------------------------------------------------------------------------------
1 | import { AccountService } from './../../account/account.service';
2 | import { Injectable } from '@angular/core';
3 | import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree, Router } from '@angular/router';
4 | import { Observable } from 'rxjs';
5 | import { map } from 'rxjs/operators';
6 |
7 | @Injectable({
8 | providedIn: 'root'
9 | })
10 | export class AuthGuard implements CanActivate {
11 |
12 | constructor(private accountService: AccountService, private router: Router) {}
13 |
14 | canActivate(
15 | next: ActivatedRouteSnapshot,
16 | state: RouterStateSnapshot): Observable | Promise | boolean | UrlTree {
17 | return this.accountService.currentUser$.pipe(
18 | map(auth => {
19 | if(auth){
20 | return true;
21 | }
22 | this.router.navigate(['account/login'], {queryParams: {returnUrl: state.url}});
23 | })
24 | );
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/client/src/app/core/Services/busy.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { NgxSpinnerService } from 'ngx-spinner';
3 |
4 | @Injectable({
5 | providedIn: 'root',
6 | })
7 | export class BusyService {
8 | busyRequestCount = 0;
9 |
10 | constructor(private spinnerService: NgxSpinnerService) {}
11 |
12 | busy() {
13 | this.busyRequestCount++;
14 | this.spinnerService.show(undefined, {
15 | type: 'pacman',
16 | bdColor: 'rgba(255,255,255,0.7)',
17 | color: '#333333',
18 | });
19 | }
20 |
21 | idle() {
22 | this.busyRequestCount--;
23 | if (this.busyRequestCount <= 0) {
24 | this.busyRequestCount = 0;
25 | this.spinnerService.hide();
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/client/src/app/core/core.module.ts:
--------------------------------------------------------------------------------
1 | import { SharedModule } from './../shared/shared.module';
2 | import { RouterModule } from '@angular/router';
3 | import { NavBarComponent } from './nav-bar/nav-bar.component';
4 |
5 | import { NgModule } from '@angular/core';
6 | import { CommonModule } from '@angular/common';
7 | import { TestErrorComponent } from './test-error/test-error.component';
8 | import { NotFoundComponent } from './not-found/not-found.component';
9 | import { ServerErrorComponent } from './server-error/server-error.component';
10 | import { ToastrModule} from 'ngx-toastr';
11 | import { SectionHeaderComponent } from './section-header/section-header.component';
12 | import { BreadcrumbModule} from 'xng-breadcrumb';
13 |
14 |
15 | @NgModule({
16 | declarations: [NavBarComponent, TestErrorComponent, NotFoundComponent, ServerErrorComponent, SectionHeaderComponent],
17 | imports: [
18 | CommonModule,
19 | RouterModule,
20 | BreadcrumbModule,
21 | SharedModule,
22 | ToastrModule.forRoot({
23 | positionClass: 'toast-bottom-right',
24 | preventDuplicates: true
25 | })
26 | ],
27 | exports: [NavBarComponent, SectionHeaderComponent]
28 | })
29 | export class CoreModule { }
30 |
--------------------------------------------------------------------------------
/client/src/app/core/interceptors/error.interceptor.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import {
3 | HttpRequest,
4 | HttpHandler,
5 | HttpEvent,
6 | HttpInterceptor
7 | } from '@angular/common/http';
8 | import { Observable, throwError } from 'rxjs';
9 | import { Router, NavigationExtras } from '@angular/router';
10 | import { catchError } from 'rxjs/operators';
11 | import { ToastrService } from 'ngx-toastr';
12 |
13 | @Injectable()
14 | export class ErrorInterceptor implements HttpInterceptor {
15 |
16 | constructor(private router: Router, private toastr: ToastrService) {}
17 |
18 | intercept(request: HttpRequest, next: HttpHandler): Observable> {
19 | return next.handle(request).pipe(
20 | catchError(error => {
21 |
22 | if(error){
23 |
24 | if(error.status === 400){
25 |
26 | if(error.error.errors){
27 | throw error.error;
28 | }else{
29 | this.toastr.error(error.error.message, error.error.statusCode);
30 | }
31 | }
32 |
33 | if(error.status === 401){
34 | this.toastr.error(error.error.message, error.error.statusCode);
35 | }
36 | if(error.status === 404){
37 | this.router.navigateByUrl('/not-found');
38 | }
39 | if(error.status === 500){
40 | const navigationExtras: NavigationExtras = {state: {error: error.error}};
41 | this.router.navigateByUrl('/server-error', navigationExtras);
42 | }
43 | }
44 |
45 | return throwError(error);
46 | })
47 | );
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/client/src/app/core/interceptors/jwt.interceptor.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import {
3 | HttpRequest,
4 | HttpHandler,
5 | HttpEvent,
6 | HttpInterceptor
7 | } from '@angular/common/http';
8 | import { Observable } from 'rxjs';
9 |
10 | @Injectable()
11 | export class JwtInterceptor implements HttpInterceptor {
12 |
13 | constructor() {}
14 |
15 | intercept(request: HttpRequest, next: HttpHandler): Observable> {
16 | const token = localStorage.getItem('token');
17 |
18 | if(token){
19 | request = request.clone({
20 | setHeaders: {
21 | Authorization: `Bearer ${token}`
22 | }
23 | });
24 | }
25 | return next.handle(request);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/client/src/app/core/interceptors/loading.interceptor.ts:
--------------------------------------------------------------------------------
1 | import { BusyService } from './../Services/busy.service';
2 | import { Injectable } from '@angular/core';
3 | import {
4 | HttpRequest,
5 | HttpHandler,
6 | HttpEvent,
7 | HttpInterceptor
8 | } from '@angular/common/http';
9 | import { Observable } from 'rxjs';
10 | import { delay, finalize } from 'rxjs/operators';
11 |
12 | @Injectable()
13 | export class LoadingInterceptor implements HttpInterceptor {
14 |
15 | constructor(private busyService: BusyService) {}
16 |
17 | intercept(request: HttpRequest, next: HttpHandler): Observable> {
18 | if(request.method === 'POST' && request.url.includes('orders')){
19 | return next.handle(request);
20 | }
21 | if(request.url.includes('emailexists')){
22 | return next.handle(request);
23 | }
24 | this.busyService.busy();
25 | return next.handle(request).pipe(
26 | finalize(() => {
27 | this.busyService.idle();
28 | })
29 | );
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/client/src/app/core/nav-bar/nav-bar.component.html:
--------------------------------------------------------------------------------
1 |
4 |

11 |
22 |
55 |
56 |
--------------------------------------------------------------------------------
/client/src/app/core/nav-bar/nav-bar.component.scss:
--------------------------------------------------------------------------------
1 | .cart-no {
2 | position: absolute;
3 | min-height: 25px;
4 | min-width: 25px;
5 | border-radius: 50%;
6 | font-size: 1em;
7 | background: blue;
8 | color: white;
9 | text-align: center;
10 | top: -12px;
11 | right: 32px;
12 | }
13 |
14 | a {
15 | text-decoration: none;
16 | color: #343a40;
17 |
18 | &.active {
19 | color: orange;
20 | }
21 | }
22 |
23 | .logo {
24 | cursor: pointer;
25 |
26 | &:focus {
27 | outline: none;
28 | }
29 | }
--------------------------------------------------------------------------------
/client/src/app/core/nav-bar/nav-bar.component.ts:
--------------------------------------------------------------------------------
1 | import { AccountService } from './../../account/account.service';
2 | import { BasketService } from './../../basket/basket.service';
3 | import { Observable } from 'rxjs';
4 | import { Component, OnInit } from '@angular/core';
5 | import { IBasket } from 'src/app/shared/models/basket';
6 | import { User } from 'src/app/shared/models/user';
7 |
8 | @Component({
9 | selector: 'app-nav-bar',
10 | templateUrl: './nav-bar.component.html',
11 | styleUrls: ['./nav-bar.component.scss'],
12 | })
13 | export class NavBarComponent implements OnInit {
14 | basket$: Observable;
15 | currentUser$: Observable;
16 |
17 | constructor(
18 | private basketService: BasketService,
19 | private accountService: AccountService
20 | ) {}
21 |
22 | ngOnInit(): void {
23 | this.basket$ = this.basketService.basket$;
24 | this.currentUser$ = this.accountService.currentUser$;
25 | }
26 |
27 | logout(){
28 | this.accountService.logout();
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/client/src/app/core/not-found/not-found.component.html:
--------------------------------------------------------------------------------
1 | not-found works!
2 |
--------------------------------------------------------------------------------
/client/src/app/core/not-found/not-found.component.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobinHaider/An-E-commerce-app-with-.Net-Core-and-Angular/3f4ef5cae6b426b9cf0411324bc6674ec7e06551/client/src/app/core/not-found/not-found.component.scss
--------------------------------------------------------------------------------
/client/src/app/core/not-found/not-found.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-not-found',
5 | templateUrl: './not-found.component.html',
6 | styleUrls: ['./not-found.component.scss']
7 | })
8 | export class NotFoundComponent implements OnInit {
9 |
10 | constructor() { }
11 |
12 | ngOnInit(): void {
13 | }
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/client/src/app/core/section-header/section-header.component.html:
--------------------------------------------------------------------------------
1 |
2 | 0 &&
5 | breadcrumbs[breadcrumbs.length - 1].label != 'Home'
6 | "
7 | class="py-3"
8 | style="margin-top: 105px; background-color: #f5f5f5;"
9 | >
10 |
11 |
12 |
13 |
14 | {{
15 | breadcrumbs.length > 0 &&
16 | breadcrumbs[breadcrumbs.length - 1].label | titlecase
17 | }}
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/client/src/app/core/section-header/section-header.component.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobinHaider/An-E-commerce-app-with-.Net-Core-and-Angular/3f4ef5cae6b426b9cf0411324bc6674ec7e06551/client/src/app/core/section-header/section-header.component.scss
--------------------------------------------------------------------------------
/client/src/app/core/section-header/section-header.component.ts:
--------------------------------------------------------------------------------
1 | import { Observable } from 'rxjs';
2 | import { Component, OnInit } from '@angular/core';
3 | import { BreadcrumbService } from 'xng-breadcrumb';
4 |
5 | @Component({
6 | selector: 'app-section-header',
7 | templateUrl: './section-header.component.html',
8 | styleUrls: ['./section-header.component.scss']
9 | })
10 | export class SectionHeaderComponent implements OnInit {
11 | breadcrumb$: Observable;
12 |
13 | constructor(private breadcrumbService: BreadcrumbService) { }
14 |
15 | ngOnInit(): void {
16 | this.breadcrumb$ = this.breadcrumbService.breadcrumbs$;
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/client/src/app/core/server-error/server-error.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Internal Server Error - refreshing the page will make the exception
4 | disappear
5 |
6 |
7 | Error: {{ error.message }}
8 |
9 | Note: if you are seeing this then Angular is probably not responsible
10 |
11 | What to do next?
12 |
13 | - Open chrome dev tools
14 | - Inspect the network tab
15 | - Check the failing request
16 | - Examine this request URL - make sure this is correct
17 | -
18 | Reproduce the error in postman - if we get the same reponse in Postman,
19 | then the issue is NOT with Angular
20 |
21 |
22 |
23 | Following is the stack trace - this is where your investigation should
24 | start!
25 |
26 | {{
27 | error.details
28 | }}
29 |
30 |
31 |
--------------------------------------------------------------------------------
/client/src/app/core/server-error/server-error.component.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobinHaider/An-E-commerce-app-with-.Net-Core-and-Angular/3f4ef5cae6b426b9cf0411324bc6674ec7e06551/client/src/app/core/server-error/server-error.component.scss
--------------------------------------------------------------------------------
/client/src/app/core/server-error/server-error.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 | import { Router } from '@angular/router';
3 |
4 | @Component({
5 | selector: 'app-server-error',
6 | templateUrl: './server-error.component.html',
7 | styleUrls: ['./server-error.component.scss']
8 | })
9 | export class ServerErrorComponent implements OnInit {
10 | error: any;
11 |
12 | constructor(private router: Router) {
13 | const navigation = router.getCurrentNavigation();
14 | this.error = navigation && navigation.extras && navigation.extras.state && navigation.extras.state.error;
15 | }
16 |
17 | ngOnInit(): void {
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/client/src/app/core/test-error/test-error.component.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
11 |
17 |
22 |
23 |
--------------------------------------------------------------------------------
/client/src/app/core/test-error/test-error.component.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobinHaider/An-E-commerce-app-with-.Net-Core-and-Angular/3f4ef5cae6b426b9cf0411324bc6674ec7e06551/client/src/app/core/test-error/test-error.component.scss
--------------------------------------------------------------------------------
/client/src/app/core/test-error/test-error.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 | import { environment } from 'src/environments/environment';
3 | import { HttpClient } from '@angular/common/http';
4 |
5 | @Component({
6 | selector: 'app-test-error',
7 | templateUrl: './test-error.component.html',
8 | styleUrls: ['./test-error.component.scss'],
9 | })
10 | export class TestErrorComponent implements OnInit {
11 | baseUrl = environment.apiUrl;
12 | validationErrors: any;
13 |
14 | constructor(private http: HttpClient) {}
15 |
16 | ngOnInit() {}
17 |
18 | get404Error() {
19 | this.http.get(this.baseUrl + 'products/42').subscribe(
20 | (response) => {
21 | console.log(response);
22 | },
23 | (error) => {
24 | console.log(error);
25 | }
26 | );
27 | }
28 |
29 | get500Error() {
30 | this.http.get(this.baseUrl + 'buggy/servererror').subscribe(
31 | (response) => {
32 | console.log(response);
33 | },
34 | (error) => {
35 | console.log(error);
36 | }
37 | );
38 | }
39 |
40 | get400Error() {
41 | this.http.get(this.baseUrl + 'buggy/badrequest').subscribe(
42 | (response) => {
43 | console.log(response);
44 | },
45 | (error) => {
46 | console.log(error);
47 | }
48 | );
49 | }
50 |
51 | get400ValidationError() {
52 | this.http.get(this.baseUrl + 'products/fortytwo').subscribe(
53 | (response) => {
54 | console.log(response);
55 | },
56 | (error) => {
57 | console.log(error);
58 | this.validationErrors = error.errors;
59 | }
60 | );
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/client/src/app/home/home.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
Welcome to the Shop!
15 |
16 |
--------------------------------------------------------------------------------
/client/src/app/home/home.component.scss:
--------------------------------------------------------------------------------
1 | .featured {
2 | height: 250px;
3 | }
4 |
5 | img {
6 | object-fit: cover;
7 | height: 600px;
8 | width: 100%;
9 | }
--------------------------------------------------------------------------------
/client/src/app/home/home.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-home',
5 | templateUrl: './home.component.html',
6 | styleUrls: ['./home.component.scss']
7 | })
8 | export class HomeComponent implements OnInit {
9 |
10 | constructor() { }
11 |
12 | ngOnInit(): void {
13 | }
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/client/src/app/home/home.module.ts:
--------------------------------------------------------------------------------
1 | import { SharedModule } from './../shared/shared.module';
2 | import { NgModule } from '@angular/core';
3 | import { CommonModule } from '@angular/common';
4 | import { HomeComponent } from './home.component';
5 |
6 |
7 |
8 | @NgModule({
9 | declarations: [HomeComponent],
10 | imports: [
11 | CommonModule,
12 | SharedModule
13 | ],
14 | exports: [HomeComponent]
15 | })
16 | export class HomeModule { }
17 |
--------------------------------------------------------------------------------
/client/src/app/orders/order-detailed/order-detailed.component.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobinHaider/An-E-commerce-app-with-.Net-Core-and-Angular/3f4ef5cae6b426b9cf0411324bc6674ec7e06551/client/src/app/orders/order-detailed/order-detailed.component.scss
--------------------------------------------------------------------------------
/client/src/app/orders/order-detailed/order-detailed.component.ts:
--------------------------------------------------------------------------------
1 | import { OrdersService } from './../orders.service';
2 | import { BreadcrumbService } from 'xng-breadcrumb';
3 | import { ActivatedRoute } from '@angular/router';
4 | import { IOrder } from './../../shared/models/order';
5 | import { Component, OnInit } from '@angular/core';
6 |
7 | @Component({
8 | selector: 'app-order-detailed',
9 | templateUrl: './order-detailed.component.html',
10 | styleUrls: ['./order-detailed.component.scss']
11 | })
12 | export class OrderDetailedComponent implements OnInit {
13 | order: IOrder;
14 |
15 | constructor(
16 | private route: ActivatedRoute,
17 | private breadcrumbService: BreadcrumbService,
18 | private ordersService: OrdersService
19 | ) {
20 | this.breadcrumbService.set('@OrderDetailed', '');
21 | }
22 |
23 | ngOnInit(): void {
24 | this.ordersService.getOrderDetailed(+this.route.snapshot.paramMap.get('id'))
25 | .subscribe((order: IOrder) => {
26 | this.order = order;
27 | this.breadcrumbService.set('@OrderDetailed', `Order# ${order.id} - ${order.status}`);
28 | }, error => {
29 | console.log(error);
30 | });
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/client/src/app/orders/orders-routing.module.ts:
--------------------------------------------------------------------------------
1 | import { OrderDetailedComponent } from './order-detailed/order-detailed.component';
2 | import { OrdersComponent } from './orders.component';
3 | import { NgModule } from '@angular/core';
4 | import { Routes, RouterModule } from '@angular/router';
5 |
6 |
7 | const routes: Routes = [
8 | {path: '', component: OrdersComponent},
9 | {path: ':id', component: OrderDetailedComponent, data: {breadcrumb: {alias: 'OrderDetailed'}}}
10 | ];
11 |
12 | @NgModule({
13 | imports: [RouterModule.forChild(routes)],
14 | exports: [RouterModule]
15 | })
16 | export class OrdersRoutingModule { }
17 |
--------------------------------------------------------------------------------
/client/src/app/orders/orders.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Order |
8 | Date |
9 | Total |
10 | Status |
11 |
12 |
13 |
14 |
15 | # {{order.id}} |
16 | {{order.orderDate | date: 'medium'}} |
17 | {{order.total | currency}} |
18 | {{order.status}} |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/client/src/app/orders/orders.component.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobinHaider/An-E-commerce-app-with-.Net-Core-and-Angular/3f4ef5cae6b426b9cf0411324bc6674ec7e06551/client/src/app/orders/orders.component.scss
--------------------------------------------------------------------------------
/client/src/app/orders/orders.component.ts:
--------------------------------------------------------------------------------
1 | import { OrdersService } from './orders.service';
2 | import { IOrder } from './../shared/models/order';
3 | import { Component, OnInit } from '@angular/core';
4 |
5 | @Component({
6 | selector: 'app-orders',
7 | templateUrl: './orders.component.html',
8 | styleUrls: ['./orders.component.scss']
9 | })
10 | export class OrdersComponent implements OnInit {
11 | orders: IOrder[];
12 |
13 | constructor(private orderService: OrdersService) { }
14 |
15 | ngOnInit(): void {
16 | this.getOrders();
17 | }
18 |
19 | getOrders(){
20 | this.orderService.getOrdersForUser().subscribe((orders: IOrder[]) => {
21 | this.orders = orders;
22 | console.log(orders);
23 | }, error => {
24 | console.log(error);
25 | });
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/client/src/app/orders/orders.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { CommonModule } from '@angular/common';
3 |
4 | import { OrdersRoutingModule } from './orders-routing.module';
5 | import { OrdersComponent } from './orders.component';
6 | import { OrderDetailedComponent } from './order-detailed/order-detailed.component';
7 |
8 |
9 | @NgModule({
10 | declarations: [OrdersComponent, OrderDetailedComponent],
11 | imports: [
12 | CommonModule,
13 | OrdersRoutingModule
14 | ]
15 | })
16 | export class OrdersModule { }
17 |
--------------------------------------------------------------------------------
/client/src/app/orders/orders.service.ts:
--------------------------------------------------------------------------------
1 | import { environment } from './../../environments/environment';
2 | import { Injectable } from '@angular/core';
3 | import { HttpClient } from '@angular/common/http';
4 |
5 | @Injectable({
6 | providedIn: 'root'
7 | })
8 | export class OrdersService {
9 | baseUrl = environment.apiUrl;
10 |
11 | constructor(private http: HttpClient) { }
12 |
13 | getOrdersForUser(){
14 | return this.http.get(this.baseUrl + 'orders');
15 | }
16 |
17 | getOrderDetailed(id: number){
18 | return this.http.get(this.baseUrl + 'orders/' + id);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/client/src/app/shared/components/basket-summary/basket-summary.component.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobinHaider/An-E-commerce-app-with-.Net-Core-and-Angular/3f4ef5cae6b426b9cf0411324bc6674ec7e06551/client/src/app/shared/components/basket-summary/basket-summary.component.scss
--------------------------------------------------------------------------------
/client/src/app/shared/components/basket-summary/basket-summary.component.ts:
--------------------------------------------------------------------------------
1 | import { BasketService } from './../../../basket/basket.service';
2 | import { BasketItem } from './../../models/basket';
3 | import { Observable } from 'rxjs';
4 | import { Component, OnInit, Output, EventEmitter, Input } from '@angular/core';
5 | import { IBasket } from '../../models/basket';
6 |
7 | @Component({
8 | selector: 'app-basket-summary',
9 | templateUrl: './basket-summary.component.html',
10 | styleUrls: ['./basket-summary.component.scss']
11 | })
12 | export class BasketSummaryComponent implements OnInit {
13 | basket$: Observable;
14 | @Output() decrement: EventEmitter = new EventEmitter();
15 | @Output() increment: EventEmitter = new EventEmitter();
16 | @Output() remove: EventEmitter = new EventEmitter();
17 | @Input() isBasket = true;
18 |
19 | constructor(private basketService: BasketService) { }
20 |
21 | ngOnInit(): void {
22 | this.basket$ = this.basketService.basket$;
23 | }
24 |
25 | decrementItemQuantity(item: BasketItem){
26 | this.decrement.emit(item);
27 | }
28 |
29 | incrementItemQuantity(item: BasketItem){
30 | this.increment.emit(item);
31 | }
32 | removeBasketItem(item: BasketItem){
33 | this.remove.emit(item);
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/client/src/app/shared/components/order-totals/order-totals.component.html:
--------------------------------------------------------------------------------
1 |
2 | Order Summary
3 |
4 |
5 |
Shipping costs will be added depending on choices made during checkout
6 |
7 | -
8 | Order subtotal
9 | {{(basketTotal$ | async).subtotal | currency}}
10 |
11 | -
12 | Shipping and handling
13 | {{(basketTotal$ | async).shipping | currency}}
14 |
15 | -
16 | Total
17 | {{(basketTotal$ | async).total | currency}}
18 |
19 |
20 |
--------------------------------------------------------------------------------
/client/src/app/shared/components/order-totals/order-totals.component.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobinHaider/An-E-commerce-app-with-.Net-Core-and-Angular/3f4ef5cae6b426b9cf0411324bc6674ec7e06551/client/src/app/shared/components/order-totals/order-totals.component.scss
--------------------------------------------------------------------------------
/client/src/app/shared/components/order-totals/order-totals.component.ts:
--------------------------------------------------------------------------------
1 | import { BasketService } from './../../../basket/basket.service';
2 | import { Observable } from 'rxjs';
3 | import { Component, OnInit } from '@angular/core';
4 | import { BasketTotals } from '../../models/basket';
5 |
6 | @Component({
7 | selector: 'app-order-totals',
8 | templateUrl: './order-totals.component.html',
9 | styleUrls: ['./order-totals.component.scss']
10 | })
11 | export class OrderTotalsComponent implements OnInit {
12 | basketTotal$: Observable;
13 |
14 | constructor(private basketService: BasketService) { }
15 |
16 | ngOnInit(): void {
17 | this.basketTotal$ = this.basketService.basketTotal$;
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/client/src/app/shared/components/pager/pager.component.html:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/client/src/app/shared/components/pager/pager.component.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobinHaider/An-E-commerce-app-with-.Net-Core-and-Angular/3f4ef5cae6b426b9cf0411324bc6674ec7e06551/client/src/app/shared/components/pager/pager.component.scss
--------------------------------------------------------------------------------
/client/src/app/shared/components/pager/pager.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-pager',
5 | templateUrl: './pager.component.html',
6 | styleUrls: ['./pager.component.scss']
7 | })
8 | export class PagerComponent implements OnInit {
9 | @Input() totalCount: number;
10 | @Input() pageSize: number;
11 | @Output() pageChanged = new EventEmitter();
12 |
13 | constructor() { }
14 |
15 | ngOnInit(): void {
16 | }
17 |
18 | onPagerChanged(event: any){
19 | this.pageChanged.emit(event.page);
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/client/src/app/shared/components/paging-header/paging-header.component.html:
--------------------------------------------------------------------------------
1 |
2 | 0">
3 | Showing
4 |
5 | {{(pageNumber-1) * pageSize+1}} -
6 | {{pageNumber*pageSize
7 | > this.totalCount
8 | ? this.totalCount
9 | : pageNumber*pageSize
10 | }}
11 | of {{this.totalCount}} Results
12 |
13 | There are 0 results for this filter
14 |
15 |
--------------------------------------------------------------------------------
/client/src/app/shared/components/paging-header/paging-header.component.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobinHaider/An-E-commerce-app-with-.Net-Core-and-Angular/3f4ef5cae6b426b9cf0411324bc6674ec7e06551/client/src/app/shared/components/paging-header/paging-header.component.scss
--------------------------------------------------------------------------------
/client/src/app/shared/components/paging-header/paging-header.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit, Input } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-paging-header',
5 | templateUrl: './paging-header.component.html',
6 | styleUrls: ['./paging-header.component.scss']
7 | })
8 | export class PagingHeaderComponent implements OnInit {
9 | @Input() pageNumber: number;
10 | @Input() pageSize: number;
11 | @Input() totalCount: number;
12 |
13 | constructor() { }
14 |
15 | ngOnInit(): void {
16 | }
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/client/src/app/shared/components/text-input/text-input.component.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/client/src/app/shared/components/text-input/text-input.component.scss:
--------------------------------------------------------------------------------
1 | .form-label-group {
2 | position: relative;
3 | margin-bottom: 1rem;
4 | }
5 |
6 | .form-label-group > input,
7 | .form-label-group > label {
8 | height: 3.125rem;
9 | padding: .75rem;
10 | }
11 |
12 | .form-label-group > label {
13 | position: absolute;
14 | top: 0;
15 | left: 0;
16 | display: block;
17 | width: 100%;
18 | margin-bottom: 0; /* Override default `