fix: Veille/ambre uniquement si sargasses à <100km, "banc" au lieu de "patch"
- scoreLabel/etaLabel/SpotMarker conditionnent Veille à distance<100km pour éviter l'alerte ambre sur les spots sans sargasses proches - "patch" → "banc de sargasses" dans le SpotPanel Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -98,7 +98,7 @@ const makeLayerStyles = (isPrediction, opacity) => ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
// ── SVG Markers ───────────────────────────────────────────────────────────
|
// ── SVG Markers ───────────────────────────────────────────────────────────
|
||||||
function SpotMarker({ level, scoreValue, isSelected, name }) {
|
function SpotMarker({ level, scoreValue, scoreDist, isSelected, name }) {
|
||||||
const size = isSelected ? 36 : 28;
|
const size = isSelected ? 36 : 28;
|
||||||
const shadow = 'filter: drop-shadow(2px 3px 0px rgba(0,0,0,0.35))';
|
const shadow = 'filter: drop-shadow(2px 3px 0px rgba(0,0,0,0.35))';
|
||||||
|
|
||||||
@@ -123,7 +123,7 @@ function SpotMarker({ level, scoreValue, isSelected, name }) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (level === 'low') {
|
if (level === 'low') {
|
||||||
const isWatch = (scoreValue ?? 0) >= 15;
|
const isWatch = (scoreValue ?? 0) >= 15 && scoreDist != null && scoreDist < 100;
|
||||||
return (
|
return (
|
||||||
<div className={`smap-marker smap-marker--${isWatch ? 'watch' : 'low'}${isSelected ? ' smap-marker--selected' : ''}`}
|
<div className={`smap-marker smap-marker--${isWatch ? 'watch' : 'low'}${isSelected ? ' smap-marker--selected' : ''}`}
|
||||||
title={name} style={{ width: size, height: size }}>
|
title={name} style={{ width: size, height: size }}>
|
||||||
@@ -195,7 +195,8 @@ export default function SargassesMap({ onSpotSelect, selectedSpotId, activeStep,
|
|||||||
.then(d => {
|
.then(d => {
|
||||||
const level = d?.score?.level;
|
const level = d?.score?.level;
|
||||||
const value = d?.score?.value ?? 0;
|
const value = d?.score?.value ?? 0;
|
||||||
if (level) setSpotScores(prev => ({ ...prev, [s.id]: { level, value } }));
|
const distance = d?.score?.distance ?? null;
|
||||||
|
if (level) setSpotScores(prev => ({ ...prev, [s.id]: { level, value, distance } }));
|
||||||
})
|
})
|
||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
});
|
});
|
||||||
@@ -299,6 +300,7 @@ export default function SargassesMap({ onSpotSelect, selectedSpotId, activeStep,
|
|||||||
const sc = spotScores[spot.id];
|
const sc = spotScores[spot.id];
|
||||||
const level = sc?.level;
|
const level = sc?.level;
|
||||||
const scoreValue = sc?.value ?? 0;
|
const scoreValue = sc?.value ?? 0;
|
||||||
|
const scoreDist = sc?.distance ?? null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Marker
|
<Marker
|
||||||
@@ -308,7 +310,7 @@ export default function SargassesMap({ onSpotSelect, selectedSpotId, activeStep,
|
|||||||
anchor="center"
|
anchor="center"
|
||||||
onClick={() => onSpotSelect(spot)}
|
onClick={() => onSpotSelect(spot)}
|
||||||
>
|
>
|
||||||
<SpotMarker level={level} scoreValue={scoreValue} isSelected={isSelected} name={spot.name} />
|
<SpotMarker level={level} scoreValue={scoreValue} scoreDist={scoreDist} isSelected={isSelected} name={spot.name} />
|
||||||
</Marker>
|
</Marker>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ import { api } from '../../api/client';
|
|||||||
import usePushSubscription from '../../hooks/usePushSubscription';
|
import usePushSubscription from '../../hooks/usePushSubscription';
|
||||||
import './SpotPanel.css';
|
import './SpotPanel.css';
|
||||||
|
|
||||||
function scoreLabel(value, level) {
|
function scoreLabel(value, level, distance) {
|
||||||
if (level === 'high') return 'Impact';
|
if (level === 'high') return 'Impact';
|
||||||
if (level === 'medium') return 'Risque';
|
if (level === 'medium') return 'Risque';
|
||||||
if (value >= 15) return 'Veille';
|
if (value >= 15 && distance != null && distance < 100) return 'Veille';
|
||||||
return 'OK';
|
return 'OK';
|
||||||
}
|
}
|
||||||
const TYPE_ICON = { beach: '🏖', port: '⚓', surf: '🏄', fishing: '🎣' };
|
const TYPE_ICON = { beach: '🏖', port: '⚓', surf: '🏄', fishing: '🎣' };
|
||||||
@@ -28,13 +28,14 @@ function computeEta(score, horizons) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function etaLabel(etaHours, score) {
|
function etaLabel(etaHours, score, distance) {
|
||||||
if (etaHours === 0) return { icon: '🚨', label: 'Impact en cours', cls: 'eta--now' };
|
if (etaHours === 0) return { icon: '🚨', label: 'Impact en cours', cls: 'eta--now' };
|
||||||
if (etaHours === 6) return { icon: '⚠️', label: 'Impact prévu dans ~6h', cls: 'eta--soon' };
|
if (etaHours === 6) return { icon: '⚠️', label: 'Impact prévu dans ~6h', cls: 'eta--soon' };
|
||||||
if (etaHours === 12) return { icon: '⚠️', label: 'Impact prévu dans ~12h', cls: 'eta--soon' };
|
if (etaHours === 12) return { icon: '⚠️', label: 'Impact prévu dans ~12h', cls: 'eta--soon' };
|
||||||
if (etaHours === 24) return { icon: '🕐', label: 'Impact prévu dans ~24h', cls: 'eta--later' };
|
if (etaHours === 24) return { icon: '🕐', label: 'Impact prévu dans ~24h', cls: 'eta--later' };
|
||||||
if (etaHours === 48) return { icon: '🕐', label: 'Impact prévu dans ~48h', cls: 'eta--later' };
|
if (etaHours === 48) return { icon: '🕐', label: 'Impact prévu dans ~48h', cls: 'eta--later' };
|
||||||
if ((score ?? 0) >= 15) return { icon: '👁', label: 'Sargasses en surveillance', cls: 'eta--watch' };
|
if ((score ?? 0) >= 15 && distance != null && distance < 100)
|
||||||
|
return { icon: '👁', label: 'Sargasses en surveillance', cls: 'eta--watch' };
|
||||||
return { icon: '✅', label: 'Aucun impact prévu (48h)', cls: 'eta--safe' };
|
return { icon: '✅', label: 'Aucun impact prévu (48h)', cls: 'eta--safe' };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,7 +101,7 @@ export default function SpotPanel({ spot, activeStep, onClose }) {
|
|||||||
: (
|
: (
|
||||||
<>
|
<>
|
||||||
{activeStep === 'now' && (() => {
|
{activeStep === 'now' && (() => {
|
||||||
const eta = etaLabel(computeEta(data?.score, data?.horizons), data?.score?.value);
|
const eta = etaLabel(computeEta(data?.score, data?.horizons), data?.score?.value, data?.score?.distance);
|
||||||
return (
|
return (
|
||||||
<div className={`spot-panel__eta ${eta.cls}`}>
|
<div className={`spot-panel__eta ${eta.cls}`}>
|
||||||
<span className="spot-panel__eta-icon">{eta.icon}</span>
|
<span className="spot-panel__eta-icon">{eta.icon}</span>
|
||||||
@@ -111,7 +112,7 @@ export default function SpotPanel({ spot, activeStep, onClose }) {
|
|||||||
|
|
||||||
<div className={`spot-panel__gauge gauge--${lvl}`}>
|
<div className={`spot-panel__gauge gauge--${lvl}`}>
|
||||||
<p className="spot-panel__gauge-header">Indice de risque</p>
|
<p className="spot-panel__gauge-header">Indice de risque</p>
|
||||||
<span className="spot-panel__gauge-label">{scoreLabel(displayScore.value, lvl)}</span>
|
<span className="spot-panel__gauge-label">{scoreLabel(displayScore.value, lvl, displayScore.distance)}</span>
|
||||||
<div className="spot-panel__gauge-track">
|
<div className="spot-panel__gauge-track">
|
||||||
<div
|
<div
|
||||||
className="spot-panel__gauge-fill"
|
className="spot-panel__gauge-fill"
|
||||||
@@ -164,7 +165,7 @@ function PatchList({ patches }) {
|
|||||||
return (
|
return (
|
||||||
<div className="patch-list">
|
<div className="patch-list">
|
||||||
<p className="patch-list__title">
|
<p className="patch-list__title">
|
||||||
{patches.length} patch{patches.length > 1 ? 'es' : ''} détecté{patches.length > 1 ? 's' : ''}
|
{patches.length} banc{patches.length > 1 ? 's' : ''} de sargasses détecté{patches.length > 1 ? 's' : ''}
|
||||||
</p>
|
</p>
|
||||||
{patches.map((p, i) => {
|
{patches.map((p, i) => {
|
||||||
const pct = Math.min((p.distanceKm / MAX_KM) * 100, 100);
|
const pct = Math.min((p.distanceKm / MAX_KM) * 100, 100);
|
||||||
|
|||||||
Reference in New Issue
Block a user