mirror of
https://github.com/Mueller-Patrick/Betterzon.git
synced 2024-11-22 14:23:57 +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 ' +
|
'PARTITION BY p.vendor_id ' +
|
||||||
'ORDER BY p.timestamp DESC) AS rk ' +
|
'ORDER BY p.timestamp DESC) AS rk ' +
|
||||||
'FROM prices p ' +
|
'FROM prices p ' +
|
||||||
'WHERE product_id = ?) ' +
|
'WHERE product_id = ? AND vendor_id != 1) ' +
|
||||||
'SELECT s.* ' +
|
'SELECT s.* ' +
|
||||||
'FROM summary s ' +
|
'FROM summary s ' +
|
||||||
'WHERE s.rk = 1 '), product);
|
'WHERE s.rk = 1 '), product);
|
||||||
} else if (type === 'lowest') {
|
} else if (type === 'lowest') {
|
||||||
// Used to get the lowest prices for this product over a period of time
|
// 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 {
|
} else {
|
||||||
// If no type is given, return all prices for this product
|
// 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) {
|
for (let row in rows) {
|
||||||
|
|
|
@ -5,16 +5,16 @@ import {NgModule} from '@angular/core';
|
||||||
import {AppComponent} from './app.component';
|
import {AppComponent} from './app.component';
|
||||||
import {AppRouting} from './app.routing';
|
import {AppRouting} from './app.routing';
|
||||||
import {ProductListComponent} from './components/product-list/product-list.component';
|
import {ProductListComponent} from './components/product-list/product-list.component';
|
||||||
import { LandingpageComponent } from './pages/landingpage/landingpage.component';
|
import {LandingpageComponent} from './pages/landingpage/landingpage.component';
|
||||||
import { ProductDetailPageComponent } from './pages/product-detail-page/product-detail-page.component';
|
import {ProductDetailPageComponent} from './pages/product-detail-page/product-detail-page.component';
|
||||||
import { FooterComponent } from './components/footer/footer.component';
|
import {FooterComponent} from './components/footer/footer.component';
|
||||||
import { ProductDetailsComponent } from './components/product-details/product-details.component';
|
import {ProductDetailsComponent} from './components/product-details/product-details.component';
|
||||||
import {NgApexchartsModule} from 'ng-apexcharts';
|
import {NgApexchartsModule} from 'ng-apexcharts';
|
||||||
import { ProductSearchPageComponent } from './pages/product-search-page/product-search-page.component';
|
import {ProductSearchPageComponent} from './pages/product-search-page/product-search-page.component';
|
||||||
import { HeaderComponent } from './components/header/header.component';
|
import {HeaderComponent} from './components/header/header.component';
|
||||||
import { NewestPricesListComponent } from './components/newest-prices-list/newest-prices-list.component';
|
import {NewestPricesListComponent} from './components/newest-prices-list/newest-prices-list.component';
|
||||||
import {FormsModule} from '@angular/forms';
|
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({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<img src="assets/images/Betterzon.svg" alt="Betterzon Logo" width="50px" (click)="clickedLogo()">
|
<img src="assets/images/Betterzon.svg" alt="Betterzon Logo" width="50px" (click)="clickedLogo()">
|
||||||
</div>
|
</div>
|
||||||
<div class="searchBox">
|
<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>
|
||||||
<div class="profileIcon">
|
<div class="profileIcon">
|
||||||
Profile
|
Profile
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import {Component, OnInit} from '@angular/core';
|
import {Component, Input, OnInit} from '@angular/core';
|
||||||
import {Router} from '@angular/router';
|
import {Router} from '@angular/router';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -8,6 +8,7 @@ import {Router} from '@angular/router';
|
||||||
})
|
})
|
||||||
export class HeaderComponent implements OnInit {
|
export class HeaderComponent implements OnInit {
|
||||||
searchInput: string;
|
searchInput: string;
|
||||||
|
@Input() showSearch: boolean;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private router: Router
|
private router: Router
|
||||||
|
@ -15,6 +16,9 @@ export class HeaderComponent implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
if (!this.showSearch) {
|
||||||
|
this.showSearch = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
clickedLogo(): void {
|
clickedLogo(): void {
|
||||||
|
|
|
@ -1,7 +1,25 @@
|
||||||
.priceList {
|
.priceList {
|
||||||
max-width: 50%;
|
margin: 2em;
|
||||||
margin: auto;
|
position: relative;
|
||||||
margin: auto;
|
}
|
||||||
align-content: center;
|
|
||||||
text-align: center;
|
.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">
|
<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>
|
</div>
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
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({
|
@Component({
|
||||||
selector: 'app-newest-prices-list',
|
selector: 'app-newest-prices-list',
|
||||||
|
@ -6,10 +9,37 @@ import { Component, OnInit } from '@angular/core';
|
||||||
styleUrls: ['./newest-prices-list.component.css']
|
styleUrls: ['./newest-prices-list.component.css']
|
||||||
})
|
})
|
||||||
export class NewestPricesListComponent implements OnInit {
|
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 {
|
.productImage {
|
||||||
max-width: 300px;
|
max-width: 300px;
|
||||||
max-height: 300px;
|
max-height: 300px;
|
||||||
display:block;
|
display: block;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
|
@ -57,14 +57,27 @@
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
padding: .25em;
|
padding: .25em;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
|
font-size: 1.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Best price div */
|
/* Best price container div */
|
||||||
.bestPrice {
|
.bestPriceContainer {
|
||||||
grid-area: bestPrice;
|
grid-area: bestPrice;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* best price div */
|
||||||
|
.bestPrice {
|
||||||
border-style: solid;
|
border-style: solid;
|
||||||
border-color: dimgrey;
|
border-color: dimgrey;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
padding: .25em;
|
padding: .25em;
|
||||||
margin: auto;
|
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"/>
|
<img class="productImage" src="https://www.mueller-patrick.tech/betterzon/images/{{product.image_guid}}.jpg"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="productTitle">
|
<div class="productTitle">
|
||||||
<b>{{product.name}}</b>
|
<b>{{product?.name}}</b>
|
||||||
</div>
|
</div>
|
||||||
<div class="priceChart">
|
<div class="priceChart">
|
||||||
<div style="text-align:center">
|
<div style="text-align:center">
|
||||||
|
@ -17,13 +17,20 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="productDescription">
|
<div class="productDescription">
|
||||||
<div>
|
<div>
|
||||||
{{product.short_description}}
|
{{product?.short_description}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="priceAlarm">
|
<div class="priceAlarm">
|
||||||
Set Price Alarm
|
Set Price Alarm
|
||||||
</div>
|
</div>
|
||||||
|
<div class="bestPriceContainer">
|
||||||
<div class="bestPrice">
|
<div class="bestPrice">
|
||||||
5€
|
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>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -8,6 +8,8 @@ import {
|
||||||
ApexXAxis,
|
ApexXAxis,
|
||||||
ApexTitleSubtitle, ApexStroke
|
ApexTitleSubtitle, ApexStroke
|
||||||
} from 'ng-apexcharts';
|
} from 'ng-apexcharts';
|
||||||
|
import {Price} from '../../models/price';
|
||||||
|
import {Vendor} from '../../models/vendor';
|
||||||
|
|
||||||
export type ChartOptions = {
|
export type ChartOptions = {
|
||||||
series: ApexAxisChartSeries;
|
series: ApexAxisChartSeries;
|
||||||
|
@ -25,6 +27,11 @@ export type ChartOptions = {
|
||||||
export class ProductDetailsComponent implements OnInit {
|
export class ProductDetailsComponent implements OnInit {
|
||||||
@Input() productId: number;
|
@Input() productId: number;
|
||||||
product: Product;
|
product: Product;
|
||||||
|
lowestPrices: Price[];
|
||||||
|
currentlyLowestPrice: Price;
|
||||||
|
currentAmazonPrice: Price;
|
||||||
|
vendors: Vendor[] = [];
|
||||||
|
vendorMap = {};
|
||||||
@ViewChild('chart') chart: ChartComponent;
|
@ViewChild('chart') chart: ChartComponent;
|
||||||
public chartOptions: ChartOptions;
|
public chartOptions: ChartOptions;
|
||||||
|
|
||||||
|
@ -35,19 +42,53 @@ export class ProductDetailsComponent implements OnInit {
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.getProduct();
|
this.getProduct();
|
||||||
this.getChartData();
|
this.getVendors();
|
||||||
|
this.getPrices();
|
||||||
}
|
}
|
||||||
|
|
||||||
getProduct(): void {
|
getProduct(): void {
|
||||||
this.apiService.getProduct(this.productId).subscribe(product => this.product = product);
|
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 {
|
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 = {
|
this.chartOptions = {
|
||||||
series: [
|
series: [
|
||||||
{
|
{
|
||||||
name: 'Lowest Price',
|
name: 'Lowest Price',
|
||||||
data: [1061.20, 1060, 1070, 1040, 1061.20, 1061, 1100, 1070, 1061.20]
|
data: prices
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
chart: {
|
chart: {
|
||||||
|
@ -58,7 +99,7 @@ export class ProductDetailsComponent implements OnInit {
|
||||||
text: 'Lowest price'
|
text: 'Lowest price'
|
||||||
},
|
},
|
||||||
xaxis: {
|
xaxis: {
|
||||||
categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep']
|
categories: categs
|
||||||
},
|
},
|
||||||
stroke: {
|
stroke: {
|
||||||
curve: 'stepline'
|
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 {
|
.productImage {
|
||||||
max-width: 50px;
|
max-width: 50px;
|
||||||
max-height: 50px;
|
max-height: 50px;
|
||||||
display:block;
|
display: block;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
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-top: .5em;
|
||||||
margin-bottom: .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">
|
<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>
|
</div>
|
||||||
<app-footer></app-footer>
|
<app-footer></app-footer>
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { Component, OnInit } from '@angular/core';
|
import {Component, OnInit} from '@angular/core';
|
||||||
|
import {Router} from '@angular/router';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-landingpage',
|
selector: 'app-landingpage',
|
||||||
|
@ -6,10 +7,23 @@ import { Component, OnInit } from '@angular/core';
|
||||||
styleUrls: ['./landingpage.component.css']
|
styleUrls: ['./landingpage.component.css']
|
||||||
})
|
})
|
||||||
export class LandingpageComponent implements OnInit {
|
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">
|
<div id="mainComponents">
|
||||||
<app-product-details [productId]="productId"></app-product-details>
|
<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>
|
</div>
|
||||||
<app-footer></app-footer>
|
<app-footer></app-footer>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<app-header></app-header>
|
<app-header [showSearch]="true"></app-header>
|
||||||
<div id="mainComponents">
|
<div id="mainComponents">
|
||||||
<app-product-list numberOfProducts="20" [showProductPicture]="true" searchQuery="{{searchTerm}}"
|
<app-product-list numberOfProducts="20" [showProductPicture]="true" searchQuery="{{searchTerm}}"
|
||||||
type="search"></app-product-list>
|
type="search"></app-product-list>
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import {Injectable} from '@angular/core';
|
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 process from 'process';
|
||||||
import {Product} from '../models/product';
|
import {Product} from '../models/product';
|
||||||
import {Price} from '../models/price';
|
import {Price} from '../models/price';
|
||||||
import {Observable, of} from 'rxjs';
|
import {Observable, of} from 'rxjs';
|
||||||
|
import {Vendor} from '../models/vendor';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
|
@ -46,10 +47,55 @@ export class ApiService {
|
||||||
getPrices(): Observable<Price[]> {
|
getPrices(): Observable<Price[]> {
|
||||||
try {
|
try {
|
||||||
const prices = this.http.get<Price[]>((this.apiUrl + '/prices'));
|
const prices = this.http.get<Price[]>((this.apiUrl + '/prices'));
|
||||||
console.log(prices);
|
|
||||||
return prices;
|
return prices;
|
||||||
} catch (exception) {
|
} catch (exception) {
|
||||||
process.stderr.write(`ERROR received from ${this.apiUrl}: ${exception}\n`);
|
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