diff --git a/Frontend/src/app/app.component.ts b/Frontend/src/app/app.component.ts index d45de93..f65d28c 100644 --- a/Frontend/src/app/app.component.ts +++ b/Frontend/src/app/app.component.ts @@ -1,6 +1,8 @@ import {Component, OnDestroy, OnInit} from '@angular/core'; import {NgcCookieConsentService, NgcInitializeEvent, NgcNoCookieLawEvent, NgcStatusChangeEvent} from 'ngx-cookieconsent'; import {Subscription} from 'rxjs'; +import {ApiService} from "./services/api.service"; + @Component({ selector: 'app-root', @@ -19,12 +21,18 @@ export class AppComponent implements OnInit, OnDestroy { private revokeChoiceSubscription: Subscription; private noCookieLawSubscription: Subscription; + isLoggedIn = false; + showUserBoard = false; + username?: string; + constructor( - private ccService: NgcCookieConsentService + private ccService: NgcCookieConsentService, + private api: ApiService ) { } ngOnInit(): void { + // subscribe to cookieconsent observables to react to main events this.popupOpenSubscription = this.ccService.popupOpen$.subscribe( () => { diff --git a/Frontend/src/app/app.module.ts b/Frontend/src/app/app.module.ts index 5635d5f..153ae2c 100644 --- a/Frontend/src/app/app.module.ts +++ b/Frontend/src/app/app.module.ts @@ -38,6 +38,8 @@ import { CopyrightComponent } from './components/copyright/copyright.component'; import { GreetingInfoSliderComponent } from './components/greeting-info-slider/greeting-info-slider.component'; import { KundenComponent } from './components/kunden/kunden.component'; import { AboutUsComponent } from './components/about-us/about-us.component'; +import { ProfileComponent } from './components/profile/profile.component'; +import { ProfilePageComponent } from './pages/profile-page/profile-page.component'; // For cookie popup const cookieConfig: NgcCookieConsentConfig = { @@ -102,6 +104,8 @@ const cookieConfig: NgcCookieConsentConfig = { GreetingInfoSliderComponent, KundenComponent, AboutUsComponent, + ProfileComponent, + ProfilePageComponent, ], imports: [ BrowserModule, diff --git a/Frontend/src/app/app.routing.ts b/Frontend/src/app/app.routing.ts index 8008c5b..2e13ded 100644 --- a/Frontend/src/app/app.routing.ts +++ b/Frontend/src/app/app.routing.ts @@ -11,6 +11,8 @@ import {ImprintComponent} from './pages/imprint/imprint.component'; import {PrivacyComponent} from './pages/privacy/privacy.component'; import {SigninComponent} from "./components/auth/signin/signin.component"; import {RegistrationComponent} from "./components/auth/registration/registration.component"; +import {ProfileComponent} from "./components/profile/profile.component"; +import {ProfilePageComponent} from "./pages/profile-page/profile-page.component"; const routes: Routes = [ {path: '', component: LandingpageComponent, pathMatch: 'full'}, @@ -21,6 +23,7 @@ const routes: Routes = [ {path: 'signin', component: SigninComponent}, {path: 'registration', component: RegistrationComponent}, {path: "product-detail", component: ProductDetailPageComponent}, + {path: "profile", component: ProfilePageComponent}, {path: '**', component: PageNotFoundPageComponent} ]; diff --git a/Frontend/src/app/components/about-us/about-us.component.html b/Frontend/src/app/components/about-us/about-us.component.html index 6fa5b2e..02cbb14 100644 --- a/Frontend/src/app/components/about-us/about-us.component.html +++ b/Frontend/src/app/components/about-us/about-us.component.html @@ -10,8 +10,8 @@
-

text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries

-

text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries

+

You follow the same passion as we do and you want to find alternatives to the de-facto monopolist Amazon?

+

In this case, welcome aboard! We’re happy that you share our passion and hope that we can help you achieving this goal with the website

diff --git a/Frontend/src/app/components/auth/registration/registration.component.html b/Frontend/src/app/components/auth/registration/registration.component.html index c18e6e0..e203b31 100644 --- a/Frontend/src/app/components/auth/registration/registration.component.html +++ b/Frontend/src/app/components/auth/registration/registration.component.html @@ -6,7 +6,7 @@
-

Konto erstellen

+

Registration

@@ -22,17 +22,17 @@
- +
- +
- Sich anmelden +

Have an account?Log In

diff --git a/Frontend/src/app/components/auth/registration/registration.component.ts b/Frontend/src/app/components/auth/registration/registration.component.ts index ff8c904..5324f72 100644 --- a/Frontend/src/app/components/auth/registration/registration.component.ts +++ b/Frontend/src/app/components/auth/registration/registration.component.ts @@ -1,6 +1,7 @@ import { Component, OnInit } from '@angular/core'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import {ApiService} from "../../../services/api.service"; +import {Router} from "@angular/router"; @Component({ @@ -15,7 +16,8 @@ export class RegistrationComponent implements OnInit { constructor( private formBuilder: FormBuilder, - private api : ApiService + private api : ApiService, + private router: Router ) { } ngOnInit(): void { @@ -32,6 +34,11 @@ export class RegistrationComponent implements OnInit { get me() { return this.form.controls; } onSubmit() { - this.api.registerUser(this.form.value.username, this.form.value.password, this.form.value.email).subscribe(res=>console.log(res)); + this.api.registerUser(this.form.value.username, this.form.value.password, this.form.value.email).subscribe( + res=> { + this.api.saveSessionInfoToLocalStorage(res); + this.router.navigate(['/']); + } + ); } } diff --git a/Frontend/src/app/components/auth/signin/signin.component.html b/Frontend/src/app/components/auth/signin/signin.component.html index 358f183..fb5992e 100644 --- a/Frontend/src/app/components/auth/signin/signin.component.html +++ b/Frontend/src/app/components/auth/signin/signin.component.html @@ -6,7 +6,7 @@
-

Anmelden

+

Sign In

@@ -18,12 +18,12 @@
- +
- Konto erstellen +

No account yet?sign up

diff --git a/Frontend/src/app/components/auth/signin/signin.component.ts b/Frontend/src/app/components/auth/signin/signin.component.ts index e39ac56..8ca6646 100644 --- a/Frontend/src/app/components/auth/signin/signin.component.ts +++ b/Frontend/src/app/components/auth/signin/signin.component.ts @@ -18,7 +18,6 @@ export class SigninComponent implements OnInit { private isSignUpFailed: boolean; private errorMessage: ''; - constructor( private formBuilder: FormBuilder, private api: ApiService, @@ -43,9 +42,8 @@ export class SigninComponent implements OnInit { this.api.loginUser(this.loginForm.value.username, this.loginForm.value.password) .subscribe( data => { - this.router.navigate(['']); this.isSuccessful = true; - this.isSignUpFailed = false; + this.router.navigate(['']); this.api.saveSessionInfoToLocalStorage(data); }, err => { diff --git a/Frontend/src/app/components/bottom-bar/bottom-bar.component.html b/Frontend/src/app/components/bottom-bar/bottom-bar.component.html index 039881b..9059db7 100644 --- a/Frontend/src/app/components/bottom-bar/bottom-bar.component.html +++ b/Frontend/src/app/components/bottom-bar/bottom-bar.component.html @@ -5,24 +5,22 @@

Location

- 70376 Stuttgart + 76133 Karlsruhe

-

FOLGE UNS

- - - - +

FOLLOW UNS

+ +
-

SOME INFO

+

CONTACT US

- text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries + betterzon-contact@mueller-patrick.tech

diff --git a/Frontend/src/app/components/hot-deals-widget/hot-deals-widget.component.html b/Frontend/src/app/components/hot-deals-widget/hot-deals-widget.component.html index a77fc6f..37474da 100644 --- a/Frontend/src/app/components/hot-deals-widget/hot-deals-widget.component.html +++ b/Frontend/src/app/components/hot-deals-widget/hot-deals-widget.component.html @@ -1,7 +1,7 @@
-

TOP-ANGEBOTE

+

TOP-SEARCHES

@@ -9,18 +9,18 @@
-
+
-
+
-
{{product.name}}
+
{{productsPricesMap[productId]?.product?.name}}
-
Amazon: {{product.price}}$
+
Amazon: {{productsPricesMap[productId]?.amazonPrice?.price_in_cents/100}}$
-
Plantshub: 599,00$
+
{{productsPricesMap[productId]?.vendor?.name}}: {{productsPricesMap[productId]?.lowestPrice?.price_in_cents/100}}
diff --git a/Frontend/src/app/components/hot-deals-widget/hot-deals-widget.component.ts b/Frontend/src/app/components/hot-deals-widget/hot-deals-widget.component.ts index 031dc53..d9a09e7 100644 --- a/Frontend/src/app/components/hot-deals-widget/hot-deals-widget.component.ts +++ b/Frontend/src/app/components/hot-deals-widget/hot-deals-widget.component.ts @@ -11,6 +11,9 @@ import {ActivatedRoute, Router} from '@angular/router'; export class HotDealsWidgetComponent implements OnInit { products: Product[] = []; + bestDealsProductIds = []; + amazonPrices = []; + productsPricesMap = new Map(); @Input() numberOfProducts: number; @Input() showProductPicture: boolean; @Input() searchQuery: string; @@ -24,12 +27,13 @@ export class HotDealsWidgetComponent implements OnInit { } ngOnInit(): void { - this.loadParams(); + + this.getBestDeals(); } loadParams(): void { if (!this.numberOfProducts) { - this.numberOfProducts = 10; + this.numberOfProducts = 9; } if (!this.showProductPicture) { this.showProductPicture = false; @@ -43,26 +47,69 @@ export class HotDealsWidgetComponent implements OnInit { switch (this.type) { case 'search': { - this.getSearchedProducts(); break; } default: { - this.getProducts(); + this.getProductsByIds(); + this.getAmazonPricesForBestDeals(); + this.getVendors() break; } } } - getProducts(): void { - this.apiService.getProducts().subscribe(products => this.products = products); + getProductsByIds(): void { + this.apiService.getProductsByIds(this.bestDealsProductIds).subscribe( + products => { + products.forEach(product => { + this.productsPricesMap [product.product_id].product = product; + }); + } + ); + } + + getBestDeals(): void { + this.apiService.getBestDeals(9).subscribe( + deals => { + deals.forEach(deal => { + this.bestDealsProductIds.push(deal.product_id); + this.productsPricesMap [deal.product_id] = {lowestPrice: deal} + }); + this.loadParams(); + } + ); + } + + getVendors(): void { + this.bestDealsProductIds.forEach( + productId => { + const currentDeal = this.productsPricesMap[productId].lowestPrice; + this.apiService.getVendorById(currentDeal.vendor_id).subscribe( + vendor => { + this.productsPricesMap[productId].vendor = vendor; + }); + }); + } + + + getAmazonPricesForBestDeals(): void{ + this.bestDealsProductIds.forEach(id => { + this.apiService.getAmazonPrice(id).subscribe( + price => { + this.amazonPrices.push(price); + this.productsPricesMap[price[0].product_id].amazonPrice = price[0]; + } + ); + } + ); } getSearchedProducts(): void { this.apiService.getProductsByQuery(this.searchQuery).subscribe(products => this.products = products); } - clickedProduct(product: Product): void { - this.router.navigate([('/product/' + product.product_id)]); + clickedProduct(productId: string): void { + this.router.navigate([('/product/' + productId)]); } diff --git a/Frontend/src/app/components/kunden/kunden.component.html b/Frontend/src/app/components/kunden/kunden.component.html index 0012423..0fde734 100644 --- a/Frontend/src/app/components/kunden/kunden.component.html +++ b/Frontend/src/app/components/kunden/kunden.component.html @@ -1,7 +1,7 @@
-

SIE VERTRAUEN UNS

+

THEY TRUST US

diff --git a/Frontend/src/app/components/product-details/product-details.component.html b/Frontend/src/app/components/product-details/product-details.component.html index f392f00..4e91ab0 100644 --- a/Frontend/src/app/components/product-details/product-details.component.html +++ b/Frontend/src/app/components/product-details/product-details.component.html @@ -1,3 +1,6 @@ +
+ +
@@ -20,8 +23,12 @@ {{product?.short_description}}
-
- Set Price Alarm +
+ Login to set a price alarm +
+
+ +
Set Price Alarm
diff --git a/Frontend/src/app/components/product-details/product-details.component.ts b/Frontend/src/app/components/product-details/product-details.component.ts index 54b9c00..e7588c2 100644 --- a/Frontend/src/app/components/product-details/product-details.component.ts +++ b/Frontend/src/app/components/product-details/product-details.component.ts @@ -34,6 +34,8 @@ export class ProductDetailsComponent implements OnInit { vendorMap = {}; @ViewChild('chart') chart: ChartComponent; public chartOptions: ChartOptions; + isLoggedIn: boolean; + price: any; constructor( private apiService: ApiService @@ -44,6 +46,9 @@ export class ProductDetailsComponent implements OnInit { this.getProduct(); this.getVendors(); this.getPrices(); + if (this.apiService.getSessionInfoFromLocalStorage().session_id != "") { + this.isLoggedIn = true; + } } getProduct(): void { @@ -117,4 +122,12 @@ export class ProductDetailsComponent implements OnInit { return Math.round(percentage); } + + setPriceAlarm() { + this.apiService.createPriceAlarms(this.productId, this.price*100).subscribe( + alarms => console.log(alarms) + ) + } + + } diff --git a/Frontend/src/app/components/product-list/product-list.component.html b/Frontend/src/app/components/product-list/product-list.component.html index 6f9a8e5..5c26ab9 100644 --- a/Frontend/src/app/components/product-list/product-list.component.html +++ b/Frontend/src/app/components/product-list/product-list.component.html @@ -1,6 +1,30 @@
No Products found!
+
+
+
+
+
+
+
{{product.name}}
+
+

{{product.short_description}}

+
+

+

+
+
+
+

${{pricesMap[product.product_id]?.price_in_cents/100}}

+
+
+
+
+
+
+
+ diff --git a/Frontend/src/app/components/product-list/product-list.component.ts b/Frontend/src/app/components/product-list/product-list.component.ts index 94bab8a..1f1bdd3 100644 --- a/Frontend/src/app/components/product-list/product-list.component.ts +++ b/Frontend/src/app/components/product-list/product-list.component.ts @@ -10,6 +10,7 @@ import {ActivatedRoute, Router} from '@angular/router'; }) export class ProductListComponent implements OnInit { products: Product[] = []; + pricesMap: any = {}; @Input() numberOfProducts: number; @Input() showProductPicture: boolean; @Input() searchQuery: string; @@ -53,15 +54,35 @@ export class ProductListComponent implements OnInit { } getProducts(): void { - this.apiService.getProducts().subscribe(products => this.products = products); + this.apiService.getProducts().subscribe(products => { + this.products = products; + this.getPrices(); + }); } + getPrices(): void { + this.products.forEach( + product => { + this.apiService.getLowestPrices(product.product_id).subscribe( + prices => { + this.pricesMap[product.product_id] = prices[prices.length - 1]; + } + ); + } + ); + } + + getSearchedProducts(): void { - this.apiService.getProductsByQuery(this.searchQuery).subscribe(products => this.products = products); + this.apiService.getProductsByQuery(this.searchQuery).subscribe(products => { + this.products = products; + this.getPrices(); + }); } - + clickedProduct(product: Product): void { this.router.navigate([('/product/' + product.product_id)]); } + } diff --git a/Frontend/src/app/components/profile/profile.component.css b/Frontend/src/app/components/profile/profile.component.css new file mode 100644 index 0000000..42605dc --- /dev/null +++ b/Frontend/src/app/components/profile/profile.component.css @@ -0,0 +1,21 @@ +.inf-content{ + border:1px solid #DDDDDD; + -webkit-border-radius:10px; + -moz-border-radius:10px; + border-radius:10px; + box-shadow: 7px 7px 7px rgba(0, 0, 0, 0.3); +} + +.header-in-page { + padding-top: calc(1rem + 20px); + padding-bottom: 1rem; +} + +table, th, td { + border: 1px solid black; +} + +.delete:hover { + cursor: pointer; + color: #0d5a4b; +} diff --git a/Frontend/src/app/components/profile/profile.component.html b/Frontend/src/app/components/profile/profile.component.html new file mode 100644 index 0000000..c08a7d9 --- /dev/null +++ b/Frontend/src/app/components/profile/profile.component.html @@ -0,0 +1,137 @@ +
+
+
+
+ +
    +
  • +
  • +
  • +
  • +
  • +
+
+
+ Information
+
+ + + + + + + + + + + + + + + + + + + + + +
+ + + Username + + + {{currentUser.username}} +
+ + + Role + + + User +
+ + + Email + + + {{currentUser.email}} +
+ + + created + + + {{currentUser.registration_date}} +
+
+
+
+
+
+
+ +
+
+
+ + + + + + + + + + + + + +
ProductPriceChangeDelete
+ {{productsMap[alarm.product_id]?.name}} + + {{alarm.defined_price/100}} + + + + +
+
+
+ diff --git a/Frontend/src/app/components/profile/profile.component.spec.ts b/Frontend/src/app/components/profile/profile.component.spec.ts new file mode 100644 index 0000000..e88012e --- /dev/null +++ b/Frontend/src/app/components/profile/profile.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ProfileComponent } from './profile.component'; + +describe('ProfileComponent', () => { + let component: ProfileComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ ProfileComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(ProfileComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/Frontend/src/app/components/profile/profile.component.ts b/Frontend/src/app/components/profile/profile.component.ts new file mode 100644 index 0000000..4e9402a --- /dev/null +++ b/Frontend/src/app/components/profile/profile.component.ts @@ -0,0 +1,58 @@ +import { Component, OnInit } from '@angular/core'; +import {ApiService} from "../../services/api.service"; + +@Component({ + selector: 'app-profile', + templateUrl: './profile.component.html', + styleUrls: ['./profile.component.css'] +}) +export class ProfileComponent implements OnInit { + + currentUser: any; + obj:any; + alarms: any []; + productsMap: any = {}; + + constructor(private api: ApiService ) { } + + ngOnInit(): void { + + this.api.getUserInfo().subscribe( + user=> { + this.currentUser = user + console.log(this.currentUser); + }, + ); + + this.getPriceAlarms(); + } + + getPriceAlarms(): void { + this.api.getPriceAlarms().subscribe( + alarms => { + this.alarms = alarms + this.getProductsByIds() + } + ) + } + + getProductsByIds(): void { + let productIds: number [] = []; + this.alarms.forEach( + alarm => {productIds.push(alarm.product_id)} + ); + this.api.getProductsByIds(productIds).subscribe( + products => { + products.forEach( + product => {this.productsMap[product.product_id] = product} + ) + } + ) + } + + delete(id:number): void { + this.api.deletePriceAlarm(id).subscribe( + res => window.location.reload() + ) + } +} diff --git a/Frontend/src/app/components/top-bar/top-bar.component.html b/Frontend/src/app/components/top-bar/top-bar.component.html index b8b6697..7cfece9 100644 --- a/Frontend/src/app/components/top-bar/top-bar.component.html +++ b/Frontend/src/app/components/top-bar/top-bar.component.html @@ -1,20 +1,22 @@