'use client'; import { useState, useEffect, useCallback } from 'react'; import { Copy, Star, Check, ArrowLeftRight, BarChart3 } from 'lucide-react'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Input } from '@/components/ui/input'; import { Button } from '@/components/ui/button'; import SearchUnits from './SearchUnits'; import ConversionHistory from './ConversionHistory'; import VisualComparison from './VisualComparison'; import CommandPalette from '@/components/ui/CommandPalette'; import { getAllMeasures, getUnitsForMeasure, convertToAll, convertUnit, formatMeasureName, getCategoryColor, getCategoryColorHex, type Measure, type ConversionResult, } from '@/lib/units'; import { parseNumberInput, formatNumber, cn } from '@/lib/utils'; import { saveToHistory, getFavorites, toggleFavorite } from '@/lib/storage'; export default function MainConverter() { const [selectedMeasure, setSelectedMeasure] = useState('length'); const [selectedUnit, setSelectedUnit] = useState('m'); const [targetUnit, setTargetUnit] = useState('ft'); const [inputValue, setInputValue] = useState('1'); const [conversions, setConversions] = useState([]); const [favorites, setFavorites] = useState([]); const [copiedUnit, setCopiedUnit] = useState(null); const [showVisualComparison, setShowVisualComparison] = useState(false); const [isDragging, setIsDragging] = useState(false); const measures = getAllMeasures(); const units = getUnitsForMeasure(selectedMeasure); // Load favorites useEffect(() => { setFavorites(getFavorites()); }, []); // Update conversions when input changes useEffect(() => { const numValue = parseNumberInput(inputValue); if (numValue !== null && selectedUnit) { const results = convertToAll(numValue, selectedUnit); setConversions(results); } else { setConversions([]); } }, [inputValue, selectedUnit]); // Update selected unit when measure changes useEffect(() => { const availableUnits = getUnitsForMeasure(selectedMeasure); if (availableUnits.length > 0) { setSelectedUnit(availableUnits[0]); setTargetUnit(availableUnits[1] || availableUnits[0]); } }, [selectedMeasure]); // Swap units const handleSwapUnits = useCallback(() => { const temp = selectedUnit; setSelectedUnit(targetUnit); setTargetUnit(temp); // Convert the value const numValue = parseNumberInput(inputValue); if (numValue !== null) { const converted = convertUnit(numValue, selectedUnit, targetUnit); setInputValue(converted.toString()); } }, [selectedUnit, targetUnit, inputValue]); // Copy to clipboard const copyToClipboard = useCallback(async (value: number, unit: string) => { try { await navigator.clipboard.writeText(`${formatNumber(value)} ${unit}`); setCopiedUnit(unit); setTimeout(() => setCopiedUnit(null), 2000); } catch (error) { console.error('Failed to copy:', error); } }, []); // Toggle favorite const handleToggleFavorite = useCallback((unit: string) => { const isFavorite = toggleFavorite(unit); setFavorites(getFavorites()); }, []); // Save to history when conversion happens (but not during dragging) useEffect(() => { if (isDragging) return; // Don't save to history while dragging const numValue = parseNumberInput(inputValue); if (numValue !== null && selectedUnit && conversions.length > 0) { // Save first conversion to history const firstConversion = conversions.find(c => c.unit !== selectedUnit); if (firstConversion) { saveToHistory({ from: { value: numValue, unit: selectedUnit }, to: { value: firstConversion.value, unit: firstConversion.unit }, measure: selectedMeasure, }); // Dispatch custom event for same-window updates window.dispatchEvent(new Event('historyUpdated')); } } }, [inputValue, selectedUnit, conversions, selectedMeasure, isDragging]); // Handle search selection const handleSearchSelect = useCallback((unit: string, measure: Measure) => { setSelectedMeasure(measure); setSelectedUnit(unit); }, []); // Handle history selection const handleHistorySelect = useCallback((record: any) => { setInputValue(record.from.value.toString()); setSelectedMeasure(record.measure); setSelectedUnit(record.from.unit); }, []); // Handle value change from draggable bars const handleValueChange = useCallback((value: number, unit: string, dragging: boolean) => { setIsDragging(dragging); // Convert the dragged unit's value back to the currently selected unit // This keeps the source unit stable while updating the value const convertedValue = convertUnit(value, unit, selectedUnit); setInputValue(convertedValue.toString()); // Keep selectedUnit unchanged }, [selectedUnit]); return (
{/* Command Palette */} {/* Search */}
{/* Category Selection */} Select Category
{measures.map((measure) => ( ))}
{/* Input Section */} Convert {formatMeasureName(selectedMeasure)}
setInputValue(e.target.value)} placeholder="Enter value" className="text-lg" />
{/* Quick result */} {parseNumberInput(inputValue) !== null && (
Result
{formatNumber(convertUnit(parseNumberInput(inputValue)!, selectedUnit, targetUnit))} {targetUnit}
)}
{/* Results */}
All Conversions
{showVisualComparison ? ( ) : (
{conversions.map((conversion) => { const isFavorite = favorites.includes(conversion.unit); const isCopied = copiedUnit === conversion.unit; return (
{/* Favorite & Copy buttons */}
{conversion.unitInfo.plural}
{formatNumber(conversion.value)}
{conversion.unit}
); })}
)}
{/* Conversion History */}
); }