← back to Watches

src/components/affiliate/OmegaPriceChart.jsx

180 lines

/**
 * OMEGA Price Chart - TradingView Style
 * Real-time price tracking with historical data
 */

import React, { useEffect, useRef } from 'react';
import { createChart } from 'lightweight-charts';

export default function OmegaPriceChart({ data, title = 'OMEGA Price History', model = '' }) {
  const chartContainerRef = useRef();
  const chartRef = useRef(null);

  useEffect(() => {
    if (!chartContainerRef.current) return;

    // Create chart instance
    const chart = createChart(chartContainerRef.current, {
      width: chartContainerRef.current.clientWidth,
      height: 400,
      layout: {
        background: { color: '#0f172a' },
        textColor: '#94a3b8',
      },
      grid: {
        vertLines: { color: '#1e293b' },
        horzLines: { color: '#1e293b' },
      },
      crosshair: {
        mode: 1,
      },
      rightPriceScale: {
        borderColor: '#334155',
      },
      timeScale: {
        borderColor: '#334155',
        timeVisible: true,
        secondsVisible: false,
      },
    });

    // Add line series
    const lineSeries = chart.addLineSeries({
      color: '#f59e0b',
      lineWidth: 2,
      crosshairMarkerVisible: true,
      crosshairMarkerRadius: 6,
      crosshairMarkerBorderColor: '#f59e0b',
      crosshairMarkerBackgroundColor: '#ffffff',
      lastValueVisible: true,
      priceLineVisible: true,
    });

    // Add area series for fill
    const areaSeries = chart.addAreaSeries({
      topColor: 'rgba(245, 158, 11, 0.4)',
      bottomColor: 'rgba(245, 158, 11, 0.0)',
      lineColor: 'rgba(245, 158, 11, 0.8)',
      lineWidth: 2,
    });

    // Set data
    if (data && data.length > 0) {
      lineSeries.setData(data);
      areaSeries.setData(data);

      // Fit content
      chart.timeScale().fitContent();
    }

    chartRef.current = chart;

    // Handle resize
    const handleResize = () => {
      if (chartContainerRef.current && chartRef.current) {
        chartRef.current.applyOptions({
          width: chartContainerRef.current.clientWidth,
        });
      }
    };

    window.addEventListener('resize', handleResize);

    return () => {
      window.removeEventListener('resize', handleResize);
      if (chartRef.current) {
        chartRef.current.remove();
        chartRef.current = null;
      }
    };
  }, [data]);

  // Calculate stats
  const stats = data && data.length > 0 ? {
    current: data[data.length - 1].value,
    start: data[0].value,
    change: data[data.length - 1].value - data[0].value,
    changePercent: ((data[data.length - 1].value - data[0].value) / data[0].value) * 100,
    high: Math.max(...data.map(d => d.value)),
    low: Math.min(...data.map(d => d.value)),
  } : null;

  return (
    <div className="bg-gradient-to-br from-slate-900 to-slate-800 rounded-xl p-6 border border-slate-700">
      {/* Header */}
      <div className="mb-4">
        <div className="flex items-center justify-between mb-2">
          <div>
            <h3 className="text-xl font-bold text-white">{title}</h3>
            {model && <p className="text-sm text-slate-400">{model}</p>}
          </div>
          {stats && (
            <div className="text-right">
              <div className="text-2xl font-bold text-amber-400">
                ${stats.current.toLocaleString()}
              </div>
              <div className={`text-sm font-semibold ${stats.change >= 0 ? 'text-green-400' : 'text-red-400'}`}>
                {stats.change >= 0 ? '+' : ''}${stats.change.toLocaleString()} ({stats.changePercent >= 0 ? '+' : ''}{stats.changePercent.toFixed(2)}%)
              </div>
            </div>
          )}
        </div>

        {/* Stats Bar */}
        {stats && (
          <div className="grid grid-cols-4 gap-3 mt-4">
            <div className="bg-slate-800 rounded-lg p-2 text-center">
              <div className="text-xs text-slate-400">Current</div>
              <div className="text-sm font-bold text-white">${stats.current.toLocaleString()}</div>
            </div>
            <div className="bg-slate-800 rounded-lg p-2 text-center">
              <div className="text-xs text-slate-400">High</div>
              <div className="text-sm font-bold text-green-400">${stats.high.toLocaleString()}</div>
            </div>
            <div className="bg-slate-800 rounded-lg p-2 text-center">
              <div className="text-xs text-slate-400">Low</div>
              <div className="text-sm font-bold text-red-400">${stats.low.toLocaleString()}</div>
            </div>
            <div className="bg-slate-800 rounded-lg p-2 text-center">
              <div className="text-xs text-slate-400">Change</div>
              <div className={`text-sm font-bold ${stats.changePercent >= 0 ? 'text-green-400' : 'text-red-400'}`}>
                {stats.changePercent >= 0 ? '+' : ''}{stats.changePercent.toFixed(1)}%
              </div>
            </div>
          </div>
        )}
      </div>

      {/* Chart */}
      <div ref={chartContainerRef} className="w-full" />

      {/* Data Source */}
      <div className="mt-3 text-xs text-slate-500 text-center">
        Data sources: Chrono24, WatchCharts, eBay, WatchBox
      </div>
    </div>
  );
}

// Sample data generator for testing
export function generateSampleData(model = 'Speedmaster Professional') {
  const startDate = new Date('2020-01-01');
  const dataPoints = [];
  let basePrice = 4200;

  for (let i = 0; i < 60; i++) {
    const date = new Date(startDate);
    date.setMonth(date.getMonth() + i);

    // Simulate realistic price appreciation
    basePrice += (Math.random() - 0.4) * 150; // Slight upward trend

    dataPoints.push({
      time: date.toISOString().split('T')[0],
      value: Math.round(basePrice)
    });
  }

  return dataPoints;
}