mirror of
https://github.com/Mueller-Patrick/Betterzon.git
synced 2024-11-22 14:23:57 +00:00
BETTERZON-42: Restructuring, creating necessary components, design of Product detail component
This commit is contained in:
commit
e83b2d7511
92
Frontend/package-lock.json
generated
92
Frontend/package-lock.json
generated
|
@ -2260,6 +2260,19 @@
|
||||||
"picomatch": "^2.0.4"
|
"picomatch": "^2.0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"apexcharts": {
|
||||||
|
"version": "3.22.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/apexcharts/-/apexcharts-3.22.3.tgz",
|
||||||
|
"integrity": "sha512-ZRZWmAmSdyc+tFhHMZ10ZxbvSbomWe46izpi8yQj5cKLxuujw2XeXVQ0jxnPl9yE5Q7W2hAbDWStaouBN4mSuw==",
|
||||||
|
"requires": {
|
||||||
|
"svg.draggable.js": "^2.2.2",
|
||||||
|
"svg.easing.js": "^2.0.0",
|
||||||
|
"svg.filter.js": "^2.0.2",
|
||||||
|
"svg.pathmorphing.js": "^0.1.3",
|
||||||
|
"svg.resize.js": "^1.4.3",
|
||||||
|
"svg.select.js": "^3.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"app-root-path": {
|
"app-root-path": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-3.0.0.tgz",
|
||||||
|
@ -7844,6 +7857,21 @@
|
||||||
"resolved": "https://registry.npmjs.org/ng/-/ng-0.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/ng/-/ng-0.0.0.tgz",
|
||||||
"integrity": "sha512-HwR40IBJa1ZU+CIGyuy7vSCN3xFYlSRfw5eIwwKOdOMNNNIl8KhT6PXKmHuFEFYpfrbOMaCYtr4QOJ3gkkubcg=="
|
"integrity": "sha512-HwR40IBJa1ZU+CIGyuy7vSCN3xFYlSRfw5eIwwKOdOMNNNIl8KhT6PXKmHuFEFYpfrbOMaCYtr4QOJ3gkkubcg=="
|
||||||
},
|
},
|
||||||
|
"ng-apexcharts": {
|
||||||
|
"version": "1.5.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/ng-apexcharts/-/ng-apexcharts-1.5.6.tgz",
|
||||||
|
"integrity": "sha512-78vmZvrT9iqfZXE00+T8NTvR+EHV0wo4qqf0Zfu1/2KiwazCU9S5EROcmgqMQ1eCO7Sz4GiR19rLTMdtWL/WmQ==",
|
||||||
|
"requires": {
|
||||||
|
"tslib": "^1.10.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": {
|
||||||
|
"version": "1.14.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||||
|
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"nice-try": {
|
"nice-try": {
|
||||||
"version": "1.0.5",
|
"version": "1.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
|
||||||
|
@ -11950,6 +11978,70 @@
|
||||||
"has-flag": "^3.0.0"
|
"has-flag": "^3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"svg.draggable.js": {
|
||||||
|
"version": "2.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/svg.draggable.js/-/svg.draggable.js-2.2.2.tgz",
|
||||||
|
"integrity": "sha512-JzNHBc2fLQMzYCZ90KZHN2ohXL0BQJGQimK1kGk6AvSeibuKcIdDX9Kr0dT9+UJ5O8nYA0RB839Lhvk4CY4MZw==",
|
||||||
|
"requires": {
|
||||||
|
"svg.js": "^2.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"svg.easing.js": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/svg.easing.js/-/svg.easing.js-2.0.0.tgz",
|
||||||
|
"integrity": "sha1-iqmUawqOJ4V6XEChDrpAkeVpHxI=",
|
||||||
|
"requires": {
|
||||||
|
"svg.js": ">=2.3.x"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"svg.filter.js": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/svg.filter.js/-/svg.filter.js-2.0.2.tgz",
|
||||||
|
"integrity": "sha1-kQCOFROJ3ZIwd5/L5uLJo2LRwgM=",
|
||||||
|
"requires": {
|
||||||
|
"svg.js": "^2.2.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"svg.js": {
|
||||||
|
"version": "2.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/svg.js/-/svg.js-2.7.1.tgz",
|
||||||
|
"integrity": "sha512-ycbxpizEQktk3FYvn/8BH+6/EuWXg7ZpQREJvgacqn46gIddG24tNNe4Son6omdXCnSOaApnpZw6MPCBA1dODA=="
|
||||||
|
},
|
||||||
|
"svg.pathmorphing.js": {
|
||||||
|
"version": "0.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/svg.pathmorphing.js/-/svg.pathmorphing.js-0.1.3.tgz",
|
||||||
|
"integrity": "sha512-49HWI9X4XQR/JG1qXkSDV8xViuTLIWm/B/7YuQELV5KMOPtXjiwH4XPJvr/ghEDibmLQ9Oc22dpWpG0vUDDNww==",
|
||||||
|
"requires": {
|
||||||
|
"svg.js": "^2.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"svg.resize.js": {
|
||||||
|
"version": "1.4.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/svg.resize.js/-/svg.resize.js-1.4.3.tgz",
|
||||||
|
"integrity": "sha512-9k5sXJuPKp+mVzXNvxz7U0uC9oVMQrrf7cFsETznzUDDm0x8+77dtZkWdMfRlmbkEEYvUn9btKuZ3n41oNA+uw==",
|
||||||
|
"requires": {
|
||||||
|
"svg.js": "^2.6.5",
|
||||||
|
"svg.select.js": "^2.1.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"svg.select.js": {
|
||||||
|
"version": "2.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/svg.select.js/-/svg.select.js-2.1.2.tgz",
|
||||||
|
"integrity": "sha512-tH6ABEyJsAOVAhwcCjF8mw4crjXSI1aa7j2VQR8ZuJ37H2MBUbyeqYr5nEO7sSN3cy9AR9DUwNg0t/962HlDbQ==",
|
||||||
|
"requires": {
|
||||||
|
"svg.js": "^2.2.5"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"svg.select.js": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/svg.select.js/-/svg.select.js-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-h5IS/hKkuVCbKSieR9uQCj9w+zLHoPh+ce19bBYyqF53g6mnPB8sAtIbe1s9dh2S2fCmYX2xel1Ln3PJBbK4kw==",
|
||||||
|
"requires": {
|
||||||
|
"svg.js": "^2.6.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
"svgo": {
|
"svgo": {
|
||||||
"version": "1.3.2",
|
"version": "1.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz",
|
||||||
|
|
|
@ -20,7 +20,9 @@
|
||||||
"@angular/platform-browser": "^10.2.3",
|
"@angular/platform-browser": "^10.2.3",
|
||||||
"@angular/platform-browser-dynamic": "^10.2.3",
|
"@angular/platform-browser-dynamic": "^10.2.3",
|
||||||
"@angular/router": "^10.2.3",
|
"@angular/router": "^10.2.3",
|
||||||
|
"apexcharts": "^3.22.3",
|
||||||
"ng": "0.0.0",
|
"ng": "0.0.0",
|
||||||
|
"ng-apexcharts": "^1.5.6",
|
||||||
"rxjs": "~6.6.0",
|
"rxjs": "~6.6.0",
|
||||||
"tslib": "^2.0.3",
|
"tslib": "^2.0.3",
|
||||||
"zone.js": "~0.10.2"
|
"zone.js": "~0.10.2"
|
||||||
|
|
|
@ -5,10 +5,14 @@ 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 './components/landingpage/landingpage.component';
|
import { LandingpageComponent } from './pages/landingpage/landingpage.component';
|
||||||
import { ProductDetailPageComponent } from './components/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 { 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';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
|
@ -17,12 +21,16 @@ import { ProductDetailsComponent } from './components/product-details/product-de
|
||||||
LandingpageComponent,
|
LandingpageComponent,
|
||||||
ProductDetailPageComponent,
|
ProductDetailPageComponent,
|
||||||
FooterComponent,
|
FooterComponent,
|
||||||
ProductDetailsComponent
|
ProductDetailsComponent,
|
||||||
|
ProductSearchPageComponent,
|
||||||
|
HeaderComponent,
|
||||||
|
NewestPricesListComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule,
|
BrowserModule,
|
||||||
AppRouting,
|
AppRouting,
|
||||||
HttpClientModule
|
HttpClientModule,
|
||||||
|
NgApexchartsModule
|
||||||
],
|
],
|
||||||
providers: [],
|
providers: [],
|
||||||
bootstrap: [AppComponent]
|
bootstrap: [AppComponent]
|
||||||
|
|
|
@ -3,12 +3,14 @@ import {CommonModule} from '@angular/common';
|
||||||
import {RouterModule, Routes} from '@angular/router';
|
import {RouterModule, Routes} from '@angular/router';
|
||||||
import {AppComponent} from './app.component';
|
import {AppComponent} from './app.component';
|
||||||
import {ProductListComponent} from './components/product-list/product-list.component';
|
import {ProductListComponent} from './components/product-list/product-list.component';
|
||||||
import {LandingpageComponent} from './components/landingpage/landingpage.component';
|
import {LandingpageComponent} from './pages/landingpage/landingpage.component';
|
||||||
import {ProductDetailPageComponent} from './components/product-detail-page/product-detail-page.component';
|
import {ProductDetailPageComponent} from './pages/product-detail-page/product-detail-page.component';
|
||||||
|
import {ProductSearchPageComponent} from './pages/product-search-page/product-search-page.component';
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{path: '', component: LandingpageComponent},
|
{path: '', component: LandingpageComponent},
|
||||||
{path: 'product', component: ProductDetailPageComponent}
|
{path: 'search', component: ProductSearchPageComponent},
|
||||||
|
{path: 'product/:id', component: ProductDetailPageComponent}
|
||||||
];
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
|
1
Frontend/src/app/components/header/header.component.html
Normal file
1
Frontend/src/app/components/header/header.component.html
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<p>header works!</p>
|
25
Frontend/src/app/components/header/header.component.spec.ts
Normal file
25
Frontend/src/app/components/header/header.component.spec.ts
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { HeaderComponent } from './header.component';
|
||||||
|
|
||||||
|
describe('HeaderComponent', () => {
|
||||||
|
let component: HeaderComponent;
|
||||||
|
let fixture: ComponentFixture<HeaderComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ HeaderComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(HeaderComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
15
Frontend/src/app/components/header/header.component.ts
Normal file
15
Frontend/src/app/components/header/header.component.ts
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-header',
|
||||||
|
templateUrl: './header.component.html',
|
||||||
|
styleUrls: ['./header.component.css']
|
||||||
|
})
|
||||||
|
export class HeaderComponent implements OnInit {
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,2 +0,0 @@
|
||||||
<app-product-list numberOfProducts="20" showProductPicture="true"></app-product-list>
|
|
||||||
<app-footer></app-footer>
|
|
|
@ -0,0 +1 @@
|
||||||
|
<p>newest-prices-list works!</p>
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { NewestPricesListComponent } from './newest-prices-list.component';
|
||||||
|
|
||||||
|
describe('NewestPricesListComponent', () => {
|
||||||
|
let component: NewestPricesListComponent;
|
||||||
|
let fixture: ComponentFixture<NewestPricesListComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ NewestPricesListComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(NewestPricesListComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-newest-prices-list',
|
||||||
|
templateUrl: './newest-prices-list.component.html',
|
||||||
|
styleUrls: ['./newest-prices-list.component.css']
|
||||||
|
})
|
||||||
|
export class NewestPricesListComponent implements OnInit {
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,2 +0,0 @@
|
||||||
<app-product-details></app-product-details>
|
|
||||||
<app-footer></app-footer>
|
|
|
@ -1,15 +0,0 @@
|
||||||
import { Component, OnInit } from '@angular/core';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-product-detail-page',
|
|
||||||
templateUrl: './product-detail-page.component.html',
|
|
||||||
styleUrls: ['./product-detail-page.component.css']
|
|
||||||
})
|
|
||||||
export class ProductDetailPageComponent implements OnInit {
|
|
||||||
|
|
||||||
constructor() { }
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
/* Div that contains each product */
|
||||||
|
.productItem {
|
||||||
|
padding: .25em;
|
||||||
|
margin: auto;
|
||||||
|
margin-bottom: .5em;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 20% 50% 30%;
|
||||||
|
grid-template-areas:
|
||||||
|
'image title priceChart'
|
||||||
|
'image description priceChart'
|
||||||
|
'image priceAlarm bestPrice';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Image div */
|
||||||
|
.productImageContainer {
|
||||||
|
grid-area: image;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Product Image */
|
||||||
|
.productImage {
|
||||||
|
max-width: 300px;
|
||||||
|
max-height: 300px;
|
||||||
|
display:block;
|
||||||
|
margin: auto;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Title div */
|
||||||
|
.productTitle {
|
||||||
|
grid-area: title;
|
||||||
|
font-size: 2em;
|
||||||
|
font-family: sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Price div */
|
||||||
|
.priceChart {
|
||||||
|
grid-area: priceChart;
|
||||||
|
text-align: center;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Description div */
|
||||||
|
.productDescription {
|
||||||
|
grid-area: description;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Price alarm div */
|
||||||
|
.priceAlarm {
|
||||||
|
grid-area: priceAlarm;
|
||||||
|
border-style: solid;
|
||||||
|
border-color: dimgrey;
|
||||||
|
padding: .25em;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Best price div */
|
||||||
|
.bestPrice {
|
||||||
|
grid-area: bestPrice;
|
||||||
|
border-style: solid;
|
||||||
|
border-color: dimgrey;
|
||||||
|
padding: .25em;
|
||||||
|
margin: auto;
|
||||||
|
}
|
|
@ -1 +1,30 @@
|
||||||
<p>product-details works!</p>
|
<meta charset="UTF-8">
|
||||||
|
<div class="productItem">
|
||||||
|
<div class="productImageContainer">
|
||||||
|
<img class="productImage" src="https://www.mueller-patrick.tech/betterzon/images/{{product.image_guid}}.jpg"/>
|
||||||
|
</div>
|
||||||
|
<div class="productTitle">
|
||||||
|
<b>{{product.name}}</b>
|
||||||
|
</div>
|
||||||
|
<div class="priceChart">
|
||||||
|
<div style="text-align:center">
|
||||||
|
<apx-chart
|
||||||
|
[series]="chartOptions.series"
|
||||||
|
[chart]="chartOptions.chart"
|
||||||
|
[xaxis]="chartOptions.xaxis"
|
||||||
|
[title]="chartOptions.title"
|
||||||
|
></apx-chart>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="productDescription">
|
||||||
|
<div>
|
||||||
|
{{product.short_description}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="priceAlarm">
|
||||||
|
Set Price Alarm
|
||||||
|
</div>
|
||||||
|
<div class="bestPrice">
|
||||||
|
5€
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
|
@ -1,4 +1,21 @@
|
||||||
import { Component, OnInit } from '@angular/core';
|
import {Component, Input, OnInit, ViewChild} from '@angular/core';
|
||||||
|
import {Product} from '../../models/product';
|
||||||
|
import {ApiService} from '../../services/api.service';
|
||||||
|
import {
|
||||||
|
ChartComponent,
|
||||||
|
ApexAxisChartSeries,
|
||||||
|
ApexChart,
|
||||||
|
ApexXAxis,
|
||||||
|
ApexTitleSubtitle, ApexStroke
|
||||||
|
} from 'ng-apexcharts';
|
||||||
|
|
||||||
|
export type ChartOptions = {
|
||||||
|
series: ApexAxisChartSeries;
|
||||||
|
chart: ApexChart;
|
||||||
|
xaxis: ApexXAxis;
|
||||||
|
title: ApexTitleSubtitle;
|
||||||
|
stroke: ApexStroke;
|
||||||
|
};
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-product-details',
|
selector: 'app-product-details',
|
||||||
|
@ -6,10 +23,47 @@ import { Component, OnInit } from '@angular/core';
|
||||||
styleUrls: ['./product-details.component.css']
|
styleUrls: ['./product-details.component.css']
|
||||||
})
|
})
|
||||||
export class ProductDetailsComponent implements OnInit {
|
export class ProductDetailsComponent implements OnInit {
|
||||||
|
@Input() productId: number;
|
||||||
|
product: Product;
|
||||||
|
@ViewChild('chart') chart: ChartComponent;
|
||||||
|
public chartOptions: ChartOptions;
|
||||||
|
|
||||||
constructor() { }
|
constructor(
|
||||||
|
private apiService: ApiService
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
this.getProduct();
|
||||||
|
this.getChartData();
|
||||||
|
}
|
||||||
|
|
||||||
|
getProduct(): void {
|
||||||
|
this.apiService.getProduct(this.productId).subscribe(product => this.product = product);
|
||||||
|
}
|
||||||
|
|
||||||
|
getChartData(): void {
|
||||||
|
this.chartOptions = {
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: 'Lowest Price',
|
||||||
|
data: [1061.20, 1060, 1070, 1040, 1061.20, 1061, 1100, 1070, 1061.20]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
chart: {
|
||||||
|
height: 350,
|
||||||
|
type: 'area'
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
text: 'Lowest price'
|
||||||
|
},
|
||||||
|
xaxis: {
|
||||||
|
categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep']
|
||||||
|
},
|
||||||
|
stroke: {
|
||||||
|
curve: 'stepline'
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,55 @@
|
||||||
|
/* Div that contains each product */
|
||||||
.productItem {
|
.productItem {
|
||||||
border-style: solid;
|
border-style: solid;
|
||||||
border-color: dimgrey;
|
border-color: dimgrey;
|
||||||
border-radius: .5em;
|
border-radius: .5em;
|
||||||
padding: .25em;
|
padding: .25em;
|
||||||
|
margin: auto;
|
||||||
|
margin-bottom: .5em;
|
||||||
|
max-width: 50em;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 10% 80% 10%;
|
||||||
|
grid-template-areas:
|
||||||
|
'image title price'
|
||||||
|
'image description price';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Image div */
|
||||||
|
.productImageContainer {
|
||||||
|
grid-area: image;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Product Image */
|
||||||
|
.productImage {
|
||||||
|
max-width: 50px;
|
||||||
|
max-height: 50px;
|
||||||
|
display:block;
|
||||||
|
margin: auto;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Title div */
|
||||||
|
.productTitle {
|
||||||
|
grid-area: title;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Price div */
|
||||||
|
.productPrice {
|
||||||
|
grid-area: price;
|
||||||
|
text-align: center;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Price text */
|
||||||
|
.productPrice * {
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Description div */
|
||||||
|
.productDescription {
|
||||||
|
grid-area: description;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,20 @@
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<p class="productItem" *ngFor="let product of products" (click)="clickedProduct(product)">
|
<div class="productItem" *ngFor="let product of products" (click)="clickedProduct(product)">
|
||||||
{{product.name}}
|
<div class="productImageContainer" *ngIf="showProductPicture===true">
|
||||||
</p>
|
<img class="productImage" src="https://www.mueller-patrick.tech/betterzon/images/{{product.image_guid}}.jpg"/>
|
||||||
<div *ngIf="showProductPicture">
|
</div>
|
||||||
Test
|
<div class="productTitle">
|
||||||
|
<b>{{product.name}}</b>
|
||||||
|
</div>
|
||||||
|
<div class="productPrice">
|
||||||
|
5€
|
||||||
|
</div>
|
||||||
|
<div class="productDescription">
|
||||||
|
<div *ngIf="product.short_description.length > 300">
|
||||||
|
{{product.short_description.substring(0, 300) + "..."}}
|
||||||
|
</div>
|
||||||
|
<div *ngIf="product.short_description.length <= 300">
|
||||||
|
{{product.short_description}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -12,6 +12,7 @@ export class ProductListComponent implements OnInit {
|
||||||
products: Product[];
|
products: Product[];
|
||||||
@Input() numberOfProducts: number;
|
@Input() numberOfProducts: number;
|
||||||
@Input() showProductPicture: boolean;
|
@Input() showProductPicture: boolean;
|
||||||
|
type: string;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private apiService: ApiService,
|
private apiService: ApiService,
|
||||||
|
@ -28,6 +29,7 @@ export class ProductListComponent implements OnInit {
|
||||||
if (!this.showProductPicture) {
|
if (!this.showProductPicture) {
|
||||||
this.showProductPicture = false;
|
this.showProductPicture = false;
|
||||||
}
|
}
|
||||||
|
this.type = 'PLP';
|
||||||
}
|
}
|
||||||
|
|
||||||
getProducts(): void {
|
getProducts(): void {
|
||||||
|
@ -35,7 +37,7 @@ export class ProductListComponent implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
clickedProduct(product: Product): void {
|
clickedProduct(product: Product): void {
|
||||||
this.router.navigate([('/helloworld/' + product.product_id)]);
|
this.router.navigate([('/product/' + product.product_id)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
<app-header></app-header>
|
||||||
|
<app-product-list numberOfProducts="20" [showProductPicture]="true"></app-product-list>
|
||||||
|
<app-footer></app-footer>
|
|
@ -0,0 +1,3 @@
|
||||||
|
<app-header></app-header>
|
||||||
|
<app-product-details [productId]="productId"></app-product-details>
|
||||||
|
<app-footer></app-footer>
|
|
@ -0,0 +1,21 @@
|
||||||
|
import {Component, OnInit} from '@angular/core';
|
||||||
|
import {Router} from '@angular/router';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-product-detail-page',
|
||||||
|
templateUrl: './product-detail-page.component.html',
|
||||||
|
styleUrls: ['./product-detail-page.component.css']
|
||||||
|
})
|
||||||
|
export class ProductDetailPageComponent implements OnInit {
|
||||||
|
productId: string;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private router: Router
|
||||||
|
) {
|
||||||
|
this.productId = router.url.substr(9, router.url.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
<app-header></app-header>
|
||||||
|
<app-product-list numberOfProducts="20" [showProductPicture]="true"></app-product-list>
|
||||||
|
<app-footer></app-footer>
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { ProductSearchPageComponent } from './product-search-page.component';
|
||||||
|
|
||||||
|
describe('ProductSearchPageComponent', () => {
|
||||||
|
let component: ProductSearchPageComponent;
|
||||||
|
let fixture: ComponentFixture<ProductSearchPageComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ ProductSearchPageComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(ProductSearchPageComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,21 @@
|
||||||
|
import {Component, OnInit} from '@angular/core';
|
||||||
|
import {ActivatedRoute} from '@angular/router';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-product-search-page',
|
||||||
|
templateUrl: './product-search-page.component.html',
|
||||||
|
styleUrls: ['./product-search-page.component.css']
|
||||||
|
})
|
||||||
|
export class ProductSearchPageComponent implements OnInit {
|
||||||
|
searchTerm: string;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private route: ActivatedRoute
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.searchTerm = this.route.snapshot.queryParamMap.get('q');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -16,6 +16,16 @@ export class ApiService {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getProduct(id): Observable<Product> {
|
||||||
|
try {
|
||||||
|
const prod = this.http.get<Product>((this.apiUrl + '/products/' + id));
|
||||||
|
console.log(prod);
|
||||||
|
return prod;
|
||||||
|
} catch (exception) {
|
||||||
|
process.stderr.write(`ERROR received from ${this.apiUrl}: ${exception}\n`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
getProducts(): Observable<Product[]> {
|
getProducts(): Observable<Product[]> {
|
||||||
try {
|
try {
|
||||||
const prods = this.http.get<Product[]>((this.apiUrl + '/products'));
|
const prods = this.http.get<Product[]>((this.apiUrl + '/products'));
|
||||||
|
|
Loading…
Reference in New Issue
Block a user