mirror of
				https://github.com/Mueller-Patrick/Betterzon.git
				synced 2025-10-31 08:45:48 +00:00 
			
		
		
		
	BETTERZON-25: Finishing prototype of UC
This commit is contained in:
		
							parent
							
								
									6338060b78
								
							
						
					
					
						commit
						31423c630a
					
				|  | @ -123,16 +123,16 @@ export const findByType = async (product: string, type: string): Promise<Prices> | |||
|                 'PARTITION BY p.vendor_id ' + | ||||
|                 'ORDER BY p.timestamp DESC) AS rk ' + | ||||
|                 'FROM prices p ' + | ||||
|                 'WHERE product_id = ?) ' + | ||||
|                 'WHERE product_id = ? AND vendor_id != 1) ' + | ||||
|                 'SELECT s.* ' + | ||||
|                 'FROM summary s ' + | ||||
|                 'WHERE s.rk = 1 '), product); | ||||
|         } else if (type === 'lowest') { | ||||
|             // Used to get the lowest prices for this product over a period of time
 | ||||
|             rows = await conn.query('SELECT price_id, product_id, vendor_id, MIN(price_in_cents) as price_in_cents, timestamp FROM prices WHERE product_id = ? GROUP BY DAY(timestamp) ORDER BY timestamp', product); | ||||
|             rows = await conn.query('SELECT price_id, product_id, vendor_id, MIN(price_in_cents) as price_in_cents, timestamp FROM prices WHERE product_id = ? AND vendor_id != 1 GROUP BY DAY(timestamp) ORDER BY timestamp', product); | ||||
|         } else { | ||||
|             // If no type is given, return all prices for this product
 | ||||
|             rows = await conn.query('SELECT price_id, product_id, vendor_id, price_in_cents, timestamp FROM prices WHERE product_id = ?', product); | ||||
|             rows = await conn.query('SELECT price_id, product_id, vendor_id, price_in_cents, timestamp FROM prices WHERE product_id = ? AND vendor_id != 1', product); | ||||
|         } | ||||
| 
 | ||||
