feat(weather): show trend indicators on team averages
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
// src/components/weather/WeatherAverageBar.tsx
|
||||
import { getAverageEmoji } from '@/lib/weather-utils';
|
||||
import { getAverageEmoji, getEmojiScore } from '@/lib/weather-utils';
|
||||
|
||||
interface WeatherEntry {
|
||||
performanceEmoji: string | null;
|
||||
@@ -10,22 +10,93 @@ interface WeatherEntry {
|
||||
|
||||
interface WeatherAverageBarProps {
|
||||
entries: WeatherEntry[];
|
||||
previousAverages?: {
|
||||
performance: number | null;
|
||||
moral: number | null;
|
||||
flux: number | null;
|
||||
valueCreation: number | null;
|
||||
} | null;
|
||||
}
|
||||
|
||||
const AXES = [
|
||||
{ key: 'performanceEmoji' as const, label: 'Performance' },
|
||||
{ key: 'moralEmoji' as const, label: 'Moral' },
|
||||
{ key: 'fluxEmoji' as const, label: 'Flux' },
|
||||
{ key: 'valueCreationEmoji' as const, label: 'Création de valeur' },
|
||||
{ key: 'performanceEmoji' as const, scoreKey: 'performance' as const, label: 'Performance' },
|
||||
{ key: 'moralEmoji' as const, scoreKey: 'moral' as const, label: 'Moral' },
|
||||
{ key: 'fluxEmoji' as const, scoreKey: 'flux' as const, label: 'Flux' },
|
||||
{
|
||||
key: 'valueCreationEmoji' as const,
|
||||
scoreKey: 'valueCreation' as const,
|
||||
label: 'Création de valeur',
|
||||
},
|
||||
];
|
||||
|
||||
export function WeatherAverageBar({ entries }: WeatherAverageBarProps) {
|
||||
function getAverageScore(emojis: (string | null)[]): number | null {
|
||||
const scores = emojis.map(getEmojiScore).filter((score): score is number => score !== null);
|
||||
if (scores.length === 0) return null;
|
||||
return scores.reduce((sum, score) => sum + score, 0) / scores.length;
|
||||
}
|
||||
|
||||
function AverageEvolutionIndicator({
|
||||
currentScore,
|
||||
previousScore,
|
||||
}: {
|
||||
currentScore: number | null;
|
||||
previousScore: number | null | undefined;
|
||||
}) {
|
||||
if (currentScore === null || previousScore === null || previousScore === undefined) return null;
|
||||
const delta = currentScore - previousScore;
|
||||
|
||||
if (delta < 0) {
|
||||
return (
|
||||
<span
|
||||
className="inline-flex h-4 w-4 shrink-0 items-center justify-center rounded-full text-[10px] font-bold"
|
||||
style={{
|
||||
backgroundColor: 'color-mix(in srgb, var(--success) 18%, transparent)',
|
||||
color: 'var(--success)',
|
||||
}}
|
||||
title="En progression"
|
||||
>
|
||||
↑
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
if (delta > 0) {
|
||||
return (
|
||||
<span
|
||||
className="inline-flex h-4 w-4 shrink-0 items-center justify-center rounded-full text-[10px] font-bold"
|
||||
style={{
|
||||
backgroundColor: 'color-mix(in srgb, var(--destructive) 18%, transparent)',
|
||||
color: 'var(--destructive)',
|
||||
}}
|
||||
title="En baisse"
|
||||
>
|
||||
↓
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<span
|
||||
className="inline-flex h-4 w-4 shrink-0 items-center justify-center rounded-full text-[10px] font-bold"
|
||||
style={{
|
||||
backgroundColor: 'color-mix(in srgb, var(--muted) 15%, transparent)',
|
||||
color: 'var(--muted)',
|
||||
}}
|
||||
title="Stable"
|
||||
>
|
||||
→
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
export function WeatherAverageBar({ entries, previousAverages }: WeatherAverageBarProps) {
|
||||
if (entries.length === 0) return null;
|
||||
|
||||
return (
|
||||
<div className="flex flex-wrap items-center gap-3 mb-4">
|
||||
<span className="text-xs font-medium text-muted uppercase tracking-wide">Moyenne équipe</span>
|
||||
{AXES.map(({ key, label }) => {
|
||||
{AXES.map(({ key, scoreKey, label }) => {
|
||||
const currentScore = getAverageScore(entries.map((e) => e[key]));
|
||||
const avg = getAverageEmoji(entries.map((e) => e[key]));
|
||||
return (
|
||||
<div
|
||||
@@ -34,6 +105,10 @@ export function WeatherAverageBar({ entries }: WeatherAverageBarProps) {
|
||||
>
|
||||
<span className="text-lg leading-none">{avg ?? '—'}</span>
|
||||
<span className="text-xs text-muted">{label}</span>
|
||||
<AverageEvolutionIndicator
|
||||
currentScore={currentScore}
|
||||
previousScore={previousAverages?.[scoreKey]}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
||||
Reference in New Issue
Block a user