From e4cec8bd928aa6d5cdb493a486f1cec07add1876 Mon Sep 17 00:00:00 2001 From: Louis Fredice NJAKO MOLOM Date: Mon, 28 Oct 2024 12:15:33 +0100 Subject: [PATCH] feat: add trending weather --- .../components/weather/weather.component.html | 12 +- .../components/weather/weather.component.ts | 10 +- src/app/models/trending.ts | 4 + src/app/services/trending.service.spec.ts | 117 ++++++++++++++++++ src/app/services/trending.service.ts | 26 ++++ 5 files changed, 162 insertions(+), 7 deletions(-) create mode 100644 src/app/models/trending.ts create mode 100644 src/app/services/trending.service.spec.ts create mode 100644 src/app/services/trending.service.ts diff --git a/src/app/components/weather/weather.component.html b/src/app/components/weather/weather.component.html index b2553a2..f79c753 100644 --- a/src/app/components/weather/weather.component.html +++ b/src/app/components/weather/weather.component.html @@ -1,11 +1,13 @@

Current Weather

-
- Trending: - Not implemented yet !!! -
@if (globalWeather$ | async) { +
+ Trending: + @if (trending()) { + {{trending()?.label}} + } +
-

First select a town or use the filter before

+

First select a town or use the filter before

diff --git a/src/app/components/weather/weather.component.ts b/src/app/components/weather/weather.component.ts index 610f524..ba7a219 100644 --- a/src/app/components/weather/weather.component.ts +++ b/src/app/components/weather/weather.component.ts @@ -7,6 +7,8 @@ import {WeatherDetailsComponent} from '@components/weather-details/weather-detai import {AsyncPipe} from '@angular/common'; import {toSignal} from '@angular/core/rxjs-interop'; import {Observable} from 'rxjs'; +import {TrendingService} from '@services/trending.service'; +import {Trending} from '@models/trending'; const SEARCH_FIELD_FORM_ID = 'townTextSearch'; @@ -26,10 +28,12 @@ export class WeatherComponent implements OnInit { public selectedTownWeather : WritableSignal = signal(null); public globalWeather!: Signal; public townFilter: WritableSignal = signal(null); - public availableTownWeather!: Signal; + public availableTownWeather!: Signal; + public trending!: Signal; public globalWeather$?: Observable; public townFilterForm!: FormGroup; private weatherService = inject(WeatherService); + private trendingService = inject(TrendingService); private formBuilder = inject(FormBuilder); constructor() { @@ -55,7 +59,9 @@ export class WeatherComponent implements OnInit { return globalWeather; } }); - + this.trending = computed(() => { + return this.trendingService.retrieveTrending(this.availableTownWeather()) + }); } public selectedTown($selectedTownWeather: TownWeather) { diff --git a/src/app/models/trending.ts b/src/app/models/trending.ts new file mode 100644 index 0000000..3b28cce --- /dev/null +++ b/src/app/models/trending.ts @@ -0,0 +1,4 @@ +export type Trending = { + label: string, + url: string +} diff --git a/src/app/services/trending.service.spec.ts b/src/app/services/trending.service.spec.ts new file mode 100644 index 0000000..9671f70 --- /dev/null +++ b/src/app/services/trending.service.spec.ts @@ -0,0 +1,117 @@ +import { TestBed } from '@angular/core/testing'; + +import { TrendingService } from './trending.service'; +import {TownWeather} from '@models/town-weather'; + +const TOWNS_WEATHER = [ + { + "id": 1, + "name": "Douala", + "forecast": { + "condition": "cloudy", + "wind": { + "speed": { + "value": 18.5, + "unit": "km/h" + }, + "direction": "North-West" + }, + "temperature": { + "min": { + "value": 10.8, + "unit": "°c" + }, + "max": { + "value": 29, + "unit": "°c" + } + } + } + }, + { + "id": 2, + "name": "Bafoussam", + "forecast": { + "condition": "cloudy", + "wind": { + "speed": { + "value": 18.5, + "unit": "km/h" + }, + "direction": "North-West" + }, + "temperature": { + "min": { + "value": 10.8, + "unit": "°c" + }, + "max": { + "value": 29, + "unit": "°c" + } + } + } + }, + { + "id": 3, + "name": "Yaoundé", + "forecast": { + "condition": "cloudy", + "wind": { + "speed": { + "value": 18.5, + "unit": "km/h" + }, + "direction": "North-West" + }, + "temperature": { + "min": { + "value": 10.8, + "unit": "°c" + }, + "max": { + "value": 29, + "unit": "°c" + } + } + } + } +]; + +describe('TrendingService', () => { + let service: TrendingService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(TrendingService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); + + it('should generate random index', () => { + expect(service).toBeTruthy(); + const townWeathers = TOWNS_WEATHER as TownWeather[]; + expect(service["generateRandomIndex"](townWeathers)).toBeGreaterThanOrEqual(0); + expect(service["generateRandomIndex"](townWeathers)).toBeLessThan(townWeathers.length); + }); + + it('retrieveTrending should return null empty array', () => { + expect(service).toBeTruthy(); + const townWeathers: TownWeather[] = []; + expect(service.retrieveTrending(townWeathers)).toBeNull(); + }); + + it('retrieveTrending should return trending', () => { + expect(service).toBeTruthy(); + const townWeathers = TOWNS_WEATHER as TownWeather[]; + service["generateRandomIndex"] = jest.fn().mockImplementation(() => 1); + const trending = service.retrieveTrending(townWeathers); + expect(service["generateRandomIndex"]).toHaveBeenCalledTimes(1); + expect(trending).toEqual({ + label: "Visiter Bafoussam", + url: "https://www.google.com/search?q=Bafoussam" + }); + }); +}); diff --git a/src/app/services/trending.service.ts b/src/app/services/trending.service.ts new file mode 100644 index 0000000..28a81d8 --- /dev/null +++ b/src/app/services/trending.service.ts @@ -0,0 +1,26 @@ +import {Injectable} from '@angular/core'; +import {TownWeather} from '@models/town-weather'; +import {Trending} from '@models/trending'; + +@Injectable({ + providedIn: 'root' +}) +export class TrendingService { + + constructor() { } + + public retrieveTrending(townWeathers: TownWeather[]): Trending | null { + if (townWeathers.length === 0) { + return null; + } + const randomIndex = this.generateRandomIndex(townWeathers); + return { + label: `Visiter ${townWeathers[randomIndex].name}`, + url: `https://www.google.com/search?q=${townWeathers[randomIndex].name}` + }; + } + + private generateRandomIndex(townWeathers: TownWeather[]): number { + return Math.floor(Math.random() * townWeathers.length); + } +}