diff --git a/apps/frontend/src/app/features/sites/site-detail/site-detail.html b/apps/frontend/src/app/features/sites/site-detail/site-detail.html
index 9c4a4bc..e10d1db 100644
--- a/apps/frontend/src/app/features/sites/site-detail/site-detail.html
+++ b/apps/frontend/src/app/features/sites/site-detail/site-detail.html
@@ -81,5 +81,16 @@
}
}
+
+
Retour aux sites
diff --git a/apps/frontend/src/app/features/sites/site-detail/site-detail.scss b/apps/frontend/src/app/features/sites/site-detail/site-detail.scss
index a0032be..5cfcad0 100644
--- a/apps/frontend/src/app/features/sites/site-detail/site-detail.scss
+++ b/apps/frontend/src/app/features/sites/site-detail/site-detail.scss
@@ -117,3 +117,12 @@ h2 {
.chart-section {
margin-bottom: 2rem;
}
+
+.recommendations-section {
+ margin: 2.5rem 0 1.5rem;
+}
+
+.recommendations-section__link {
+ display: inline-block;
+ margin-top: 1rem;
+}
diff --git a/apps/frontend/src/app/features/sites/site-detail/site-detail.spec.ts b/apps/frontend/src/app/features/sites/site-detail/site-detail.spec.ts
index 5e3cf46..0e7c35a 100644
--- a/apps/frontend/src/app/features/sites/site-detail/site-detail.spec.ts
+++ b/apps/frontend/src/app/features/sites/site-detail/site-detail.spec.ts
@@ -5,6 +5,8 @@ import { BehaviorSubject, of, throwError } from 'rxjs';
import { SiteDetail } from './site-detail';
import { SitesService } from '../../../core/services/sites.service';
import { ReadingsService } from '../../../core/services/readings.service';
+import { AlertsService } from '../../../core/services/alerts.service';
+import { RecommendationsService } from '../../../core/services/recommendations.service';
const SITE = {
site_id: 'SITE001',
@@ -69,6 +71,7 @@ function setup(
readingsMock: Partial,
) {
const paramMap = new BehaviorSubject(convertToParamMap({ siteId }));
+ const getAlerts = vi.fn().mockReturnValue(of([]));
TestBed.configureTestingModule({
imports: [SiteDetail],
providers: [
@@ -76,9 +79,14 @@ function setup(
{ provide: ActivatedRoute, useValue: { paramMap } },
{ provide: SitesService, useValue: sitesMock },
{ provide: ReadingsService, useValue: readingsMock },
+ { provide: AlertsService, useValue: { getAlerts } },
+ {
+ provide: RecommendationsService,
+ useValue: { getRecommendations: vi.fn().mockReturnValue(of([])) },
+ },
],
});
- return { fixture: TestBed.createComponent(SiteDetail), paramMap };
+ return { fixture: TestBed.createComponent(SiteDetail), paramMap, getAlerts };
}
describe('SiteDetail', () => {
@@ -261,6 +269,27 @@ describe('SiteDetail', () => {
);
});
+ it('demande les recommandations du site consulté à travers ses alertes', () => {
+ const { fixture, getAlerts } = setup(
+ 'SITE001',
+ {
+ getSite: vi.fn().mockReturnValue(of(SITE)),
+ getCurrent: vi.fn().mockReturnValue(of(CURRENT_COMPLET)),
+ },
+ { getHistory: vi.fn().mockReturnValue(of([])) },
+ );
+
+ fixture.detectChanges();
+ fixture.detectChanges();
+
+ expect(getAlerts).toHaveBeenCalledWith({ site_id: 'SITE001' });
+ expect(fixture.nativeElement.querySelector('app-recommendation-list')).not.toBeNull();
+ expect(fixture.nativeElement.textContent).toContain('Recommandations');
+ expect(
+ fixture.nativeElement.querySelector('a[href="/recommendations?site=SITE001"]'),
+ ).not.toBeNull();
+ });
+
it("annonce l'absence de mesure sans interroger l'historique quand timestamp est null", () => {
const getHistory = vi.fn().mockReturnValue(of([]));
const { fixture } = setup(
diff --git a/apps/frontend/src/app/features/sites/site-detail/site-detail.ts b/apps/frontend/src/app/features/sites/site-detail/site-detail.ts
index 21e716d..4fa7896 100644
--- a/apps/frontend/src/app/features/sites/site-detail/site-detail.ts
+++ b/apps/frontend/src/app/features/sites/site-detail/site-detail.ts
@@ -13,6 +13,7 @@ import { Badge, BadgeTone } from '../../../shared/components/ui/badge/badge';
import { Brand } from '../../../shared/components/ui/brand/brand';
import { ConsumptionGauge } from '../../../shared/components/consumption-gauge/consumption-gauge';
import { ReadingHistoryChart } from '../../../shared/components/reading-history-chart/reading-history-chart';
+import { RecommendationList } from '../../../shared/components/recommendation-list/recommendation-list';
const UNAVAILABLE_MESSAGE = 'Détail du site indisponible, réessayez plus tard.';
const NO_MEASUREMENT_MESSAGE = 'Aucune mesure remontée pour ce site.';
@@ -96,7 +97,16 @@ export interface MetricView {
@Component({
selector: 'app-site-detail',
standalone: true,
- imports: [RouterLink, Card, Alert, Badge, Brand, ConsumptionGauge, ReadingHistoryChart],
+ imports: [
+ RouterLink,
+ Card,
+ Alert,
+ Badge,
+ Brand,
+ ConsumptionGauge,
+ ReadingHistoryChart,
+ RecommendationList,
+ ],
templateUrl: './site-detail.html',
styleUrl: './site-detail.scss',
})
@@ -117,6 +127,11 @@ export class SiteDetail {
hasMeasurement = computed(() => this.current()?.timestamp != null);
+ siteAsList = computed(() => {
+ const site = this.site();
+ return site ? [site] : [];
+ });
+
consumptionKw = computed(() => this.current()?.consumption_kw ?? null);
consumptionLabel = computed(() => {