← back to Watches

public/price-history.html

342 lines

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Omega Watch Price History</title>
    <script src="https://cdn.jsdelivr.net/npm/chart.js@4.5.1/dist/chart.umd.min.js"></script>
    <script src="https://cdn.tailwindcss.com"></script>
    <style>
        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
        }
    </style>
</head>
<body class="bg-gray-100 min-h-screen">
    <div class="max-w-7xl mx-auto p-6 space-y-6">
        <div class="bg-white rounded-lg shadow-lg p-6">
            <h1 class="text-3xl font-bold text-gray-800 mb-6">Omega Watch Price History</h1>
            
            <!-- Dropdowns -->
            <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6">
                <div>
                    <label for="model-select" class="block text-sm font-semibold text-gray-700 mb-2">
                        Model
                    </label>
                    <select
                        id="model-select"
                        class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-gray-800 bg-white"
                    >
                        <option value="">Loading models...</option>
                    </select>
                </div>

                <div>
                    <label for="year-select" class="block text-sm font-semibold text-gray-700 mb-2">
                        Year (Show data up to)
                    </label>
                    <select
                        id="year-select"
                        class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-gray-800 bg-white"
                        disabled
                    >
                        <option value="">Select a model first</option>
                    </select>
                </div>
            </div>

            <!-- Watch Info -->
            <div id="watch-info" class="bg-gray-50 rounded-lg p-4 mb-6 hidden">
                <div class="grid grid-cols-1 md:grid-cols-3 gap-4">
                    <div>
                        <span class="text-sm text-gray-600">Collection:</span>
                        <p id="collection" class="font-semibold text-gray-800"></p>
                    </div>
                    <div>
                        <span class="text-sm text-gray-600">Reference:</span>
                        <p id="reference" class="font-semibold text-gray-800"></p>
                    </div>
                    <div>
                        <span class="text-sm text-gray-600">Year Introduced:</span>
                        <p id="year-introduced" class="font-semibold text-gray-800"></p>
                    </div>
                </div>
                <div id="description-container" class="mt-4 hidden">
                    <span class="text-sm text-gray-600">Description:</span>
                    <p id="description" class="text-gray-800 mt-1"></p>
                </div>
            </div>

            <!-- Chart -->
            <div class="bg-white rounded-lg p-6 border border-gray-200">
                <div class="h-96">
                    <canvas id="priceChart"></canvas>
                </div>
            </div>

            <!-- Legend Info -->
            <div class="bg-blue-50 rounded-lg p-4 mt-4">
                <h3 class="font-semibold text-gray-800 mb-2">Chart Information:</h3>
                <ul class="space-y-1 text-sm text-gray-700">
                    <li><span class="font-semibold text-blue-600">Blue Line:</span> Retail prices for new watches</li>
                    <li><span class="font-semibold text-red-600">Red Line:</span> Confirmed auction sales (vintage/used condition)</li>
                    <li class="mt-2 text-gray-600">Data shows prices up to the selected year</li>
                </ul>
            </div>
        </div>
    </div>

    <script type="module">
        let watchesData = null;
        let chartInstance = null;
        const modelSelect = document.getElementById('model-select');
        const yearSelect = document.getElementById('year-select');
        const watchInfo = document.getElementById('watch-info');
        const chartCanvas = document.getElementById('priceChart');

        // Load watches data
        async function loadWatchesData() {
            try {
                const response = await fetch('/data/omega-watches-expanded-v3.json');
                const data = await response.json();
                watchesData = data.watches;
                
                // Populate model dropdown
                const watchesList = Object.entries(watchesData).map(([key, value]) => ({
                    id: key,
                    ...value
                }));
                
                modelSelect.innerHTML = '<option value="">Select a model...</option>';
                watchesList.forEach(watch => {
                    const option = document.createElement('option');
                    option.value = watch.id;
                    option.textContent = `${watch.name} (${watch.collection})`;
                    modelSelect.appendChild(option);
                });
            } catch (error) {
                console.error('Error loading watches data:', error);
                modelSelect.innerHTML = '<option value="">Error loading data</option>';
            }
        }

        // Update year dropdown when model changes
        modelSelect.addEventListener('change', (e) => {
            const selectedModelId = e.target.value;
            if (!selectedModelId || !watchesData) return;

            const watch = watchesData[selectedModelId];
            if (!watch || !watch.priceHistory) return;

            // Update watch info
            document.getElementById('collection').textContent = watch.collection || 'N/A';
            document.getElementById('reference').textContent = watch.reference || 'N/A';
            document.getElementById('year-introduced').textContent = watch.year_introduced || 'N/A';
            
            if (watch.description) {
                document.getElementById('description').textContent = watch.description;
                document.getElementById('description-container').classList.remove('hidden');
            } else {
                document.getElementById('description-container').classList.add('hidden');
            }
            
            watchInfo.classList.remove('hidden');

            // Get unique years
            const years = [...new Set(watch.priceHistory.map(p => p.year))].sort((a, b) => a - b);
            
            yearSelect.innerHTML = '';
            years.forEach(year => {
                const option = document.createElement('option');
                option.value = year.toString();
                option.textContent = year.toString();
                yearSelect.appendChild(option);
            });
            
            yearSelect.disabled = false;
            if (years.length > 0) {
                yearSelect.value = years[years.length - 1].toString();
                updateChart();
            }
        });

        // Update chart when year changes
        yearSelect.addEventListener('change', () => {
            updateChart();
        });

        // Update chart
        function updateChart() {
            const selectedModelId = modelSelect.value;
            const selectedYear = parseInt(yearSelect.value);
            
            if (!selectedModelId || !selectedYear || !watchesData) return;

            const watch = watchesData[selectedModelId];
            if (!watch || !watch.priceHistory) return;

            // Filter data up to selected year
            const filteredHistory = watch.priceHistory.filter(p => p.year <= selectedYear);

            // Separate retail prices (new condition) and auction sales (vintage/other)
            const retailPrices = filteredHistory
                .filter(p => p.condition === 'new')
                .map(p => ({ year: p.year, price: p.price }));

            const auctionSales = filteredHistory
                .filter(p => p.condition !== 'new' && (p.condition === 'vintage' || p.condition === 'used' || p.condition === 'auction'))
                .map(p => ({ year: p.year, price: p.price }));

            // Get all unique years
            const allYears = [...new Set([...retailPrices.map(p => p.year), ...auctionSales.map(p => p.year)])].sort((a, b) => a - b);
            
            const retailData = allYears.map(year => {
                const entry = retailPrices.find(p => p.year === year);
                return entry ? entry.price : null;
            });

            const auctionData = allYears.map(year => {
                const entry = auctionSales.find(p => p.year === year);
                return entry ? entry.price : null;
            });

            // Destroy previous chart
            if (chartInstance) {
                chartInstance.destroy();
            }

            // Create new chart
            chartInstance = new Chart(chartCanvas, {
                type: 'line',
                data: {
                    labels: allYears,
                    datasets: [
                        {
                            label: 'Retail Price (New)',
                            data: retailData,
                            borderColor: '#2563eb',
                            backgroundColor: 'rgba(37, 99, 235, 0.1)',
                            borderWidth: 3,
                            fill: true,
                            tension: 0.4,
                            pointRadius: 6,
                            pointHoverRadius: 8,
                            pointBackgroundColor: '#2563eb',
                            pointBorderColor: '#fff',
                            pointBorderWidth: 2,
                            spanGaps: false
                        },
                        {
                            label: 'Auction Sales (Vintage/Used)',
                            data: auctionData,
                            borderColor: '#dc2626',
                            backgroundColor: 'rgba(220, 38, 38, 0.1)',
                            borderWidth: 3,
                            fill: true,
                            tension: 0.4,
                            pointRadius: 6,
                            pointHoverRadius: 8,
                            pointBackgroundColor: '#dc2626',
                            pointBorderColor: '#fff',
                            pointBorderWidth: 2,
                            spanGaps: false
                        }
                    ]
                },
                options: {
                    responsive: true,
                    maintainAspectRatio: false,
                    plugins: {
                        legend: {
                            display: true,
                            position: 'top',
                            labels: {
                                font: {
                                    size: 14,
                                    weight: 'bold'
                                },
                                padding: 15,
                                usePointStyle: true
                            }
                        },
                        tooltip: {
                            backgroundColor: 'rgba(0, 0, 0, 0.8)',
                            titleFont: {
                                size: 14,
                                weight: 'bold'
                            },
                            bodyFont: {
                                size: 13
                            },
                            padding: 12,
                            callbacks: {
                                label: function(context) {
                                    if (context.parsed.y === null) {
                                        return context.dataset.label + ': No data';
                                    }
                                    return context.dataset.label + ': $' + context.parsed.y.toLocaleString();
                                }
                            }
                        },
                        title: {
                            display: true,
                            text: watch.name + ' - Price History',
                            font: {
                                size: 18,
                                weight: 'bold'
                            },
                            padding: 20
                        }
                    },
                    scales: {
                        y: {
                            beginAtZero: false,
                            ticks: {
                                callback: function(value) {
                                    return '$' + value.toLocaleString();
                                },
                                font: {
                                    size: 12
                                }
                            },
                            grid: {
                                color: 'rgba(0, 0, 0, 0.1)'
                            },
                            title: {
                                display: true,
                                text: 'Price (USD)',
                                font: {
                                    size: 14,
                                    weight: 'bold'
                                }
                            }
                        },
                        x: {
                            ticks: {
                                font: {
                                    size: 12
                                }
                            },
                            grid: {
                                display: false
                            },
                            title: {
                                display: true,
                                text: 'Year',
                                font: {
                                    size: 14,
                                    weight: 'bold'
                                }
                            }
                        }
                    }
                }
            });
        }

        // Initialize
        loadWatchesData();
    </script>
</body>
</html>