Compare commits

...

37 Commits
main ... dev

Author SHA1 Message Date
Julian Tomczyk bd0b2dc230 Correction valeurs par défaut de la fourchette de prix 2022-03-01 13:48:52 +01:00
Julian Tomczyk 1f1c069bdd Correction demander pour le brief + ajout des infos rating + bouton reset 2022-03-01 11:55:28 +01:00
Julian Tomczyk f6601fcd9c résolution erreur merge 2022-01-19 13:38:48 +01:00
Julian 52cf48a5dd
Merge pull request #5 from Julian30520/romain
Romain
2022-01-19 13:35:25 +01:00
Julian 4ea850b638
Merge branch 'dev' into romain 2022-01-19 13:35:14 +01:00
Julian Tomczyk 822a367ebe modification zone cliquable des vignettes 2022-01-19 13:17:38 +01:00
HarmandI 8555ac38ec dernière mise en forme 2022-01-18 20:56:55 +01:00
HarmandI 48f5ee490c Mise en page de la carte detail 2022-01-18 20:52:41 +01:00
HarmandI 28aff74caf Carte détail grossière 2022-01-18 18:51:53 +01:00
HarmandI 0936d942e0 URL details isa + romain 2022-01-17 21:02:22 +01:00
HarmandI 4fbea6ac18 Merge branch 'romain le-plante into romain 2022-01-17 18:33:33 +01:00
HarmandI a24530e005 récupère les ID des produits dans la page détail 2022-01-17 18:20:39 +01:00
Romain 247071b04f Ajout module account + pages + routes 2022-01-17 12:16:38 +01:00
Julian 3272bd9f06
Merge pull request #4 from Julian30520/cecile
version finale branche cecile
2022-01-11 20:55:52 +01:00
Julian 60a12b709d
Merge branch 'dev' into cecile 2022-01-11 20:55:44 +01:00
Julian 03b15210c1
Merge pull request #3 from Julian30520/Isa
Isa Recherche par categorie
2022-01-11 20:45:40 +01:00
Julian 6fb1e4aa18
Merge branch 'dev' into Isa 2022-01-11 20:45:21 +01:00
Julian Tomczyk d81976a237 Ajuster filtre du haut et du click counter 2022-01-11 20:33:42 +01:00
Julian 9a5868dfc4
Merge pull request #2 from Julian30520/Julian
Julian
2022-01-11 20:27:23 +01:00
Julian 5b700ae7bd
Merge branch 'dev' into Julian 2022-01-11 20:23:48 +01:00
Julian Tomczyk 6e2598537a modification onApplyFilters 2022-01-11 20:13:29 +01:00
Julian30520 23746f21cd onapplyfilter method 2022-01-11 19:33:15 +01:00
Romain b81ebb7d89 Add routing(id) vers page Details 2022-01-11 17:38:35 +01:00
Romain f1d0af652b Routing(id) vers page Details 2022-01-11 17:38:04 +01:00
cecilesimplon93 898454fbd2 version finale branche cecile 2022-01-11 15:59:38 +01:00
HarmandI c22e8b7039 Isa Recherche par categorie 2022-01-11 15:59:31 +01:00
Julian30520 08d05a41d4 parseFloat 2022-01-11 15:58:12 +01:00
Julian30520 9d1507846b Affichage des données selon les avis sur la page d'accueil 2022-01-11 10:40:48 +01:00
Julian30520 ea2fe72b13 ajout listDataGlobal 2022-01-11 10:26:24 +01:00
Julian30520 f883a03581 package lock version change 2022-01-11 10:14:45 +01:00
Julian f966a69457
Merge pull request #1 from Julian30520/romain
Romain
2022-01-11 10:12:55 +01:00
Romain 4b18ed8b44 Add fonction Tri 2022-01-11 10:09:34 +01:00
Julian Tomczyk b97670ee9f maj list rate 2022-01-10 22:14:54 +01:00
Romain cf65a3a258 Commit Rating (Julian) 2022-01-10 17:29:39 +01:00
Julian Tomczyk 87824c5824 ajout onRatingFilter 2022-01-10 17:15:14 +01:00
Julian Tomczyk 996674410a ajout event emitter dans avis-bar 2022-01-10 15:45:09 +01:00
Julian Tomczyk bc93c272d4 Recup info des etoiles sous forme de nombre 2022-01-10 15:41:09 +01:00
60 changed files with 22273 additions and 6052 deletions

View File

