diff --git a/src/app/app.config.ts b/src/app/app.config.ts index c778438..f09bc97 100644 --- a/src/app/app.config.ts +++ b/src/app/app.config.ts @@ -1,7 +1,8 @@ import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core'; import { provideRouter } from '@angular/router'; import { routes } from './app.routes'; +import { provideHttpClient } from '@angular/common/http'; export const appConfig: ApplicationConfig = { - providers: [provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes)] + providers: [provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes), provideHttpClient()] }; diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts index 6aeb858..5f521ac 100644 --- a/src/app/app.routes.ts +++ b/src/app/app.routes.ts @@ -1,6 +1,12 @@ import { Routes } from '@angular/router'; import {ProductListComponent} from './product-list/product-list.component'; +import { ProductDetailsComponent } from './product-details/product-details.component'; +import { CartComponent } from './cart/cart.component'; +import { ShippingComponent } from './shipping/shipping.component'; export const routes: Routes = [ { path: '', component: ProductListComponent }, + { path: 'products/:productId', component: ProductDetailsComponent }, + { path: 'cart', component: CartComponent }, + { path: 'shipping', component: ShippingComponent }, ]; diff --git a/src/app/cart.service.spec.ts b/src/app/cart.service.spec.ts new file mode 100644 index 0000000..cb4a750 --- /dev/null +++ b/src/app/cart.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { CartService } from './cart.service'; + +describe('CartService', () => { + let service: CartService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(CartService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/src/app/cart.service.ts b/src/app/cart.service.ts new file mode 100644 index 0000000..1ea47f9 --- /dev/null +++ b/src/app/cart.service.ts @@ -0,0 +1,30 @@ +import { Injectable } from '@angular/core'; +import { Product } from './products'; +import { HttpClient } from '@angular/common/http'; + +@Injectable({ + providedIn: 'root' +}) +export class CartService { + items: Product[] = []; + constructor( + private http: HttpClient, + ) { } + + addToCart(product: Product) { + this.items.push(product); + } + + getItems() { + return this.items; + } + + clearCart() { + this.items = []; + return this.items; + } + + getShippingPrices() { + return this.http.get<{type: string, price: number}[]>('/assets/shiping.json'); + } +} diff --git a/src/app/cart/cart.component.css b/src/app/cart/cart.component.css new file mode 100644 index 0000000..e69de29 diff --git a/src/app/cart/cart.component.html b/src/app/cart/cart.component.html new file mode 100644 index 0000000..e54f182 --- /dev/null +++ b/src/app/cart/cart.component.html @@ -0,0 +1,12 @@ +

Cart

+ +

+ Shipping Prices +

