← back to Watches

src/components/FavoritesManager.jsx

147 lines

import React from 'react';
import { motion } from 'framer-motion';
import { FiHeart, FiShare2, FiDownload } from 'react-icons/fi';
import { useLocalStorage } from '../hooks/useLocalStorage';

/**
 * Favorites/Watchlist manager with localStorage persistence
 * Features: Add/remove favorites, share links, export data
 */
export function useFavorites() {
  const [favorites, setFavorites] = useLocalStorage('omega-favorites', []);

  const toggleFavorite = (watchId) => {
    setFavorites(prev =>
      prev.includes(watchId)
        ? prev.filter(id => id !== watchId)
        : [...prev, watchId]
    );
  };

  const isFavorite = (watchId) => favorites.includes(watchId);

  const clearFavorites = () => setFavorites([]);

  return { favorites, toggleFavorite, isFavorite, clearFavorites };
}

/**
 * Favorite button component
 */
export function FavoriteButton({ watchId, isFavorite, onToggle, className = '' }) {
  return (
    <motion.button
      whileHover={{ scale: 1.1 }}
      whileTap={{ scale: 0.9 }}
      onClick={(e) => {
        e.stopPropagation();
        onToggle(watchId);
      }}
      className={`p-2 rounded-full transition-colors ${className} ${
        isFavorite
          ? 'bg-omega-red text-white hover:bg-red-700'
          : 'bg-gray-200 dark:bg-gray-700 text-gray-600 dark:text-gray-300 hover:bg-gray-300 dark:hover:bg-gray-600'
      }`}
      title={isFavorite ? 'Remove from favorites' : 'Add to favorites'}
    >
      <FiHeart className={isFavorite ? 'fill-current' : ''} />
    </motion.button>
  );
}

/**
 * Share watch link button
 */
export function ShareButton({ watch, className = '' }) {
  const handleShare = async (e) => {
    e.stopPropagation();

    const url = `${window.location.origin}?watch=${watch.id}`;
    const text = `Check out this ${watch.model} by Omega`;

    if (navigator.share) {
      try {
        await navigator.share({ title: watch.model, text, url });
      } catch (err) {
        if (err.name !== 'AbortError') {
          copyToClipboard(url);
        }
      }
    } else {
      copyToClipboard(url);
    }
  };

  const copyToClipboard = (text) => {
    navigator.clipboard.writeText(text).then(() => {
      alert('Link copied to clipboard!');
    });
  };

  return (
    <motion.button
      whileHover={{ scale: 1.1 }}
      whileTap={{ scale: 0.9 }}
      onClick={handleShare}
      className={`p-2 rounded-full bg-blue-500 text-white hover:bg-blue-600 transition-colors ${className}`}
      title="Share this watch"
    >
      <FiShare2 />
    </motion.button>
  );
}

/**
 * Export watch data button
 */
export function ExportButton({ watch, format = 'json', className = '' }) {
  const handleExport = (e) => {
    e.stopPropagation();

    if (format === 'json') {
      exportJSON(watch);
    } else if (format === 'csv') {
      exportCSV(watch);
    }
  };

  const exportJSON = (watch) => {
    const data = JSON.stringify(watch, null, 2);
    const blob = new Blob([data], { type: 'application/json' });
    downloadBlob(blob, `${watch.reference}-data.json`);
  };

  const exportCSV = (watch) => {
    const headers = ['Date', 'Price'];
    const rows = watch.priceHistory.map(p => [p.date, p.price]);
    const csv = [headers, ...rows].map(row => row.join(',')).join('\n');
    const blob = new Blob([csv], { type: 'text/csv' });
    downloadBlob(blob, `${watch.reference}-prices.csv`);
  };

  const downloadBlob = (blob, filename) => {
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = filename;
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
    URL.revokeObjectURL(url);
  };

  return (
    <motion.button
      whileHover={{ scale: 1.1 }}
      whileTap={{ scale: 0.9 }}
      onClick={handleExport}
      className={`p-2 rounded-full bg-green-500 text-white hover:bg-green-600 transition-colors ${className}`}
      title={`Export as ${format.toUpperCase()}`}
    >
      <FiDownload />
    </motion.button>
  );
}

export default { useFavorites, FavoriteButton, ShareButton, ExportButton };