Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 14 additions & 6 deletions src/app/rxjs-app/app/components/fruits-list.component.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,29 @@
import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
import { FruitService } from '../../shared/services/fruits.service';
import { CartService } from '../../shared/services/cart.service';
import {ChangeDetectionStrategy, Component, inject, OnInit} from '@angular/core';
import {FruitService} from '../../shared/services/fruits.service';
import {CartService} from '../../shared/services/cart.service';
import {Fruit} from "../../shared/model/fruit";
import {Observable} from "rxjs";

@Component({
selector: 'app-fruits-list',
template: `
<div *ngFor="let fruit of fruitsService.fruitList">
{{fruit.name}} - {{fruit.price}}€
<div *ngFor="let fruit of this.fruitsList$ | async">
{{ fruit.name }} - {{ fruit.price }}€
<button (click)="cartService.addFruit(fruit)">Ajouter</button>
</div>
`,
styles: ``,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class FruitsListComponent {
export class FruitsListComponent implements OnInit {

fruitsService = inject(FruitService)
cartService = inject(CartService)
fruitsList$?: Observable<Fruit[]>;

ngOnInit() {
this.fruitsList$ = this.fruitsService.fruitList

}

}
50 changes: 39 additions & 11 deletions src/app/rxjs-app/shared/services/cart.service.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import { Injectable } from '@angular/core';
import { Fruit, FruitState } from '../model/fruit';
import { BehaviorSubject, Observable, map } from 'rxjs';
import {Injectable} from '@angular/core';
import {Fruit, FruitState} from '../model/fruit';
import {BehaviorSubject, Observable} from 'rxjs';

@Injectable({
providedIn: 'root'
})
export class CartService {

/* Le type du panier peut faire peur, nous allons le décomposer
/* Le type du panier peut faire peur, nous allons le décomposer
- L'état du panier est stocké sous la forme d'une Map<K, V>
- K est la clé de notre map, ici un nombre, qui va correspondre à l'id d'un fruit
- V est un objet de type FruitState, qui est le type Fruit avec une quantité associée

- Par exemple, pour représenter 10 oranges dans notre panier :
- Par exemple, pour représenter 10 oranges dans notre panier :
cart.set(2, { id: 2, name: "Orange", price: 3, quantity: 10 })
- La clé est 2, id de notre fruit
- { id: 2,
Expand All @@ -25,7 +25,7 @@ export class CartService {
cart$: Observable<Map<number, FruitState>>

/* Pour ceux qui veulent aller plus loin :
- Implémenter un observable total$, qui renvoie le prix total du panier
- Implémenter un observable total$, qui renvoie le prix total du panier
*/
total$!: Observable<number>

Expand All @@ -35,6 +35,22 @@ export class CartService {
- Le fruit n'est pas déja dans le panier
- Le fruit est déja dans le panier
*/
const lastValue = this._cart.getValue()

if (lastValue.has(fruit.id)) {
const fruitInCart = lastValue.get(fruit.id)
let fruitInCartQuantity = fruitInCart?.quantity

if (fruitInCart && fruitInCartQuantity) {
fruitInCartQuantity++
lastValue.set(fruit.id, {...fruit, quantity: fruitInCartQuantity})
}
} else {
lastValue.set(fruit.id, {...fruit, quantity: 1})
}

this._cart.next(lastValue);

}

/* /!\ Pour les méthodes addFruit(), removeFruit() et removeAllFruitOfType(), attention à ne pas muter la Map existante */
Expand All @@ -43,21 +59,33 @@ export class CartService {
/* Enlève un fruit dans le panier
/* Deux cas à considerer :
- Il reste un fruit de ce type dans le panier, enlever l'entrée dans la map
- Il reste plusieurs fruits de ce type dans le panier, dans ce cas enlever tous les types de fruits
- Il reste plusieurs fruits de ce type dans le panier, dans ce cas enlever tous les types de fruits
*/
const lastValue = this._cart.getValue()

if (lastValue.has(fruit.id)) {
const fruitInCart = lastValue.get(fruit.id)
let fruitInCartQuantity = fruitInCart?.quantity

if (fruitInCart && fruitInCartQuantity && fruitInCartQuantity > 1) {
fruitInCartQuantity--
lastValue.set(fruit.id, {...fruit, quantity: fruitInCartQuantity})
} else if (fruitInCart && fruitInCartQuantity && fruitInCartQuantity == 1)
lastValue.delete(fruit.id)
}

this._cart.next(lastValue);
}

removeAllFruitOfType(fruit: Fruit) {
/* Enlève tous les fruits d'un type dans le panier */
this._cart.getValue().delete(fruit.id)
}

/* Ici le constructeur nous donne une valeur par défaut pour le panier, mais il n'est pas indispensable */
constructor() {
const defaultMap = new Map<number, FruitState>()
defaultMap.set(1, { id: 1, name: "Pomme", price: 1, quantity: 5 })
defaultMap.set(2, { id: 2, name: "Orange", price: 3, quantity: 10 })

this._cart = new BehaviorSubject(defaultMap)
this._cart = new BehaviorSubject(new Map())
this.cart$ = this._cart.asObservable()
}

Expand Down
12 changes: 7 additions & 5 deletions src/app/rxjs-app/shared/services/fruits.service.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
import { Injectable } from '@angular/core';
import {inject, Injectable} from '@angular/core';
import { Fruit } from '../model/fruit';
import {HttpClient} from "@angular/common/http";
import {Observable} from "rxjs";

@Injectable({
providedIn: 'root'
})
export class FruitService {

readonly FRUITS_URL = "http://localhost:3000/fruits"
_http = inject(HttpClient);

get fruitList() {
return this._list
}

/* Remplacer cette liste par un appel http */
private readonly _list: Fruit[] = [
{ id: 1, name: "Pomme", price: 1 },
{ id: 2, name: "Orange", price: 3 },
]
private readonly _list = this._http.get<Fruit[]>(this.FRUITS_URL);

}