+ +@for(item of items; track item.id){ +
+ {{ item.name }} + {{ item.price | currency }} +
+} diff --git a/src/app/cart/cart.component.spec.ts b/src/app/cart/cart.component.spec.ts new file mode 100644 index 0000000..03dcc4a --- /dev/null +++ b/src/app/cart/cart.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { CartComponent } from './cart.component'; + +describe('CartComponent', () => { + let component: CartComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [CartComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(CartComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/cart/cart.component.ts b/src/app/cart/cart.component.ts new file mode 100644 index 0000000..6968f5b --- /dev/null +++ b/src/app/cart/cart.component.ts @@ -0,0 +1,21 @@ +import { Component } from '@angular/core'; +import { CartService } from '../cart.service'; +import { Product } from '../products'; +import { CurrencyPipe } from '@angular/common'; + +@Component({ + selector: 'app-cart', + standalone: true, + imports: [CurrencyPipe], + templateUrl: './cart.component.html', + styleUrl: './cart.component.css' +}) +export class CartComponent { + items: Product[] | undefined = undefined; + + constructor( + private cartService: CartService, + ) { + this.items = this.cartService.getItems(); + } +} diff --git a/src/app/product-alerts/product-alerts.component.css b/src/app/product-alerts/product-alerts.component.css new file mode 100644 index 0000000..e69de29 diff --git a/src/app/product-alerts/product-alerts.component.html b/src/app/product-alerts/product-alerts.component.html new file mode 100644 index 0000000..eb1cf5f --- /dev/null +++ b/src/app/product-alerts/product-alerts.component.html @@ -0,0 +1,5 @@ +@if(product && product.price > 700){ +

+ +

+} diff --git a/src/app/product-alerts/product-alerts.component.spec.ts b/src/app/product-alerts/product-alerts.component.spec.ts new file mode 100644 index 0000000..6709df8 --- /dev/null +++ b/src/app/product-alerts/product-alerts.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ProductAlertsComponent } from './product-alerts.component'; + +describe('ProductAlertsComponent', () => { + let component: ProductAlertsComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ProductAlertsComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ProductAlertsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/product-alerts/product-alerts.component.ts b/src/app/product-alerts/product-alerts.component.ts new file mode 100644 index 0000000..1414203 --- /dev/null +++ b/src/app/product-alerts/product-alerts.component.ts @@ -0,0 +1,14 @@ +import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { Product } from '../products'; + +@Component({ + selector: 'app-product-alerts', + standalone: true, + imports: [], + templateUrl: './product-alerts.component.html', + styleUrl: './product-alerts.component.css' +}) +export class ProductAlertsComponent { + @Input() product: Product | undefined; + @Output() notify = new EventEmitter(); +} diff --git a/src/app/product-details/product-details.component.css b/src/app/product-details/product-details.component.css new file mode 100644 index 0000000..e69de29 diff --git a/src/app/product-details/product-details.component.html b/src/app/product-details/product-details.component.html new file mode 100644 index 0000000..1af8a15 --- /dev/null +++ b/src/app/product-details/product-details.component.html @@ -0,0 +1,7 @@ +

Product Details

+ +@if(product){
+

{{ product.name }}

+

{{ product.price | currency }}

+

{{ product.description }}

+
} diff --git a/src/app/product-details/product-details.component.spec.ts b/src/app/product-details/product-details.component.spec.ts new file mode 100644 index 0000000..bf10c15 --- /dev/null +++ b/src/app/product-details/product-details.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ProductDetailsComponent } from './product-details.component'; + +describe('ProductDetailsComponent', () => { + let component: ProductDetailsComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ProductDetailsComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ProductDetailsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/product-details/product-details.component.ts b/src/app/product-details/product-details.component.ts new file mode 100644 index 0000000..2242c67 --- /dev/null +++ b/src/app/product-details/product-details.component.ts @@ -0,0 +1,30 @@ +import { Component, OnInit } from '@angular/core'; +import { Product, products } from '../products'; +import { ActivatedRoute } from '@angular/router'; +import { CurrencyPipe, NgIf } from '@angular/common'; +import { CartService } from '../cart.service'; + +@Component({ + selector: 'app-product-details', + standalone: true, + imports: [CurrencyPipe, NgIf], + templateUrl: './product-details.component.html', + styleUrl: './product-details.component.css' +}) +export class ProductDetailsComponent implements OnInit { + product: Product | undefined; + + constructor(private route: ActivatedRoute, private cartService: CartService) { } + + addToCart(product: Product) { + this.cartService.addToCart(product); + window.alert('Your product has genn thrown into the cart!'); + } + + ngOnInit(): void { + const routeParams = this.route.snapshot.paramMap; + const productIdFromRoute = Number(routeParams.get('productId')); + + this.product = products.find(product => product.id === productIdFromRoute); + } +} diff --git a/src/app/product-list/product-list.component.html b/src/app/product-list/product-list.component.html index 1007667..4191bd9 100644 --- a/src/app/product-list/product-list.component.html +++ b/src/app/product-list/product-list.component.html @@ -1 +1,21 @@

Products

+ +@for(product of products; track product.id){ +
+

+ + {{ product.name }} + +

+ + @if(product.description){ +

Description: {{product.description}}

+ } + + + + +
+} diff --git a/src/app/product-list/product-list.component.ts b/src/app/product-list/product-list.component.ts index 5bfe608..a765361 100644 --- a/src/app/product-list/product-list.component.ts +++ b/src/app/product-list/product-list.component.ts @@ -1,10 +1,12 @@ import { Component } from '@angular/core'; import { products } from '../products'; +import { ProductAlertsComponent } from '../product-alerts/product-alerts.component'; +import { RouterModule } from '@angular/router'; @Component({ selector: 'app-product-list', standalone: true, - imports: [], + imports: [ProductAlertsComponent, RouterModule], templateUrl: './product-list.component.html', styleUrl: './product-list.component.css' }) @@ -14,4 +16,8 @@ export class ProductListComponent { share() { window.alert('The product has been shared!'); } + + onNotify() { + window.alert("You will be notified when the product goes on sale"); + } } diff --git a/src/app/shipping/shipping.component.css b/src/app/shipping/shipping.component.css new file mode 100644 index 0000000..e69de29 diff --git a/src/app/shipping/shipping.component.html b/src/app/shipping/shipping.component.html new file mode 100644 index 0000000..6c4d7ff --- /dev/null +++ b/src/app/shipping/shipping.component.html @@ -0,0 +1,8 @@ +

Shipping Prices

+ +@for(shipping of shippingCosts | async; track shipping.type) { +
+ {{ shipping.type }} + {{ shipping.price | currency }} +
+} diff --git a/src/app/shipping/shipping.component.spec.ts b/src/app/shipping/shipping.component.spec.ts new file mode 100644 index 0000000..b7d6707 --- /dev/null +++ b/src/app/shipping/shipping.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ShippingComponent } from './shipping.component'; + +describe('ShippingComponent', () => { + let component: ShippingComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ShippingComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ShippingComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/shipping/shipping.component.ts b/src/app/shipping/shipping.component.ts new file mode 100644 index 0000000..266839b --- /dev/null +++ b/src/app/shipping/shipping.component.ts @@ -0,0 +1,20 @@ +import { Component } from '@angular/core'; +import { CartService } from '../cart.service'; +import { Observable } from 'rxjs'; +import { AsyncPipe, CurrencyPipe } from '@angular/common'; + +@Component({ + selector: 'app-shipping', + standalone: true, + imports: [AsyncPipe, CurrencyPipe], + templateUrl: './shipping.component.html', + styleUrl: './shipping.component.css' +}) +export class ShippingComponent { + constructor(private cartService: CartService) { } + shippingCosts!: Observable<{ type: string, price: number }[]>; + + ngOnInit(): void { + this.shippingCosts = this.cartService.getShippingPrices(); + } +} diff --git a/src/app/top-bar/top-bar.component.html b/src/app/top-bar/top-bar.component.html index 86bbf82..365fb61 100644 --- a/src/app/top-bar/top-bar.component.html +++ b/src/app/top-bar/top-bar.component.html @@ -2,4 +2,6 @@

My Store

-shopping_cartCheckout + + shopping_cartCheckout +