156 lines
5.3 KiB
TypeScript
156 lines
5.3 KiB
TypeScript
'use client';
|
|
|
|
import { useState, useEffect } from 'react';
|
|
import { deleteHistoryItem } from '@/utils/historyStorage';
|
|
|
|
export interface HistoryItem {
|
|
id: string;
|
|
item1: string;
|
|
item2: string;
|
|
description1: string;
|
|
description2: string;
|
|
result: string;
|
|
timestamp: number;
|
|
}
|
|
|
|
interface ComparisonHistoryProps {
|
|
onSelectHistory: (item: HistoryItem) => void;
|
|
}
|
|
|
|
export default function ComparisonHistory({ onSelectHistory }: ComparisonHistoryProps) {
|
|
const [history, setHistory] = useState<HistoryItem[]>([]);
|
|
const [isExpanded, setIsExpanded] = useState(false);
|
|
|
|
useEffect(() => {
|
|
const loadHistory = () => {
|
|
try {
|
|
const stored = localStorage.getItem('comparison-history');
|
|
if (stored) {
|
|
const parsed = JSON.parse(stored);
|
|
setHistory(parsed.slice(0, 10)); // Keep only last 10 items
|
|
}
|
|
} catch (error) {
|
|
console.error('Error loading history:', error);
|
|
}
|
|
};
|
|
|
|
loadHistory();
|
|
|
|
// Listen for storage changes
|
|
const handleStorageChange = () => {
|
|
loadHistory();
|
|
};
|
|
|
|
window.addEventListener('storage', handleStorageChange);
|
|
// Custom event for same-page updates
|
|
window.addEventListener('comparison-history-updated', handleStorageChange);
|
|
|
|
return () => {
|
|
window.removeEventListener('storage', handleStorageChange);
|
|
window.removeEventListener('comparison-history-updated', handleStorageChange);
|
|
};
|
|
}, []);
|
|
|
|
const clearHistory = () => {
|
|
localStorage.removeItem('comparison-history');
|
|
setHistory([]);
|
|
window.dispatchEvent(new Event('comparison-history-updated'));
|
|
};
|
|
|
|
const handleDeleteItem = (e: React.MouseEvent, itemId: string) => {
|
|
e.stopPropagation(); // Prevent triggering the onClick of the parent div
|
|
deleteHistoryItem(itemId);
|
|
};
|
|
|
|
const formatDate = (timestamp: number) => {
|
|
return new Date(timestamp).toLocaleDateString('en-US', {
|
|
month: 'short',
|
|
day: 'numeric',
|
|
hour: '2-digit',
|
|
minute: '2-digit'
|
|
});
|
|
};
|
|
|
|
if (history.length === 0) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
<div className="bg-white rounded-xl shadow-lg p-6">
|
|
<div className="flex items-center justify-between mb-4">
|
|
<h2 className="text-xl font-bold text-gray-900">Comparison History</h2>
|
|
<div className="flex items-center gap-3">
|
|
<button
|
|
onClick={() => setIsExpanded(!isExpanded)}
|
|
className="text-blue-600 hover:text-blue-800 text-sm font-medium"
|
|
>
|
|
{isExpanded ? 'Show Less' : `Show All (${history.length})`}
|
|
</button>
|
|
<button
|
|
onClick={clearHistory}
|
|
className="text-red-600 hover:text-red-800 text-sm font-medium"
|
|
>
|
|
Clear History
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="space-y-3">
|
|
{(isExpanded ? history : history.slice(0, 3)).map((item) => (
|
|
<div
|
|
key={item.id}
|
|
onClick={() => onSelectHistory(item)}
|
|
className="p-4 border border-gray-200 rounded-lg hover:border-blue-300 hover:bg-blue-50 cursor-pointer transition-all duration-200 group relative"
|
|
>
|
|
<div className="flex items-center justify-between mb-2">
|
|
<div className="font-medium text-gray-900 flex-1">
|
|
<span className="text-blue-600">{item.item1}</span>
|
|
<span className="text-gray-400 mx-2">vs</span>
|
|
<span className="text-green-600">{item.item2}</span>
|
|
</div>
|
|
<div className="flex items-center gap-2">
|
|
<span className="text-xs text-gray-500">
|
|
{formatDate(item.timestamp)}
|
|
</span>
|
|
<button
|
|
onClick={(e) => handleDeleteItem(e, item.id)}
|
|
className="opacity-0 group-hover:opacity-100 text-red-500 hover:text-red-700 p-1 rounded transition-all duration-200"
|
|
title="Delete this comparison"
|
|
>
|
|
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
{(item.description1 || item.description2) && (
|
|
<div className="text-sm text-gray-600">
|
|
{item.description1 && (
|
|
<div className="truncate">
|
|
<strong>{item.item1}:</strong> {item.description1}
|
|
</div>
|
|
)}
|
|
{item.description2 && (
|
|
<div className="truncate">
|
|
<strong>{item.item2}:</strong> {item.description2}
|
|
</div>
|
|
)}
|
|
</div>
|
|
)}
|
|
</div>
|
|
))}
|
|
</div>
|
|
|
|
{!isExpanded && history.length > 3 && (
|
|
<div className="text-center mt-4">
|
|
<button
|
|
onClick={() => setIsExpanded(true)}
|
|
className="text-blue-600 hover:text-blue-800 text-sm font-medium"
|
|
>
|
|
View {history.length - 3} more comparisons...
|
|
</button>
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
} |