@ -4,13 +4,15 @@ This project was generated with [Angular CLI](https://github.com/angular/angular
## Development server
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change
any of the source files.
Run `npm run api` for the api server. Reach to `http://localhost:3000/`
## Code scaffolding
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
Run `ng generate component component-name` to generate a new component. You can also
use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
## Build
@ -22,8 +24,10 @@ Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.
## Running end-to-end tests
Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities.
Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a
package that implements end-to-end testing capabilities.
## Further help
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.
To get more help on the Angular CLI use `ng help` or go check out
the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.

11814
db.json

File diff suppressed because it is too large Load Diff

View File

@ -28,8 +28,8 @@ module.exports = function (config) {
dir: require('path').join(__dirname, './coverage/la-belle-plante'),
subdir: '.',
reporters: [
{ type: 'html' },
{ type: 'text-summary' }
{type: 'html'},
{type: 'text-summary'}
]
},
reporters: ['progress', 'kjhtml'],

15249
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -33,6 +33,7 @@
"@types/node": "^12.11.1",
"@types/underscore": "^1.11.4",
"jasmine-core": "~3.10.0",
"json-server-auth": "^2.1.0",
"karma": "~6.3.0",
"karma-chrome-launcher": "~3.1.0",
"karma-coverage": "~2.0.3",

View File

@ -1,18 +1,27 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { PageAccueilComponent } from './pages/page-accueil/page-accueil.component';
import { PageDetailsComponent } from './pages/page-details/page-details.component';
import { PageNotFoundComponent } from './pages/page-not-found/page-not-found.component';
import {NgModule} from '@angular/core';
import {RouterModule, Routes} from '@angular/router';
import {PageAccueilComponent} from './pages/page-accueil/page-accueil.component';
import {PageDetailsComponent} from './pages/page-details/page-details.component';
import {PageNotFoundComponent} from './pages/page-not-found/page-not-found.component';
const routes: Routes = [
{ path: '', redirectTo: 'home', pathMatch: 'full' },
{ path: 'home', component: PageAccueilComponent },
{ path: 'details', component: PageDetailsComponent },
{ path: '**', component: PageNotFoundComponent }
{path: '', redirectTo: 'home', pathMatch: 'full'},
{
path: 'home', component: PageAccueilComponent
},
{path: 'details/:productId', component: PageDetailsComponent},
{
path: 'account',
loadChildren: () => import('./modules/account/account.module')
.then(m => m.AccountModule)
},
{path: '**', component: PageNotFoundComponent}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
export class AppRoutingModule {
}

View File

@ -1,6 +1,6 @@
import { TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { AppComponent } from './app.component';
import {TestBed} from '@angular/core/testing';
import {RouterTestingModule} from '@angular/router/testing';
import {AppComponent} from './app.component';
describe('AppComponent', () => {
beforeEach(async () => {

View File

@ -1,4 +1,4 @@
import { Component } from '@angular/core';
import {Component} from '@angular/core';
@Component({
selector: 'app-root',

View File

@ -1,17 +1,17 @@
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import {NgModule} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { NavBarComponent } from './components/nav-bar/nav-bar.component';
import { PageAccueilComponent } from './pages/page-accueil/page-accueil.component';
import { PageDetailsComponent } from './pages/page-details/page-details.component';
import { PageNotFoundComponent } from './pages/page-not-found/page-not-found.component';
import { FilterSideBarComponent } from './components/filter-side-bar/filter-side-bar.component';
import { CardPlanteComponent } from './components/card-plante/card-plante.component';
import { HttpClientModule } from '@angular/common/http';
import { IconComponent } from './components/icon/icon.component';
import { AvisBarComponent } from './components/avis-bar/avis-bar.component';
import {AppRoutingModule} from './app-routing.module';
import {AppComponent} from './app.component';
import {NavBarComponent} from './components/nav-bar/nav-bar.component';
import {PageAccueilComponent} from './pages/page-accueil/page-accueil.component';
import {PageDetailsComponent} from './pages/page-details/page-details.component';
import {PageNotFoundComponent} from './pages/page-not-found/page-not-found.component';
import {FilterSideBarComponent} from './components/filter-side-bar/filter-side-bar.component';
import {CardPlanteComponent} from './components/card-plante/card-plante.component';
import {HttpClientModule} from '@angular/common/http';
import {IconComponent} from './components/icon/icon.component';
import {AvisBarComponent} from './components/avis-bar/avis-bar.component';
@NgModule({
declarations: [
@ -28,9 +28,12 @@ import { AvisBarComponent } from './components/avis-bar/avis-bar.component';
imports: [
BrowserModule,
AppRoutingModule,
HttpClientModule
HttpClientModule,
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
export class AppModule {
}

View File

@ -1,9 +1,16 @@
<div (mouseleave)="onMouseLeave()">
<app-icon *ngFor="let star of starStates; let starIndex = index"
[iconName]="star.stateHoverUser ? 'star-fill' : 'star'"
[iconSize]="1.2"
[iconColor]="'#ffbf00'"
(mouseover)="onMouseOver(starIndex)"
(click)="onClickStar(starIndex)"
></app-icon>
<div (mouseover)="isOver = true" *ngIf="isOver === false">
<app-icon *ngFor="let star of starStates; let starIndex = index"
[iconName]="star.stateRatingProduct ? 'star-fill' : 'star'"
[iconSize]="1.2"
[iconColor]="'#ffbf00'"
></app-icon>
</div>
<div (mouseleave)="onMouseLeave()" *ngIf="isOver">
<app-icon *ngFor="let star of starStates; let starIndex = index"
[iconName]="star.stateHoverUser ? 'star-fill' : 'star'"
[iconSize]="1.2"
[iconColor]="'#ffbf00'"
(mouseover)="onMouseOver(starIndex)"
(click)="onClickStar(starIndex)"
></app-icon>
</div>

View File

@ -1,6 +1,6 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import {ComponentFixture, TestBed} from '@angular/core/testing';
import { AvisBarComponent } from './avis-bar.component';
import {AvisBarComponent} from './avis-bar.component';
describe('AvisBarComponent', () => {
let component: AvisBarComponent;
@ -8,9 +8,9 @@ describe('AvisBarComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ AvisBarComponent ]
declarations: [AvisBarComponent]
})
.compileComponents();
.compileComponents();
});
beforeEach(() => {

View File

@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core';
import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
@Component({
selector: 'app-avis-bar',
@ -6,28 +6,42 @@ import { Component, OnInit } from '@angular/core';
styleUrls: ['./avis-bar.component.scss']
})
export class AvisBarComponent implements OnInit {
starStates: {stateSelectedUser : boolean, stateHoverUser : boolean}[];
starStates: { stateSelectedUser: boolean, stateHoverUser: boolean, stateRatingProduct: boolean }[];
@Output() stateNumber = new EventEmitter
starStateNumber: number = 0;
@Input() ratingIndex: number = 0;
isOver: boolean;
constructor() {
this.starStates = [];
this.isOver = false;
for (let index = 0; index < 5; index++) {
this.starStates.push(
{
stateSelectedUser : false,
stateHoverUser : false
stateSelectedUser: false,
stateHoverUser: false,
stateRatingProduct: false
}
);
}
}
}
ngOnInit(): void {
for (let i = 0; i < 5; i++) {
if (i < this.ratingIndex) {
this.starStates[i].stateRatingProduct = true;
} else {
this.starStates[i].stateRatingProduct = false;
}
}
}
onMouseOver(index: number) {
console.log("star over", index);
for (let i = 0; i < this.starStates.length ; i++) {
if(i <= index) {
this.isOver = true;
for (let i = 0; i < this.starStates.length; i++) {
if (i <= index) {
this.starStates[i].stateHoverUser = true;
} else {
this.starStates[i].stateHoverUser = false;
@ -37,12 +51,14 @@ export class AvisBarComponent implements OnInit {
onMouseLeave() {
// this.starState = ['star', 'star', 'star', 'star', 'star'];
this.isOver = false;
const tempTab = [];
for (let index = 0; index < this.starStates.length; index++) {
tempTab.push(
{
stateSelectedUser : this.starStates[index].stateSelectedUser,
stateHoverUser : this.starStates[index].stateSelectedUser
stateSelectedUser: this.starStates[index].stateSelectedUser,
stateHoverUser: this.starStates[index].stateSelectedUser,
stateRatingProduct: this.starStates[index].stateRatingProduct
}
);
}
@ -50,13 +66,18 @@ export class AvisBarComponent implements OnInit {
}
onClickStar(starIndex: number) {
for (let i = 0; i < this.starStates.length ; i++) {
if(i <= starIndex) {
this.starStateNumber = 0;
for (let i = 0; i < this.starStates.length; i++) {
if (i <= starIndex) {
this.starStates[i].stateSelectedUser = true;
this.starStates[i].stateRatingProduct = true;
this.starStateNumber++;
} else {
this.starStates[i].stateSelectedUser = false;
this.starStates[i].stateRatingProduct = false;
}
}
//console.log(`Rating : ${this.starStateNumber}`);
this.stateNumber.emit(this.starStateNumber);
}
}

View File

@ -1,20 +1,21 @@
<div class="plant card mb-4" style="width: 14rem;">
<app-icon class="like"
<app-icon class="like"
[iconName]="'heart'"
[iconColor]="'#e35d6a'"
(click)="onClickLike()"></app-icon>
<img src="{{plant.product_url_picture}}" class="card-img-top" alt="Image de {{ plant.product_name }}">
<div class="card-body">
<h6 class="card-title">{{ plant.product_name }}</h6>
<div class="card-content">
<app-avis-bar></app-avis-bar>
</div>
<div class="d-flex flex-row align-items-end justify-content-between">
<div class="card-content">
{{ plant.product_unitprice_ati }} €
</div>
<a href="#" class="btn btn-success">Pour moi !</a>
</div>
<img src="{{plant.product_url_picture}}" class="card-img-top" alt="Image de {{ plant.product_name }}"
(click)="onGetId(plant.product_id)">
<div class="card-body">
<h6 class="card-title" (click)="onGetId(plant.product_id)">{{ plant.product_name }}</h6>
<div class="card-content">
<app-avis-bar [ratingIndex]="plant.product_rating"></app-avis-bar>
</div>
<div class="d-flex flex-row align-items-end justify-content-between">
<div class="card-content">
{{ plant.product_unitprice_ati }} €
</div>
<a href="#" class="btn btn-success">Pour moi !</a>
</div>
</div>
</div>

View File

@ -1,14 +1,15 @@
.plant {
min-height: 22rem;
.card-body {
display: flex;
flex-direction: column;
justify-content: space-between;
}
min-height: 22rem;
.card-body {
display: flex;
flex-direction: column;
justify-content: space-between;
}
}
.like {
position: absolute;
right: 0.7rem;
top: 0.5rem;
position: absolute;
right: 0.7rem;
top: 0.5rem;
}

View File

@ -1,6 +1,6 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import {ComponentFixture, TestBed} from '@angular/core/testing';
import { CardPlanteComponent } from './card-plante.component';
import {CardPlanteComponent} from './card-plante.component';
describe('CardPlanteComponent', () => {
let component: CardPlanteComponent;
@ -8,9 +8,9 @@ describe('CardPlanteComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ CardPlanteComponent ]
declarations: [CardPlanteComponent]
})
.compileComponents();
.compileComponents();
});
beforeEach(() => {

View File

@ -1,4 +1,5 @@
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
import {Router} from '@angular/router';
@Component({
@ -9,7 +10,10 @@ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
export class CardPlanteComponent implements OnInit {
@Input() plant: any;
@Output() clickLike = new EventEmitter();
constructor() { }
@Output() clickCardId = new EventEmitter();
constructor(private router: Router) {
}
ngOnInit(): void {
}
@ -19,4 +23,11 @@ export class CardPlanteComponent implements OnInit {
this.clickLike.emit();
}
onGetId(id: string) {
this.clickCardId.emit(id);
this.router.navigateByUrl('/details/' + id);
}
}
//http://localhost:3000/list_products?product_id=952438

View File

@ -1,44 +1,52 @@
<div class="custom-side-bar flex-shrink-0 bg-white border-end">
<div class="p-3">
<span class="fs-5 fw-semibold">Filtres</span>
</div>
<ul class="list-unstyled ps-0 border-top">
<div class="p-3">
<span class="fs-5 fw-semibold">Filtres</span>
<p class="mb-1 fs-5 fw-semibold">Catégories</p>
<div *ngFor="let category of listCategories; let indexCat = index" class="form-check">
<input class="form-check-input" type="checkbox" value="testcategory" id="checkBoxCategory{{indexCat}}"
(click)="onCheckCategory(category,$event)">
<label class="form-check-label" for="checkBoxCategory{{indexCat}}">
{{ category }}
</label>
</div>
<div *ngIf="listCategories.length == 0 ">
Aucune catégorie disponible
</div>
</div>
<ul class="list-unstyled ps-0 border-top">
<div class="p-3">
<p class="mb-1 fs-5 fw-semibold">Catégories</p>
<div *ngFor="let category of listCategories; let indexCat = index" class="form-check">
</ul>
<ul class="list-unstyled ps-0 border-top">
<div class="p-3">
<p class="mb-1 fs-5 fw-semibold">Prix</p>
<div class="d-flex justify-content-center">
<input #minNum id="numberMin" type="number" placeholder="min" class="me-2" style="width: 45%;">
<input #maxNum id="numberMax" type="number" placeholder="max" class="me-2" style="width: 45%;">
</div>
<input class="form-check-input" type="checkbox" value="testcategory" id="checkBoxCategory{{indexCat}}">
<div class="d-flex justify-content-center">
<button class="btn btn-success m-3" (click)="onSendValues(minNum, maxNum)">Valider</button>
</div>
</div>
</ul>
<ul class="list-unstyled ps-0 border-top">
<div class="p-3">
<p class="mb-1 fs-5 fw-semibold">Avis</p>
<label class="form-check-label" for="checkBoxCategory{{indexCat}}">
{{ category }}
</label>
</div>
<div *ngIf="listCategories.length == 0 ">S
Aucune catégorie disponible
</div>
</div>
</ul>
<ul class="list-unstyled ps-0 border-top">
<div class="p-3">
<p class="mb-1 fs-5 fw-semibold">Prix</p>
<div class="d-flex justify-content-center">
<input id="number" type="number" placeholder="min" min=0 value="" class="me-2" style="width: 45%;">
<input id="number" type="number" placeholder="max" value="" class="me-2" style="width: 45%;">
</div>
<div class="d-flex justify-content-center">
<a href="#" class="btn btn-success m-3">Valider</a>
</div>
</div>
</ul>
<ul class="list-unstyled ps-0 border-top">
<div class="p-3">
<p class="mb-1 fs-5 fw-semibold">Avis</p>
<div class="flex-column justify-content-start">
<app-avis-bar></app-avis-bar>
<a href="#" class="btn btn-success me-2">Valider</a>
</div>
</div>
</ul>
<div class="flex-column justify-content-start">
<app-avis-bar (stateNumber)="onStateNumberChange($event)"></app-avis-bar>
<button class="btn btn-success me-2" (click)="onSendRating()">Valider</button>
</div>
</div>
</ul>
<ul class="list-unstyled ps-0 border-top">
<div class="p-3">
<div class="flex-column justify-content-start">
<button class="btn btn-success me-2" (click)="onReset()">Réinitialiser</button>
</div>
</div>
</ul>
</div>

View File

@ -1,5 +1,5 @@
.custom-side-bar {
min-height: calc(100vh - 54px);
width: 280px;
height: 100%;
min-height: calc(100vh - 54px);
width: 280px;
height: 100%;
}

View File

@ -1,6 +1,6 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import {ComponentFixture, TestBed} from '@angular/core/testing';
import { FilterSideBarComponent } from './filter-side-bar.component';
import {FilterSideBarComponent} from './filter-side-bar.component';
describe('FilterSideBarComponent', () => {
let component: FilterSideBarComponent;
@ -8,9 +8,9 @@ describe('FilterSideBarComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ FilterSideBarComponent ]
declarations: [FilterSideBarComponent]
})
.compileComponents();
.compileComponents();
});
beforeEach(() => {

View File

@ -1,4 +1,4 @@
import { Component, Input, OnInit } from '@angular/core';
import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
@Component({
selector: 'app-filter-side-bar',
@ -7,12 +7,75 @@ import { Component, Input, OnInit } from '@angular/core';
})
export class FilterSideBarComponent implements OnInit {
@Input() listCategories: string[];
@Output() checkCategory = new EventEmitter();
@Output() stateNumber = new EventEmitter();
@Output() rangeNumber = new EventEmitter();
@Output() reset = new EventEmitter();
filterStateNumber: number = 0;
public selectedCategory: string[];
public rangeArray: number[];
public minPrice : any;
public maxPrice : any;
constructor() {
this.listCategories = [];
this.selectedCategory = [];
this.minPrice = 0;
this.maxPrice = 1000;
this.rangeArray = [];
}
ngOnInit(): void {
}
onCheckCategory(category: string, event: any) {
console.log(event)
if (event.target.checked == true) {
//console.log("true")
this.selectedCategory.push(category);
}
if (event.target.checked == false) {
//console.log("false")
this.selectedCategory = this.selectedCategory.filter(product => product !== category);
}
this.checkCategory.emit(this.selectedCategory);
//console.log("romain" , this.selectedCategory)
}
onStateNumberChange(stateNumber: number): void {
this.filterStateNumber = stateNumber;
}
onSendRating():void {
this.stateNumber.emit(this.filterStateNumber);
}
onSendValues(minNum: any, maxNum: any): void {
if (minNum.value == "") {
if (maxNum.value == "") {
this.rangeArray = [parseFloat(this.minPrice), parseFloat(this.maxPrice)];
this.rangeNumber.emit(this.rangeArray);
} else {
this.rangeArray = [parseFloat(this.minPrice), parseFloat(maxNum.value)];
this.rangeNumber.emit(this.rangeArray)
}
} else {
if (maxNum.value == "") {
this.rangeArray = [parseFloat(minNum.value), parseFloat(this.maxPrice)];
this.rangeNumber.emit(this.rangeArray);
} else {
this.rangeArray = [parseFloat(minNum.value), parseFloat(maxNum.value)];
this.rangeNumber.emit(this.rangeArray);
}
}
}
onReset(): void {
this.reset.emit();
}
}

View File

@ -1,2 +1,2 @@
<i class="bi-{{iconName}}"
[ngStyle]="{'font-size.rem': iconSize, 'color': iconColor}"></i>
[ngStyle]="{'font-size.rem': iconSize, 'color': iconColor}"></i>

View File

@ -1,3 +1,3 @@
i {
cursor: pointer;
cursor: pointer;
}

View File

@ -1,6 +1,6 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import {ComponentFixture, TestBed} from '@angular/core/testing';
import { IconComponent } from './icon.component';
import {IconComponent} from './icon.component';
describe('IconComponent', () => {
let component: IconComponent;
@ -8,9 +8,9 @@ describe('IconComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ IconComponent ]
declarations: [IconComponent]
})
.compileComponents();
.compileComponents();
});
beforeEach(() => {

View File

@ -1,4 +1,4 @@
import { Component, Input, OnInit } from '@angular/core';
import {Component, Input, OnInit} from '@angular/core';
@Component({
selector: 'app-icon',
@ -9,7 +9,9 @@ export class IconComponent implements OnInit {
@Input() iconName!: string;
@Input() iconSize!: number;
@Input() iconColor!: string;
constructor() { }
constructor() {
}
ngOnInit(): void {
}

View File

@ -1,26 +1,27 @@
<nav class="navbar sticky-top navbar-expand-lg navbar-light bg-light shadow ">
<div class="container-fluid">
<a class="navbar-brand" href="#">🪴 La Belle Plante</a>
<button class="navbar-toggler"
<div class="container-fluid">
<a class="navbar-brand" href="#">🪴 La Belle Plante</a>
<button class="navbar-toggler"
type="button"
data-bs-toggle="collapse"
data-bs-target="#navbarNavAltMarkup"
aria-controls="navbarNavAltMarkup"
aria-expanded="false"
aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNavAltMarkup">
<div class="navbar-nav">
<a routerLink="home" routerLinkActive="active-custom" class="nav-link">Accueil</a>
<a routerLink="details" routerLinkActive="active-custom" class="nav-link">Details</a>
<a class="nav-link">Panier</a>
<a class="nav-link disabled">Plus d'option bientôt</a>
<a class="nav-link disabled" *ngIf="likeCounter == 0"> Pas de plante likée</a>
<a class="nav-link disabled" *ngIf="likeCounter == 1">Plante likée : {{ likeCounter }}</a>
<a class="nav-link disabled" *ngIf="likeCounter > 1">Plantes likées : {{ likeCounter }}</a>
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNavAltMarkup">
<div class="navbar-nav">
<a routerLink="home" routerLinkActive="active-custom" class="nav-link">Accueil</a>
<a routerLink="details" routerLinkActive="active-custom" class="nav-link">Details</a>
<a routerLink="account/signin" routerLinkActive="active-custom" class="nav-link">Se connecter</a>
<a class="nav-link">Panier</a>
<a class="nav-link disabled">Plus d'option bientôt</a>
<a class="nav-link disabled" *ngIf="likeCounter == 0"> Pas de plante likée</a>
<a class="nav-link disabled" *ngIf="likeCounter == 1">Plante likée : {{ likeCounter }}</a>
<a class="nav-link disabled" *ngIf="likeCounter > 1">Plantes likées : {{ likeCounter }}</a>
</div>
</div>
</div>
</div>
</div>
</nav>

View File

@ -1,3 +1,3 @@
.active-custom {
color: green !important;
color: green !important;
}

View File

@ -1,6 +1,6 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import {ComponentFixture, TestBed} from '@angular/core/testing';
import { NavBarComponent } from './nav-bar.component';
import {NavBarComponent} from './nav-bar.component';
describe('NavBarComponent', () => {
let component: NavBarComponent;
@ -8,9 +8,9 @@ describe('NavBarComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ NavBarComponent ]
declarations: [NavBarComponent]
})
.compileComponents();
.compileComponents();
});
beforeEach(() => {

View File

@ -1,6 +1,6 @@
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Subscription } from 'rxjs';
import { PlantouneService } from 'src/app/services/plantoune.service';
import {Component, OnDestroy, OnInit} from '@angular/core';
import {Subscription} from 'rxjs';
import {PlantouneService} from 'src/app/services/plantoune.service';
@Component({
selector: 'app-nav-bar',
@ -13,19 +13,19 @@ export class NavBarComponent implements OnInit, OnDestroy {
constructor(private plantouneService: PlantouneService) {
this.likeCounter = 0;
}
}
ngOnInit(): void {
this.subPlantLiked = this.plantouneService.plantLiked$.subscribe(
() => {
console.log('Get new event from Subject');
this.likeCounter ++;
this.likeCounter++;
}
)
}
ngOnDestroy(): void {
this.subPlantLiked.unsubscribe();
this.subPlantLiked.unsubscribe();
}
}

View File

@ -0,0 +1,22 @@
import {NgModule} from '@angular/core';
import {RouterModule, Routes} from '@angular/router';
import {PageForgotPasswordComponent} from './pages/page-forgot-password/page-forgot-password.component';
import {PageResetPasswordComponent} from './pages/page-reset-password/page-reset-password.component';
import {PageSigninComponent} from './pages/page-signin/page-signin.component';
import {PageSignupComponent} from './pages/page-signup/page-signup.component';
const routes: Routes = [
{path: '', redirectTo: 'signin', pathMatch: 'full'},
{path: "signin", component: PageSigninComponent},
{path: "signup", component: PageSignupComponent},
{path: "forgot-password", component: PageForgotPasswordComponent},
{path: "reset-password", component: PageResetPasswordComponent}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class AccountRoutingModule {
}

View File

@ -0,0 +1,24 @@
import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {AccountRoutingModule} from './account-routing.module';
import {PageSignupComponent} from './pages/page-signup/page-signup.component';
import {PageSigninComponent} from './pages/page-signin/page-signin.component';
import {PageForgotPasswordComponent} from './pages/page-forgot-password/page-forgot-password.component';
import {PageResetPasswordComponent} from './pages/page-reset-password/page-reset-password.component';
@NgModule({
declarations: [
PageSignupComponent,
PageSigninComponent,
PageForgotPasswordComponent,
PageResetPasswordComponent
],
imports: [
CommonModule,
AccountRoutingModule
]
})
export class AccountModule {
}

View File

@ -0,0 +1 @@
<p>page-forgot-password works!</p>

View File

@ -0,0 +1,25 @@
import {ComponentFixture, TestBed} from '@angular/core/testing';
import {PageForgotPasswordComponent} from './page-forgot-password.component';
describe('PageForgotPasswordComponent', () => {
let component: PageForgotPasswordComponent;
let fixture: ComponentFixture<PageForgotPasswordComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [PageForgotPasswordComponent]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(PageForgotPasswordComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,16 @@
import {Component, OnInit} from '@angular/core';
@Component({
selector: 'app-page-forgot-password',
templateUrl: './page-forgot-password.component.html',
styleUrls: ['./page-forgot-password.component.scss']
})
export class PageForgotPasswordComponent implements OnInit {
constructor() {
}
ngOnInit(): void {
}
}

View File

@ -0,0 +1 @@
<p>page-reset-password works!</p>

View File

@ -0,0 +1,25 @@
import {ComponentFixture, TestBed} from '@angular/core/testing';
import {PageResetPasswordComponent} from './page-reset-password.component';
describe('PageResetPasswordComponent', () => {
let component: PageResetPasswordComponent;
let fixture: ComponentFixture<PageResetPasswordComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [PageResetPasswordComponent]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(PageResetPasswordComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,16 @@
import {Component, OnInit} from '@angular/core';
@Component({
selector: 'app-page-reset-password',
templateUrl: './page-reset-password.component.html',
styleUrls: ['./page-reset-password.component.scss']
})
export class PageResetPasswordComponent implements OnInit {
constructor() {
}
ngOnInit(): void {
}
}

View File

@ -0,0 +1 @@
<p>page-signin works!</p>

View File

@ -0,0 +1,25 @@
import {ComponentFixture, TestBed} from '@angular/core/testing';
import {PageSigninComponent} from './page-signin.component';
describe('PageSigninComponent', () => {
let component: PageSigninComponent;
let fixture: ComponentFixture<PageSigninComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [PageSigninComponent]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(PageSigninComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,16 @@
import {Component, OnInit} from '@angular/core';
@Component({
selector: 'app-page-signin',
templateUrl: './page-signin.component.html',
styleUrls: ['./page-signin.component.scss']
})
export class PageSigninComponent implements OnInit {
constructor() {
}
ngOnInit(): void {
}
}

View File

@ -0,0 +1 @@
<p>page-signup works!</p>

View File

@ -0,0 +1,25 @@
import {ComponentFixture, TestBed} from '@angular/core/testing';
import {PageSignupComponent} from './page-signup.component';
describe('PageSignupComponent', () => {
let component: PageSignupComponent;
let fixture: ComponentFixture<PageSignupComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [PageSignupComponent]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(PageSignupComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,16 @@
import {Component, OnInit} from '@angular/core';
@Component({
selector: 'app-page-signup',
templateUrl: './page-signup.component.html',
styleUrls: ['./page-signup.component.scss']
})
export class PageSignupComponent implements OnInit {
constructor() {
}
ngOnInit(): void {
}
}

View File

@ -1,26 +1,25 @@
<div class="d-flex align-items-stretch">
<app-filter-side-bar [listCategories]="listCategoriesFilter"></app-filter-side-bar>
<div class="custom-main container p-3">
<input class="form-control"
type="text"
placeholder="Recherche ta belle plante"
aria-label="Input Recherche ta belle plante">
<div class="py-3">
Trier par :
<button class="btn btn-outline-success btn-sm me-2">Prix</button>
<button class="btn btn-outline-success btn-sm me-2">Ordre Alpha</button>
<button class="btn btn-outline-success btn-sm me-2">Avis</button>
</div>
<div class="row">
<div class="col" *ngFor="let product of listData">
<app-card-plante [plant]="product"
(clickLike)="onEventLike()">
</app-card-plante>
</div>
</div>
<app-filter-side-bar [listCategories]="listCategoriesFilter" (stateNumber)="onRatingFilter($event)"
(rangeNumber)="onPriceFilter($event)" (checkCategory)="onListCategory($event)"
(reset)="onResetFilter()"></app-filter-side-bar>
<div class="custom-main container p-3">
<input class="form-control"
type="text"
placeholder="Recherche ta belle plante"
aria-label="Input Recherche ta belle plante"
(input)="onRecherchePlante($event)">
<div class="py-3">
Trier par :
<button class="btn btn-outline-success btn-sm me-2" (click)="onPriceTri()">Prix</button>
<button class="btn btn-outline-success btn-sm me-2" (click)="onAlphaTri()">Ordre Alpha</button>
<button class="btn btn-outline-success btn-sm me-2" (click)="onRatingTri()">Avis</button>
</div>
</div>
<div class="row">
<div class="col" *ngFor="let product of listData">
<app-card-plante [plant]="product" (clickLike)="onEventLike()">
</app-card-plante>
</div>
</div>
</div>
</div>

View File

@ -1,6 +1,6 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import {ComponentFixture, TestBed} from '@angular/core/testing';
import { PageAccueilComponent } from './page-accueil.component';
import {PageAccueilComponent} from './page-accueil.component';
describe('PageAccueilComponent', () => {
let component: PageAccueilComponent;
@ -8,9 +8,9 @@ describe('PageAccueilComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ PageAccueilComponent ]
declarations: [PageAccueilComponent]
})
.compileComponents();
.compileComponents();
});
beforeEach(() => {

View File

@ -1,7 +1,8 @@
import { Component, OnInit } from '@angular/core';
import { PlantouneService } from 'src/app/services/plantoune.service';
import {Component, OnInit} from '@angular/core';
import {PlantouneService} from 'src/app/services/plantoune.service';
import * as _ from 'underscore';
@Component({
selector: 'app-page-accueil',
templateUrl: './page-accueil.component.html',
@ -9,39 +10,69 @@ import * as _ from 'underscore';
})
export class PageAccueilComponent implements OnInit {
public listData: any[];
public listPricePlant: any[];
public clickCounter: any;
public listDataGlobal: any[];
public listDataFilter: any[];
public listCategoriesFilter: string[];
public category: string[];
public choix: string;
public rangeNumber: number[];
public stateNumber: number;
public isCategoryFilterActive: boolean;
public isPricingFilterActive: boolean;
public isRatingFilterActive: boolean;
public isSearchFilterActive: boolean;
constructor(private plantouneService: PlantouneService) {
this.listData = [];
this.listCategoriesFilter = [];
}
this.listPricePlant = [];
this.listDataGlobal = [];
this.clickCounter = 0;
this.listDataFilter = [];
/**
* equivalent de la ligne du dessus
*
* plantouneService;
*
* constructor(plantouneService: PlantouneService) {
* this.plantouneService = plantouneService;
* }
*/
this.category = [];
this.choix = '';
this.rangeNumber = [];
this.stateNumber = 0;
this.isCategoryFilterActive = false;
this.isPricingFilterActive = false;
this.isRatingFilterActive = false;
this.isSearchFilterActive = false;
this.clickCounter = 0;
}
/**
* equivalent de la ligne du dessus
*
* plantouneService;
*
* constructor(plantouneService: PlantouneService) {
* this.plantouneService = plantouneService; }
*/
ngOnInit(): void {
this.plantouneService.getData().subscribe(
(listPlant: any[]) => {
console.log(listPlant);
this.listDataGlobal = [...listPlant];
this.listDataFilter = [...this.listDataGlobal];
console.log(this.listDataGlobal);
/**
* Technique avec Underscore JS pour recupérer les catégories uniques de nos plantes
*/
const listAllCategories = listPlant.map(product => product.product_breadcrumb_label);
console.log(listAllCategories);
// console.log(listAllCategories);
const listUniqCategories = _.uniq(listAllCategories)
console.log(listUniqCategories);
// console.log(listUniqCategories);
/**
@ -52,14 +83,305 @@ export class PageAccueilComponent implements OnInit {
console.log(listUniqJsCategories);
this.listCategoriesFilter = listUniqJsCategories;
this.listData = listPlant;
this.listData = [...listPlant];
this.listData.length = 9;
this.listDataGlobal = [...listPlant]
console.log(this.listData);
}
)
}
onEventLike() {
this.plantouneService.plantLiked$.next('')
this.plantouneService.plantLiked$.next('');
}
// onRecherchePlante(choix: any) {
//
// this.clickCounter ++
// console.log(this.clickCounter)
// this.listData = [...this.listDataGlobal];
// if (this.clickCounter %2) {
// this.listData.sort((a, b) => parseFloat(a.product_price) - parseFloat(b.product_price));
// }else{
// this.listData.sort((a, b) => parseFloat(b.product_price) - parseFloat(a.product_price));
// }
// const search = choix.target.value
// if (search == '') {
// this.listData = [...this.listDataGlobal];
// }
// console.log(search);
// this.listData = this.listData.filter((plant) => {
// if(plant.product_name.toLowerCase().includes(search.toLowerCase())){
// return plant;
// }
// });
// //Equivaut à la ligne ci-dessous (version abrégée)
// //this.listData = this.listDataGlobal.filter((plant) => plant.product_name.toLowerCase().includes(search.toLowerCase()))
// console.log(this.listData);
// if (this.listData.length >= 9) {this.listData.length=9}
// }
// onListCategory(categoryArray: string[]) {
// // this.listData=listData;
// //console.log(typeof(valueText));
//
// if (categoryArray.length == 0) {
// this.listData = [...this.listDataGlobal];
//
// } else if (categoryArray.length > 0) {
// let listProductsByCategory: string[] = [];
// this.listDataGlobal.forEach(product => {
//
// categoryArray.forEach(categorySelected => {
// if (product.product_breadcrumb_label == categorySelected) {
// listProductsByCategory.push(product);
// }
// });
// });
// this.listData = [...listProductsByCategory];
// }
//
// if (this.listData.length >= 9) {
// this.listData.length = 9;
// }
// }
onListCategory(categoryArray: string[]) {
if (categoryArray.length == 0) {
this.listData = [...this.listDataGlobal];
this.isCategoryFilterActive = false;
} else {
this.category = [...categoryArray];
this.isCategoryFilterActive = true;
}
this.onApplyFilters();
}
onRecherchePlante(choix: any) {
this.choix = choix.target.value;
this.isSearchFilterActive = true;
this.onApplyFilters();
}
onRatingFilter(stateNumber: number): void {
this.stateNumber = stateNumber;
this.isRatingFilterActive = true;
this.onApplyFilters();
}
onPriceFilter(rangeNumber: number[]) {
this.rangeNumber = [...rangeNumber];
this.isPricingFilterActive = true;
this.onApplyFilters();
}
onApplyFilters(): void {
this.clickCounter = 0;
if (this.isCategoryFilterActive) {
let listDataFinal: any = [];
this.listDataGlobal.forEach(product => {
this.category.forEach(categorySelected => {
if (product.product_breadcrumb_label == categorySelected) {
listDataFinal.push(product);
}
});
});
this.listData = [...listDataFinal];
}
if (this.isSearchFilterActive) {
let listDataFinal: any = [];
this.listDataGlobal.forEach(product => {
if (product.product_name.toLowerCase().includes(this.choix.toLowerCase())) {
listDataFinal.push(product);
}
});
this.listData = [...listDataFinal];
}
if (this.isPricingFilterActive) {
let listDataFinal: any = [];
this.listDataGlobal.forEach(product => {
if (parseFloat(product.product_unitprice_ati) >= this.rangeNumber[0]
&& parseFloat(product.product_unitprice_ati) <= this.rangeNumber[1]) {
listDataFinal.push(product);
}
});
this.listData = [...listDataFinal];
}
if (this.isRatingFilterActive) {
let listDataFinal: any = [];
this.listDataGlobal.forEach(product => {
if (product.product_rating >= this.stateNumber) {
listDataFinal.push(product);
}
});
this.listData = [...listDataFinal];
}
if (this.isSearchFilterActive && this.isCategoryFilterActive) {
let listDataFinal: any = [];
this.listDataGlobal.forEach(product => {
this.category.forEach(categorySelected => {
if (product.product_breadcrumb_label == categorySelected
&& product.product_name.toLowerCase().includes(this.choix.toLowerCase())) {
listDataFinal.push(product);
}
});
});
this.listData = [...listDataFinal];
}
if (this.isPricingFilterActive && this.isCategoryFilterActive) {
let listDataFinal: any = [];
this.listDataGlobal.forEach(product => {
this.category.forEach(categorySelected => {
if (product.product_breadcrumb_label == categorySelected
&& parseFloat(product.product_unitprice_ati) >= this.rangeNumber[0]
&& parseFloat(product.product_unitprice_ati) <= this.rangeNumber[1]) {
listDataFinal.push(product);
}
});
});
this.listData = [...listDataFinal];
}
if (this.isRatingFilterActive && this.isCategoryFilterActive) {
let listDataFinal: any = [];
this.listDataGlobal.forEach(product => {
this.category.forEach(categorySelected => {
if (product.product_breadcrumb_label == categorySelected
&& product.product_rating >= this.stateNumber) {
listDataFinal.push(product);
}
});
});
this.listData = [...listDataFinal];
}
if (this.isSearchFilterActive && this.isPricingFilterActive) {
let listDataFinal: any = [];
this.listDataGlobal.forEach(product => {
if (parseFloat(product.product_unitprice_ati) >= this.rangeNumber[0]
&& parseFloat(product.product_unitprice_ati) <= this.rangeNumber[1]
&& product.product_name.toLowerCase().includes(this.choix.toLowerCase())) {
listDataFinal.push(product);
}
});
this.listData = [...listDataFinal];
}
if (this.isSearchFilterActive && this.isRatingFilterActive) {
let listDataFinal: any = [];
this.listDataGlobal.forEach(product => {
if (product.product_rating >= this.stateNumber
&& product.product_name.toLowerCase().includes(this.choix.toLowerCase())) {
listDataFinal.push(product);
}
});
this.listData = [...listDataFinal];
}
if (this.isPricingFilterActive && this.isRatingFilterActive) {
let listDataFinal: any = [];
this.listDataGlobal.forEach(product => {
if (parseFloat(product.product_unitprice_ati) >= this.rangeNumber[0]
&& parseFloat(product.product_unitprice_ati) <= this.rangeNumber[1]
&& product.product_rating >= this.stateNumber) {
listDataFinal.push(product);
}
});
this.listData = [...listDataFinal];
}
if (this.isSearchFilterActive && this.isPricingFilterActive && this.isRatingFilterActive) {
let listDataFinal: any = [];
this.listDataGlobal.forEach(product => {
if (product.product_rating >= this.stateNumber && parseFloat(product.product_unitprice_ati) >= this.rangeNumber[0]
&& parseFloat(product.product_unitprice_ati) <= this.rangeNumber[1]
&& product.product_name.toLowerCase().includes(this.choix.toLowerCase())) {
listDataFinal.push(product);
}
});
this.listData = [...listDataFinal];
}
if (this.isCategoryFilterActive && this.isSearchFilterActive && this.isPricingFilterActive) {
let listDataFinal: any = [];
this.listDataGlobal.forEach(product => {
this.category.forEach(categorySelected => {
if (product.product_breadcrumb_label == categorySelected
&& parseFloat(product.product_unitprice_ati) >= this.rangeNumber[0]
&& parseFloat(product.product_unitprice_ati) <= this.rangeNumber[1]
&& product.product_name.toLowerCase().includes(this.choix.toLowerCase())) {
listDataFinal.push(product);
}
});
});
this.listData = [...listDataFinal];
}
if (this.isRatingFilterActive && this.isCategoryFilterActive && this.isSearchFilterActive && this.isPricingFilterActive) {
let listDataFinal: any = [];
this.listDataGlobal.forEach(product => {
this.category.forEach(categorySelected => {
if (product.product_breadcrumb_label == categorySelected
&& product.product_rating >= this.stateNumber
&& parseFloat(product.product_unitprice_ati) >= this.rangeNumber[0]
&& parseFloat(product.product_unitprice_ati) <= this.rangeNumber[1]
&& product.product_name.toLowerCase().includes(this.choix.toLowerCase())) {
listDataFinal.push(product);
}
});
});
this.listData = [...listDataFinal];
}
if (this.listData.length >= 9) this.listData.length = 9;
}
onResetFilter(): void {
window.location.reload();
}
//Tri des prix des plantes par ordre croissant ou décroissant
onPriceTri(): void {
this.clickCounter++
console.log(this.clickCounter)
if (this.clickCounter % 2) {
this.listData.sort((a, b) => parseFloat(a.product_price) - parseFloat(b.product_price));
} else {
this.listData.sort((a, b) => parseFloat(b.product_price) - parseFloat(a.product_price));
}
}
//Tri des noms des plantes par ordre alphanumérique
onAlphaTri(): void {
this.clickCounter++
if (this.clickCounter % 2) {
this.listData.sort((a, b) => (a.product_name > b.product_name) ? 1 : -1)
} else {
this.listData.sort((a, b) => (b.product_name > a.product_name) ? 1 : -1)
}
}
//Tri des avis des plantes par ordre croissant ou décroissant
onRatingTri(): void {
this.clickCounter++
if (this.clickCounter % 2) {
this.listData.sort((a, b) => (a.product_rating > b.product_rating) ? 1 : -1)
} else {
this.listData.sort((a, b) => (b.product_rating > a.product_rating) ? 1 : -1)
}
}
}

View File

@ -1 +1,33 @@
<p>page-details works!</p>
<div class="d-flex justify-content-center" *ngIf="detailsPlant">
<div class="d-flex align-items-center flex-column">
<img src="{{detailsPlant.product_url_picture}}" class="col-sm-5" style="width: 30rem;"
alt="Image de {{ detailsPlant.product_name }}">
<div class="card-content">
<app-avis-bar [ratingIndex]="detailsPlant.product_rating"></app-avis-bar>
</div>
</div>
<div class="d-flex align-items-start flex-column mt-4 ">
<h4 style=" color: green;">{{detailsPlant.product_breadcrumb_label}}</h4>
<h2 class="card-title" style="font-size: 30px;">{{ detailsPlant.product_name }}</h2>
<div>
</div>
<div class="card-content">
</div>
<div
style="border-style: solid; border-color: green; margin: auto; text-align: left; margin-right: 20%;padding: 2%;">
<p>
Plante appréciant la chaleur et un bon réseau wifi,
interconnectée avec son propriétaire et détestant les chats.
Beaucoup de café et un peu deau. Ne pas sortir en extérieur, sauf en terrasse. Floraison totale au
mois de juin.
</p>
</div>
<a href="#" class="card-content" class="btn btn-success">Je l'ajoute à mon panier
: {{ detailsPlant.product_unitprice_ati }} €</a>
<div>Quantité restante : {{detailsPlant.product_qty}}</div>
<a href="#" class="btn btn-success" style="margin-left: 75%">Voir mon panier</a>
</div>
</div>

View File

@ -1,6 +1,6 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import {ComponentFixture, TestBed} from '@angular/core/testing';
import { PageDetailsComponent } from './page-details.component';
import {PageDetailsComponent} from './page-details.component';
describe('PageDetailsComponent', () => {
let component: PageDetailsComponent;
@ -8,9 +8,9 @@ describe('PageDetailsComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ PageDetailsComponent ]
declarations: [PageDetailsComponent]
})
.compileComponents();
.compileComponents();
});
beforeEach(() => {

View File

@ -1,4 +1,7 @@
import { Component, OnInit } from '@angular/core';
import {Component, OnInit} from '@angular/core';
import {ActivatedRoute} from '@angular/router';
import {PlantouneService} from 'src/app/services/plantoune.service';
@Component({
selector: 'app-page-details',
@ -7,9 +10,39 @@ import { Component, OnInit } from '@angular/core';
})
export class PageDetailsComponent implements OnInit {
constructor() { }
detailsPlant: any;
public listData: any[];
ngOnInit(): void {
constructor(private route: ActivatedRoute, private plantouneService: PlantouneService) {
this.listData = [];
}
ngOnInit(): void {
this.plantouneService.getData().subscribe(
(listPlant: any[]) => {
console.log(listPlant);
this.listData = listPlant;
//ajoute le ProductId à l'url
const routeParams = this.route.snapshot.paramMap;
const productIdFromRoute = Number(routeParams.get('productId'));
// Faire appel au service et récuperer et executer la requete http et lui fournir le productId
this.plantouneService.getPlantById(productIdFromRoute).subscribe
(plant => {
this.detailsPlant = plant[0];
console.log(this.detailsPlant);
})
})
}
test(id: any) {
console.log(id);
}
}

View File

@ -1,6 +1,6 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import {ComponentFixture, TestBed} from '@angular/core/testing';
import { PageNotFoundComponent } from './page-not-found.component';
import {PageNotFoundComponent} from './page-not-found.component';
describe('PageNotFoundComponent', () => {
let component: PageNotFoundComponent;
@ -8,9 +8,9 @@ describe('PageNotFoundComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ PageNotFoundComponent ]
declarations: [PageNotFoundComponent]
})
.compileComponents();
.compileComponents();
});
beforeEach(() => {

View File

@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core';
import {Component, OnInit} from '@angular/core';
@Component({
selector: 'app-page-not-found',
@ -7,7 +7,8 @@ import { Component, OnInit } from '@angular/core';
})
export class PageNotFoundComponent implements OnInit {
constructor() { }
constructor() {
}
ngOnInit(): void {
}

View File

@ -1,6 +1,6 @@
import { TestBed } from '@angular/core/testing';
import {TestBed} from '@angular/core/testing';
import { PlantouneService } from './plantoune.service';
import {PlantouneService} from './plantoune.service';
describe('PlantouneService', () => {
let service: PlantouneService;

View File

@ -1,6 +1,6 @@
import { Injectable } from '@angular/core';
import { Observable, Subject } from 'rxjs';
import { HttpClient } from '@angular/common/http';
import {Injectable} from '@angular/core';
import {Observable, Subject} from 'rxjs';
import {HttpClient} from '@angular/common/http';
@Injectable({
providedIn: 'root'
@ -8,9 +8,15 @@ import { HttpClient } from '@angular/common/http';
export class PlantouneService {
plantLiked$ = new Subject<any>();
constructor(private httpClient: HttpClient) { }
constructor(private httpClient: HttpClient) {
}
getData(): Observable<any[]> {
return this.httpClient.get<any[]>('http://localhost:3000/list_products');
}
getPlantById(id: any): Observable<any[]> {
return this.httpClient.get<any[]>('http://localhost:3000/list_products?product_id=' + id);
}
}

View File

@ -9,6 +9,6 @@
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.7.2/font/bootstrap-icons.css">
</head>
<body>
<app-root></app-root>
<app-root></app-root>
</body>
</html>

View File

@ -1,8 +1,8 @@
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import {enableProdMode} from '@angular/core';
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
import {AppModule} from './app/app.module';
import {environment} from './environments/environment';
if (environment.production) {
enableProdMode();

View File

@ -45,7 +45,7 @@
/***************************************************************************************************
* Zone JS is required by default for Angular itself.
*/
import 'zone.js'; // Included with Angular CLI.
import 'zone.js'; // Included with Angular CLI.
/***************************************************************************************************

View File

@ -1,11 +1,8 @@
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
import 'zone.js/testing';
import { getTestBed } from '@angular/core/testing';
import {
BrowserDynamicTestingModule,
platformBrowserDynamicTesting
} from '@angular/platform-browser-dynamic/testing';
import {getTestBed} from '@angular/core/testing';
import {BrowserDynamicTestingModule, platformBrowserDynamicTesting} from '@angular/platform-browser-dynamic/testing';
declare const require: {
context(path: string, deep?: boolean, filter?: RegExp): {