|         for (let row in rows) { | ||||
|  |  | |||
|  | @ -5,16 +5,16 @@ import {NgModule} from '@angular/core'; | |||
| import {AppComponent} from './app.component'; | ||||
| import {AppRouting} from './app.routing'; | ||||
| import {ProductListComponent} from './components/product-list/product-list.component'; | ||||
| import { LandingpageComponent } from './pages/landingpage/landingpage.component'; | ||||
| import { ProductDetailPageComponent } from './pages/product-detail-page/product-detail-page.component'; | ||||
| import { FooterComponent } from './components/footer/footer.component'; | ||||
| import { ProductDetailsComponent } from './components/product-details/product-details.component'; | ||||
| import {LandingpageComponent} from './pages/landingpage/landingpage.component'; | ||||
| import {ProductDetailPageComponent} from './pages/product-detail-page/product-detail-page.component'; | ||||
| import {FooterComponent} from './components/footer/footer.component'; | ||||
| import {ProductDetailsComponent} from './components/product-details/product-details.component'; | ||||
| import {NgApexchartsModule} from 'ng-apexcharts'; | ||||
| import { ProductSearchPageComponent } from './pages/product-search-page/product-search-page.component'; | ||||
| import { HeaderComponent } from './components/header/header.component'; | ||||
| import { NewestPricesListComponent } from './components/newest-prices-list/newest-prices-list.component'; | ||||
| import {ProductSearchPageComponent} from './pages/product-search-page/product-search-page.component'; | ||||
| import {HeaderComponent} from './components/header/header.component'; | ||||
| import {NewestPricesListComponent} from './components/newest-prices-list/newest-prices-list.component'; | ||||
| import {FormsModule} from '@angular/forms'; | ||||
| import { PageNotFoundPageComponent } from './pages/page-not-found-page/page-not-found-page.component'; | ||||
| import {PageNotFoundPageComponent} from './pages/page-not-found-page/page-not-found-page.component'; | ||||
| 
 | ||||
| @NgModule({ | ||||
|     declarations: [ | ||||
|  |  | |||
|  | @ -5,7 +5,7 @@ | |||
|             <img src="assets/images/Betterzon.svg" alt="Betterzon Logo" width="50px" (click)="clickedLogo()"> | ||||
|         </div> | ||||
|         <div class="searchBox"> | ||||
|             <input type="text" [(ngModel)]="searchInput" placeholder="Search" (keyup.enter)="startedSearch()"> | ||||
|             <input *ngIf="showSearch===true" type="text" [(ngModel)]="searchInput" placeholder="Search" (keyup.enter)="startedSearch()"> | ||||
|         </div> | ||||
|         <div class="profileIcon"> | ||||
|             Profile | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| import {Component, OnInit} from '@angular/core'; | ||||
| import {Component, Input, OnInit} from '@angular/core'; | ||||
| import {Router} from '@angular/router'; | ||||
| 
 | ||||
| @Component({ | ||||
|  | @ -8,6 +8,7 @@ import {Router} from '@angular/router'; | |||
| }) | ||||
| export class HeaderComponent implements OnInit { | ||||
|     searchInput: string; | ||||
|     @Input() showSearch: boolean; | ||||
| 
 | ||||
|     constructor( | ||||
|         private router: Router | ||||
|  | @ -15,6 +16,9 @@ export class HeaderComponent implements OnInit { | |||
|     } | ||||
| 
 | ||||
|     ngOnInit(): void { | ||||
|         if (!this.showSearch) { | ||||
|             this.showSearch = false; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     clickedLogo(): void { | ||||
|  |  | |||
|  | @ -1,7 +1,25 @@ | |||
| .priceList { | ||||
|     max-width: 50%; | ||||
|     margin: auto; | ||||
|     margin: auto; | ||||
|     align-content: center; | ||||
|     text-align: center; | ||||
|     margin: 2em; | ||||
|     position: relative; | ||||
| } | ||||
| 
 | ||||
| .priceList table { | ||||
|     position: relative; | ||||
|     margin: auto; | ||||
|     font-family: Arial, Helvetica, sans-serif; | ||||
|     border-collapse: collapse; | ||||
|     width: 80%; | ||||
| } | ||||
| 
 | ||||
| .priceList table td, .priceList table th { | ||||
|     border: 1px solid #ddd; | ||||
|     padding: 8px; | ||||
| } | ||||
| 
 | ||||
| .priceList table tr:nth-child(even) { | ||||
|     background-color: #f2f2f2; | ||||
| } | ||||
| 
 | ||||
| .priceList table tr:hover { | ||||
|     background-color: #ddd; | ||||
| } | ||||
|  |  | |||
|  | @ -1,3 +1,14 @@ | |||
| <div class="priceList"> | ||||
|     PriceList | ||||
|     <table> | ||||
|         <tr> | ||||
|             <th>Vendor</th> | ||||
|             <th>Current price</th> | ||||
|             <th>Visit</th> | ||||
|         </tr> | ||||
|         <tr *ngFor="let price of prices"> | ||||
|             <td>{{vendorMap[price.vendor_id]?.name}}</td> | ||||
|             <td>{{price.price_in_cents / 100}}€</td> | ||||
|             <td><a href="https://www.amazon.com">Visit Shop</a></td> | ||||
|         </tr> | ||||
|     </table> | ||||
| </div> | ||||
|  |  | |||
|  | @ -1,15 +1,45 @@ | |||
| import { Component, OnInit } from '@angular/core'; | ||||
| import {Component, Input, OnInit} from '@angular/core'; | ||||
| import {Price} from '../../models/price'; | ||||
| import {Vendor} from '../../models/vendor'; | ||||
| import {ApiService} from '../../services/api.service'; | ||||
| 
 | ||||
| @Component({ | ||||
|   selector: 'app-newest-prices-list', | ||||
|   templateUrl: './newest-prices-list.component.html', | ||||
|   styleUrls: ['./newest-prices-list.component.css'] | ||||
|     selector: 'app-newest-prices-list', | ||||
|     templateUrl: './newest-prices-list.component.html', | ||||
|     styleUrls: ['./newest-prices-list.component.css'] | ||||
| }) | ||||
| export class NewestPricesListComponent implements OnInit { | ||||
|     @Input() productId: number; | ||||
|     prices: Price[] = []; | ||||
|     vendors: Vendor[] = []; | ||||
|     vendorMap = {}; | ||||
| 
 | ||||
|   constructor() { } | ||||
|     constructor( | ||||
|         private apiService: ApiService | ||||
|     ) { | ||||
|     } | ||||
| 
 | ||||
|   ngOnInit(): void { | ||||
|   } | ||||
|     ngOnInit(): void { | ||||
|         this.getVendors(); | ||||
|         this.getPrices(); | ||||
|     } | ||||
| 
 | ||||
|     getPrices(): void { | ||||
|         // Lowest prices
 | ||||
|         this.apiService.getCurrentPricePerVendor(this.productId).subscribe( | ||||
|             prices => { | ||||
|                 this.prices = prices; | ||||
|             }); | ||||
|     } | ||||
| 
 | ||||
|     getVendors(): void { | ||||
|         this.apiService.getVendors().subscribe(vendors => { | ||||
|             this.vendors = vendors; | ||||
| 
 | ||||
|             this.vendors.forEach(vendor => { | ||||
|                 this.vendorMap[vendor.vendor_id] = vendor; | ||||
|             }); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -21,7 +21,7 @@ | |||
| .productImage { | ||||
|     max-width: 300px; | ||||
|     max-height: 300px; | ||||
|     display:block; | ||||
|     display: block; | ||||
|     margin: auto; | ||||
|     position: absolute; | ||||
|     top: 0; | ||||
|  | @ -57,14 +57,27 @@ | |||
|     border-radius: 5px; | ||||
|     padding: .25em; | ||||
|     margin: auto; | ||||
|     font-size: 1.5em; | ||||
| } | ||||
| 
 | ||||
| /* Best price div */ | ||||
| .bestPrice { | ||||
| /* Best price container div */ | ||||
| .bestPriceContainer { | ||||
|     grid-area: bestPrice; | ||||
| } | ||||
| 
 | ||||
| /* best price div */ | ||||
| .bestPrice { | ||||
|     border-style: solid; | ||||
|     border-color: dimgrey; | ||||
|     border-radius: 5px; | ||||
|     padding: .25em; | ||||
|     margin: auto; | ||||
|     text-align: center; | ||||
|     font-size: 1.5em; | ||||
| } | ||||
| 
 | ||||
| /* amazon price div */ | ||||
| .amazonPrice { | ||||
|     margin-top: .5em; | ||||
|     text-align: center; | ||||
| } | ||||
|  |  | |||
|  | @ -3,7 +3,7 @@ | |||
|         <img class="productImage" src="https://www.mueller-patrick.tech/betterzon/images/{{product.image_guid}}.jpg"/> | ||||
|     </div> | ||||
|     <div class="productTitle"> | ||||
|         <b>{{product.name}}</b> | ||||
|         <b>{{product?.name}}</b> | ||||
|     </div> | ||||
|     <div class="priceChart"> | ||||
|         <div style="text-align:center"> | ||||
|  | @ -17,13 +17,20 @@ | |||
|     </div> | ||||
|     <div class="productDescription"> | ||||
|         <div> | ||||
|             {{product.short_description}} | ||||
|             {{product?.short_description}} | ||||
|         </div> | ||||
|     </div> | ||||
|     <div class="priceAlarm"> | ||||
|         Set Price Alarm | ||||
|     </div> | ||||
|     <div class="bestPrice"> | ||||
|         5€ | ||||
|     <div class="bestPriceContainer"> | ||||
|         <div class="bestPrice"> | ||||
|             Best price: {{currentlyLowestPrice?.price_in_cents / 100}}€ at | ||||
|             vendor {{vendorMap[currentlyLowestPrice.vendor_id]?.name}}! | ||||
|         </div> | ||||
|         <div class="amazonPrice"> | ||||
|             Amazon-price: {{currentAmazonPrice?.price_in_cents / 100}}€ (<span | ||||
|             *ngIf="getAmazonPriceDifference()>0">+</span>{{getAmazonPriceDifference()}}%) | ||||
|         </div> | ||||
|     </div> | ||||
| </div> | ||||
|  |  | |||
|  | @ -8,6 +8,8 @@ import { | |||
|     ApexXAxis, | ||||
|     ApexTitleSubtitle, ApexStroke | ||||
| } from 'ng-apexcharts'; | ||||
| import {Price} from '../../models/price'; | ||||
| import {Vendor} from '../../models/vendor'; | ||||
| 
 | ||||
| export type ChartOptions = { | ||||
|     series: ApexAxisChartSeries; | ||||
|  | @ -25,6 +27,11 @@ export type ChartOptions = { | |||
| export class ProductDetailsComponent implements OnInit { | ||||
|     @Input() productId: number; | ||||
|     product: Product; | ||||
|     lowestPrices: Price[]; | ||||
|     currentlyLowestPrice: Price; | ||||
|     currentAmazonPrice: Price; | ||||
|     vendors: Vendor[] = []; | ||||
|     vendorMap = {}; | ||||
|     @ViewChild('chart') chart: ChartComponent; | ||||
|     public chartOptions: ChartOptions; | ||||
| 
 | ||||
|  | @ -35,19 +42,53 @@ export class ProductDetailsComponent implements OnInit { | |||
| 
 | ||||
|     ngOnInit(): void { | ||||
|         this.getProduct(); | ||||
|         this.getChartData(); | ||||
|         this.getVendors(); | ||||
|         this.getPrices(); | ||||
|     } | ||||
| 
 | ||||
|     getProduct(): void { | ||||
|         this.apiService.getProduct(this.productId).subscribe(product => this.product = product); | ||||
|     } | ||||
| 
 | ||||
|     getPrices(): void { | ||||
|         // Lowest prices
 | ||||
|         this.apiService.getLowestPrices(this.productId).subscribe( | ||||
|             prices => { | ||||
|                 this.lowestPrices = prices; | ||||
|                 this.currentlyLowestPrice = prices[prices.length - 1]; | ||||
| 
 | ||||
|                 // Update charts
 | ||||
|                 this.getChartData(); | ||||
|             }); | ||||
| 
 | ||||
|         // Amazon price
 | ||||
|         this.apiService.getAmazonPrice(this.productId).subscribe(price => { | ||||
|             this.currentAmazonPrice = price[0]; | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     getVendors(): void { | ||||
|         this.apiService.getVendors().subscribe(vendors => { | ||||
|             this.vendors = vendors; | ||||
|             this.vendors.forEach(vendor => { | ||||
|                 this.vendorMap[vendor.vendor_id] = vendor; | ||||
|             }); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     getChartData(): void { | ||||
|         const prices = []; | ||||
|         const categs = []; | ||||
|         this.lowestPrices?.forEach(price => { | ||||
|             prices.push(price.price_in_cents / 100); | ||||
|             categs.push(new Date(price.timestamp).toDateString()); | ||||
|         }); | ||||
| 
 | ||||
|         this.chartOptions = { | ||||
|             series: [ | ||||
|                 { | ||||
|                     name: 'Lowest Price', | ||||
|                     data: [1061.20, 1060, 1070, 1040, 1061.20, 1061, 1100, 1070, 1061.20] | ||||
|                     data: prices | ||||
|                 } | ||||
|             ], | ||||
|             chart: { | ||||
|  | @ -58,7 +99,7 @@ export class ProductDetailsComponent implements OnInit { | |||
|                 text: 'Lowest price' | ||||
|             }, | ||||
|             xaxis: { | ||||
|                 categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep'] | ||||
|                 categories: categs | ||||
|             }, | ||||
|             stroke: { | ||||
|                 curve: 'stepline' | ||||
|  | @ -66,4 +107,16 @@ export class ProductDetailsComponent implements OnInit { | |||
|         }; | ||||
|     } | ||||
| 
 | ||||
|     getAmazonPriceDifference(): number { | ||||
|         const amazonPrice = this.currentAmazonPrice?.price_in_cents; | ||||
|         const lowestPrice = this.currentlyLowestPrice?.price_in_cents; | ||||
| 
 | ||||
|         const percentage = amazonPrice / lowestPrice; | ||||
| 
 | ||||
|         if (percentage < 1) { | ||||
|             return -Math.round(percentage); | ||||
|         } else { | ||||
|             return +Math.round(percentage); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -24,7 +24,7 @@ | |||
| .productImage { | ||||
|     max-width: 50px; | ||||
|     max-height: 50px; | ||||
|     display:block; | ||||
|     display: block; | ||||
|     margin: auto; | ||||
|     position: absolute; | ||||
|     top: 0; | ||||
|  |  | |||
							
								
								
									
										10
									
								
								Frontend/src/app/models/vendor.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								Frontend/src/app/models/vendor.ts
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,10 @@ | |||
| export interface Vendor { | ||||
|     vendor_id: number; | ||||
|     name: string; | ||||
|     streetname: string; | ||||
|     zip_code: string; | ||||
|     city: string; | ||||
|     country_code: string; | ||||
|     phone: string; | ||||
|     website: string; | ||||
| } | ||||
|  | @ -3,3 +3,48 @@ | |||
|     margin-top: .5em; | ||||
|     margin-bottom: .5em; | ||||
| } | ||||
| 
 | ||||
| #productListsContainer { | ||||
|     display: grid; | ||||
|     grid-template-areas: | ||||
|     'search search' | ||||
|     'popularSearches bestDeals'; | ||||
|     grid-template-columns: 50% 50%; | ||||
| } | ||||
| 
 | ||||
| #searchContainer { | ||||
|     position: relative; | ||||
|     grid-area: search; | ||||
|     height: 10em; | ||||
| } | ||||
| 
 | ||||
| #searchContainer input { | ||||
|     position: relative; | ||||
|     font-size: 1.5em; | ||||
|     padding: .25em; | ||||
|     display: block; | ||||
|     border: 1px solid #ccc; | ||||
|     border-radius: 4px; | ||||
|     box-sizing: border-box; | ||||
|     margin: auto; | ||||
|     -ms-transform: translateY(50%); | ||||
|     transform: translateY(2.5em); | ||||
| } | ||||
| 
 | ||||
| #popularSearchesList { | ||||
|     grid-area: popularSearches; | ||||
|     padding: .5em; | ||||
| } | ||||
| 
 | ||||
| #popularSearchesList h2 { | ||||
|     text-align: center; | ||||
| } | ||||
| 
 | ||||
| #bestDealsList { | ||||
|     grid-area: bestDeals; | ||||
|     padding: .5em; | ||||
| } | ||||
| 
 | ||||
| #bestDealsList h2 { | ||||
|     text-align: center; | ||||
| } | ||||
|  |  | |||
|  | @ -1,5 +1,18 @@ | |||
| <app-header></app-header> | ||||
| <app-header [showSearch]="false"></app-header> | ||||
| <div id="mainComponents"> | ||||
|     <app-product-list numberOfProducts="20" [showProductPicture]="true"></app-product-list> | ||||
|     <div id="searchContainer"> | ||||
|         <input type="text" [(ngModel)]="searchInput" placeholder="Search" (keyup.enter)="startedSearch()"> | ||||
|     </div> | ||||
|     <div id="productListsContainer"> | ||||
|         <div id="popularSearchesList"> | ||||
|             <h2>Popular Searches</h2> | ||||
|             <app-product-list numberOfProducts="3" [showProductPicture]="true" | ||||
|                               type="popularSearches"></app-product-list> | ||||
|         </div> | ||||
|         <div id="bestDealsList"> | ||||
|             <h2>Best Deals</h2> | ||||
|             <app-product-list numberOfProducts="3" [showProductPicture]="true" type="bestDeals"></app-product-list> | ||||
|         </div> | ||||
|     </div> | ||||
| </div> | ||||
| <app-footer></app-footer> | ||||
|  |  | |||
|  | @ -1,15 +1,29 @@ | |||
| import { Component, OnInit } from '@angular/core'; | ||||
| import {Component, OnInit} from '@angular/core'; | ||||
| import {Router} from '@angular/router'; | ||||
| 
 | ||||
| @Component({ | ||||
|   selector: 'app-landingpage', | ||||
|   templateUrl: './landingpage.component.html', | ||||
|   styleUrls: ['./landingpage.component.css'] | ||||
|     selector: 'app-landingpage', | ||||
|     templateUrl: './landingpage.component.html', | ||||
|     styleUrls: ['./landingpage.component.css'] | ||||
| }) | ||||
| export class LandingpageComponent implements OnInit { | ||||
|     searchInput: string; | ||||
| 
 | ||||
|   constructor() { } | ||||
|     constructor( | ||||
|         private router: Router | ||||
|     ) { | ||||
|     } | ||||
| 
 | ||||
|   ngOnInit(): void { | ||||
|   } | ||||
|     ngOnInit(): void { | ||||
|     } | ||||
| 
 | ||||
|     startedSearch(): void { | ||||
|         this.redirectTo('/search', {queryParams: {q: this.searchInput}}); | ||||
|     } | ||||
| 
 | ||||
|     redirectTo(uri: string, queryParams: object): void { | ||||
|         this.router.navigateByUrl('/', {skipLocationChange: true}).then(() => | ||||
|             this.router.navigate([uri], queryParams)); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -1,6 +1,6 @@ | |||
| <app-header></app-header> | ||||
| <app-header [showSearch]="true"></app-header> | ||||
| <div id="mainComponents"> | ||||
|     <app-product-details [productId]="productId"></app-product-details> | ||||
|     <app-newest-prices-list></app-newest-prices-list> | ||||
|     <app-newest-prices-list [productId]="productId"></app-newest-prices-list> | ||||
| </div> | ||||
| <app-footer></app-footer> | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| <app-header></app-header> | ||||
| <app-header [showSearch]="true"></app-header> | ||||
| <div id="mainComponents"> | ||||
|     <app-product-list numberOfProducts="20" [showProductPicture]="true" searchQuery="{{searchTerm}}" | ||||
|                       type="search"></app-product-list> | ||||
|  |  | |||
|  | @ -1,9 +1,10 @@ | |||
| import {Injectable} from '@angular/core'; | ||||
| import {HttpClient, HttpHeaders} from '@angular/common/http'; | ||||
| import {HttpClient, HttpHeaders, HttpParams} from '@angular/common/http'; | ||||
| import process from 'process'; | ||||
| import {Product} from '../models/product'; | ||||
| import {Price} from '../models/price'; | ||||
| import {Observable, of} from 'rxjs'; | ||||
| import {Vendor} from '../models/vendor'; | ||||
| 
 | ||||
| @Injectable({ | ||||
|     providedIn: 'root' | ||||
|  | @ -46,10 +47,55 @@ export class ApiService { | |||
|     getPrices(): Observable<Price[]> { | ||||
|         try { | ||||
|             const prices = this.http.get<Price[]>((this.apiUrl + '/prices')); | ||||
|             console.log(prices); | ||||
|             return prices; | ||||
|         } catch (exception) { | ||||
|             process.stderr.write(`ERROR received from ${this.apiUrl}: ${exception}\n`); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     getLowestPrices(productId): Observable<Price[]> { | ||||
|         try { | ||||
|             let params = new HttpParams(); | ||||
|             params = params.append('product', productId); | ||||
|             params = params.append('type', 'lowest'); | ||||
|             const prices = this.http.get<Price[]>((this.apiUrl + '/prices'), {params}); | ||||
|             return prices; | ||||
|         } catch (exception) { | ||||
|             process.stderr.write(`ERROR received from ${this.apiUrl}: ${exception}\n`); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     getAmazonPrice(productId): Observable<Price> { | ||||
|         try { | ||||
|             let params = new HttpParams(); | ||||
|             params = params.append('product', productId); | ||||
|             params = params.append('vendor', '1'); | ||||
|             params = params.append('type', 'newest'); | ||||
|             const price = this.http.get<Price>((this.apiUrl + '/prices'), {params}); | ||||
|             return price; | ||||
|         } catch (exception) { | ||||
|             process.stderr.write(`ERROR received from ${this.apiUrl}: ${exception}\n`); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     getCurrentPricePerVendor(productId): Observable<Price[]> { | ||||
|         try { | ||||
|             let params = new HttpParams(); | ||||
|             params = params.append('product', productId); | ||||
|             params = params.append('type', 'newest'); | ||||
|             const prices = this.http.get<Price[]>((this.apiUrl + '/prices'), {params}); | ||||
|             return prices; | ||||
|         } catch (exception) { | ||||
|             process.stderr.write(`ERROR received from ${this.apiUrl}: ${exception}\n`); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     getVendors(): Observable<Vendor[]> { | ||||
|         try { | ||||
|             const vendors = this.http.get<Vendor[]>((this.apiUrl + '/vendors')); | ||||
|             return vendors; | ||||
|         } catch (exception) { | ||||
|             process.stderr.write(`ERROR received from ${this.apiUrl}: ${exception}\n`); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	Block a user