'use client' import { Card, CardContent } from '@/components/ui/card' import { Check, X } from 'lucide-react' import { cn } from '@/lib/utils' import type { Assessment, FlyableWindow, WeatherPoint } from '@/lib/types' import { format, parseISO } from 'date-fns' import { useThresholdStore } from '@/store/threshold-store' interface AssessmentBadgeProps { assessment: Assessment currentWeather: WeatherPoint bestWindow?: FlyableWindow className?: string } // Transform direction to offset from West (270°) function calculateOffset(direction: number): number { return ((direction - 270 + 180) % 360) - 180 } type Rating = 'Great' | 'Good' | 'Okay' | 'Bad' interface RatingInfo { text: Rating color: string } export function AssessmentBadge({ assessment, currentWeather, bestWindow, className }: AssessmentBadgeProps) { const { speedMin, speedMax, dirCenter, dirRange } = useThresholdStore() // Evaluate wind speed const evaluateWindSpeed = (speed: number): RatingInfo => { if (speed < speedMin || speed > speedMax) { return { text: 'Bad', color: 'text-red-600 dark:text-red-400' } } const range = speedMax - speedMin const distanceFromMin = speed - speedMin const distanceFromMax = speedMax - speed const minDistance = Math.min(distanceFromMin, distanceFromMax) if (minDistance < range * 0.15) { return { text: 'Okay', color: 'text-yellow-600 dark:text-yellow-400' } } else if (minDistance < range * 0.35) { return { text: 'Good', color: 'text-green-600 dark:text-green-400' } } else { return { text: 'Great', color: 'text-green-700 dark:text-green-300' } } } // Evaluate wind direction const evaluateWindDirection = (direction: number): RatingInfo => { const offset = calculateOffset(direction) const centerOffset = calculateOffset(dirCenter) const minOffset = centerOffset - dirRange const maxOffset = centerOffset + dirRange if (offset < minOffset || offset > maxOffset) { return { text: 'Bad', color: 'text-red-600 dark:text-red-400' } } const distanceFromCenter = Math.abs(offset - centerOffset) if (distanceFromCenter > dirRange * 0.7) { return { text: 'Okay', color: 'text-yellow-600 dark:text-yellow-400' } } else if (distanceFromCenter > dirRange * 0.4) { return { text: 'Good', color: 'text-green-600 dark:text-green-400' } } else { return { text: 'Great', color: 'text-green-700 dark:text-green-300' } } } const speedRating = evaluateWindSpeed(currentWeather.wind_speed) const directionRating = evaluateWindDirection(currentWeather.wind_direction) // Overall assessment is based on the worse of the two metrics const getOverallAssessment = (): boolean => { const ratingValues: Record = { 'Great': 4, 'Good': 3, 'Okay': 2, 'Bad': 1 } const worstRating = Math.min( ratingValues[speedRating.text], ratingValues[directionRating.text] ) // Only GOOD if both metrics are at least "Good" return worstRating >= 3 } const isGood = getOverallAssessment() return (
{isGood ? 'GOOD' : 'BAD'}
Flyability Assessment
{bestWindow && isGood && (
Best window
{format(parseISO(bestWindow.start), 'ha')} -{' '} {format(parseISO(bestWindow.end), 'ha')}
{bestWindow.duration_hours.toFixed(1)}h duration
)}
{/* Individual metric ratings */}
Wind direction is {directionRating.text}
Wind speed is {speedRating.text}
) }