194 lines
7.9 KiB
TypeScript
194 lines
7.9 KiB
TypeScript
'use client';
|
|
|
|
import { useState, useEffect } from 'react';
|
|
|
|
interface ComparisonFormProps {
|
|
onSubmit: (item1: string, item2: string, description1: string, description2: string) => void;
|
|
isLoading: boolean;
|
|
selectedExample?: { item1: string; item2: string } | null;
|
|
onExampleUsed?: () => void;
|
|
}
|
|
|
|
export default function ComparisonForm({ onSubmit, isLoading, selectedExample, onExampleUsed }: ComparisonFormProps) {
|
|
const [item1, setItem1] = useState('');
|
|
const [item2, setItem2] = useState('');
|
|
const [description1, setDescription1] = useState('');
|
|
const [description2, setDescription2] = useState('');
|
|
const [showDescriptions, setShowDescriptions] = useState(false);
|
|
|
|
// Handle selected example
|
|
useEffect(() => {
|
|
if (selectedExample) {
|
|
setItem1(selectedExample.item1);
|
|
setItem2(selectedExample.item2);
|
|
onExampleUsed?.();
|
|
}
|
|
}, [selectedExample, onExampleUsed]);
|
|
|
|
const examples = [
|
|
{ item1: 'iPhone 15 Pro', item2: 'Samsung Galaxy S24 Ultra', category: 'Smartphones' },
|
|
{ item1: 'React', item2: 'Vue.js', category: 'Frontend Frameworks' },
|
|
{ item1: 'Tesla Model 3', item2: 'BMW i4', category: 'Electric Cars' },
|
|
{ item1: 'Netflix', item2: 'Disney+', category: 'Streaming Services' },
|
|
{ item1: 'MacBook Pro', item2: 'ThinkPad X1 Carbon', category: 'Laptops' },
|
|
{ item1: 'Coffee', item2: 'Tea', category: 'Beverages' }
|
|
];
|
|
|
|
const getRandomExample = () => {
|
|
return examples[Math.floor(Math.random() * examples.length)];
|
|
};
|
|
|
|
const fillRandomExample = () => {
|
|
const example = getRandomExample();
|
|
setItem1(example.item1);
|
|
setItem2(example.item2);
|
|
};
|
|
|
|
const handleSubmit = (e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
if (item1.trim() && item2.trim()) {
|
|
onSubmit(item1.trim(), item2.trim(), description1.trim(), description2.trim());
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
<div className="text-center mb-6">
|
|
<h2 className="text-2xl font-bold text-gray-900 mb-2">Start Your Comparison</h2>
|
|
<p className="text-gray-600 mb-4">Enter any two items you want to compare - products, services, concepts, or ideas</p>
|
|
<button
|
|
type="button"
|
|
onClick={fillRandomExample}
|
|
className="text-blue-600 hover:text-blue-800 text-sm font-medium underline"
|
|
>
|
|
Try a random example
|
|
</button>
|
|
</div>
|
|
|
|
<form onSubmit={handleSubmit} className="space-y-6">
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
<div>
|
|
<label htmlFor="item1" className="block text-sm font-medium text-gray-700 mb-2">
|
|
First Item
|
|
</label>
|
|
<div className="relative">
|
|
<input
|
|
type="text"
|
|
id="item1"
|
|
value={item1}
|
|
onChange={(e) => setItem1(e.target.value)}
|
|
placeholder="e.g., iPhone 15 Pro, React, Tesla Model 3"
|
|
className={`w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200 ${isLoading ? 'bg-gray-50 cursor-not-allowed' : 'bg-white'}`}
|
|
disabled={isLoading}
|
|
required
|
|
/>
|
|
{isLoading && (
|
|
<div className="absolute inset-0 flex items-center justify-center bg-gray-50 bg-opacity-75 rounded-lg">
|
|
<div className="animate-spin rounded-full h-5 w-5 border-b-2 border-blue-600"></div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<label htmlFor="item2" className="block text-sm font-medium text-gray-700 mb-2">
|
|
Second Item
|
|
</label>
|
|
<div className="relative">
|
|
<input
|
|
type="text"
|
|
id="item2"
|
|
value={item2}
|
|
onChange={(e) => setItem2(e.target.value)}
|
|
placeholder="e.g., Samsung Galaxy S24, Vue.js, BMW i4"
|
|
className={`w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200 ${isLoading ? 'bg-gray-50 cursor-not-allowed' : 'bg-white'}`}
|
|
disabled={isLoading}
|
|
required
|
|
/>
|
|
{isLoading && (
|
|
<div className="absolute inset-0 flex items-center justify-center bg-gray-50 bg-opacity-75 rounded-lg">
|
|
<div className="animate-spin rounded-full h-5 w-5 border-b-2 border-blue-600"></div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="text-center">
|
|
<button
|
|
type="button"
|
|
onClick={() => setShowDescriptions(!showDescriptions)}
|
|
className="text-blue-600 hover:text-blue-800 text-sm font-medium"
|
|
>
|
|
{showDescriptions ? 'Hide' : 'Add'} additional descriptions
|
|
</button>
|
|
</div>
|
|
|
|
{showDescriptions && (
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
<div>
|
|
<label htmlFor="description1" className="block text-sm font-medium text-gray-700 mb-2">
|
|
Description for {item1 || 'First Item'}
|
|
</label>
|
|
<div className="relative">
|
|
<textarea
|
|
id="description1"
|
|
value={description1}
|
|
onChange={(e) => setDescription1(e.target.value)}
|
|
placeholder="Additional details, specifications, or context about the first item..."
|
|
rows={3}
|
|
className={`w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200 ${isLoading ? 'bg-gray-50 cursor-not-allowed' : 'bg-white'}`}
|
|
disabled={isLoading}
|
|
/>
|
|
{isLoading && (
|
|
<div className="absolute inset-0 flex items-center justify-center bg-gray-50 bg-opacity-75 rounded-lg">
|
|
<div className="animate-spin rounded-full h-5 w-5 border-b-2 border-blue-600"></div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<label htmlFor="description2" className="block text-sm font-medium text-gray-700 mb-2">
|
|
Description for {item2 || 'Second Item'}
|
|
</label>
|
|
<div className="relative">
|
|
<textarea
|
|
id="description2"
|
|
value={description2}
|
|
onChange={(e) => setDescription2(e.target.value)}
|
|
placeholder="Additional details, specifications, or context about the second item..."
|
|
rows={3}
|
|
className={`w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200 ${isLoading ? 'bg-gray-50 cursor-not-allowed' : 'bg-white'}`}
|
|
disabled={isLoading}
|
|
/>
|
|
{isLoading && (
|
|
<div className="absolute inset-0 flex items-center justify-center bg-gray-50 bg-opacity-75 rounded-lg">
|
|
<div className="animate-spin rounded-full h-5 w-5 border-b-2 border-blue-600"></div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
<div className="text-center">
|
|
<button
|
|
type="submit"
|
|
disabled={isLoading || !item1.trim() || !item2.trim()}
|
|
className="px-8 py-4 bg-blue-600 text-white font-medium rounded-lg hover:bg-blue-700 focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed transition-all duration-200 flex items-center justify-center gap-2 mx-auto"
|
|
>
|
|
{isLoading ? (
|
|
<>
|
|
<div className="animate-spin rounded-full h-5 w-5 border-b-2 border-white"></div>
|
|
Analyzing & Comparing...
|
|
</>
|
|
) : (
|
|
'Compare Now'
|
|
)}
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
);
|
|
} |