T.ME/BIBIL_0DAY
CasperSecurity


Server : Apache/2
System : Linux server-15-235-50-60 5.15.0-164-generic #174-Ubuntu SMP Fri Nov 14 20:25:16 UTC 2025 x86_64
User : gositeme ( 1004)
PHP Version : 8.2.29
Disable Function : exec,system,passthru,shell_exec,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname
Directory :  /home/gositeme/domains/lavocat.quebec/private_html/src/components/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : /home/gositeme/domains/lavocat.quebec/private_html/src/components/ReactionPicker.tsx
import React, { useState } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import { Smile, Heart, Laugh, Frown, Angry, Zap, ThumbsUp, ThumbsDown, Star, Shield, Scale, Gavel } from 'lucide-react';

interface Reaction {
  type: string;
  emoji: string;
  icon: React.ReactNode;
  color: string;
  label: string;
}

interface ReactionPickerProps {
  onReaction: (reactionType: string) => void;
  currentReactions: Array<{
    reactionType: string;
    count: number;
    userReacted: boolean;
  }>;
  commentId: string;
  className?: string;
}

const REACTIONS: Reaction[] = [
  {
    type: 'like',
    emoji: '👍',
    icon: <ThumbsUp className="h-4 w-4" />,
    color: 'bg-blue-500 hover:bg-blue-600',
    label: 'Like'
  },
  {
    type: 'love',
    emoji: '❤️',
    icon: <Heart className="h-4 w-4" />,
    color: 'bg-red-500 hover:bg-red-600',
    label: 'Love'
  },
  {
    type: 'laugh',
    emoji: '😂',
    icon: <Laugh className="h-4 w-4" />,
    color: 'bg-yellow-500 hover:bg-yellow-600',
    label: 'Laugh'
  },
  {
    type: 'wow',
    emoji: '😮',
    icon: <Zap className="h-4 w-4" />,
    color: 'bg-purple-500 hover:bg-purple-600',
    label: 'Wow'
  },
  {
    type: 'sad',
    emoji: '😢',
    icon: <Frown className="h-4 w-4" />,
    color: 'bg-gray-500 hover:bg-gray-600',
    label: 'Sad'
  },
  {
    type: 'angry',
    emoji: '😠',
    icon: <Angry className="h-4 w-4" />,
    color: 'bg-orange-500 hover:bg-orange-600',
    label: 'Angry'
  },
  {
    type: 'dislike',
    emoji: '👎',
    icon: <ThumbsDown className="h-4 w-4" />,
    color: 'bg-red-600 hover:bg-red-700',
    label: 'Dislike'
  },
  {
    type: 'star',
    emoji: '⭐',
    icon: <Star className="h-4 w-4" />,
    color: 'bg-yellow-400 hover:bg-yellow-500',
    label: 'Star'
  },
  {
    type: 'justice',
    emoji: '⚖️',
    icon: <Scale className="h-4 w-4" />,
    color: 'bg-green-600 hover:bg-green-700',
    label: 'Justice'
  },
  {
    type: 'gavel',
    emoji: '🔨',
    icon: <Gavel className="h-4 w-4" />,
    color: 'bg-gray-700 hover:bg-gray-800',
    label: 'Gavel'
  },
  {
    type: 'shield',
    emoji: '🛡️',
    icon: <Shield className="h-4 w-4" />,
    color: 'bg-blue-700 hover:bg-blue-800',
    label: 'Protect'
  }
];

const ReactionPicker: React.FC<ReactionPickerProps> = ({
  onReaction,
  currentReactions,
  commentId,
  className = ''
}) => {
  const [isOpen, setIsOpen] = useState(false);
  const [hoveredReaction, setHoveredReaction] = useState<string | null>(null);

  const handleReaction = (reactionType: string) => {
    onReaction(reactionType);
    setIsOpen(false);
  };

  const getReactionCount = (type: string) => {
    const reaction = currentReactions.find(r => r.reactionType === type);
    return reaction?.count || 0;
  };

  const hasUserReacted = (type: string) => {
    const reaction = currentReactions.find(r => r.reactionType === type);
    return reaction?.userReacted || false;
  };

  const getTopReactions = () => {
    return currentReactions
      .filter(r => r.count > 0)
      .sort((a, b) => b.count - a.count)
      .slice(0, 3);
  };

  return (
    <div className={`relative ${className}
      {/* Reaction Display */}
      <div className="flex items-center gap-1">
        {getTopReactions().map((reaction) => {
          const reactionData = REACTIONS.find(r => r.type === reaction.reactionType);
          if (!reactionData) return null;

          return (
            <motion.button
              key={reaction.reactionType}
              onClick={() => handleReaction(reaction.reactionType)}
              className={
                reaction.userReacted 
                  ? 'bg-blue-100 text-blue-700 border border-blue-200' 
                  : 'bg-gray-100 text-gray-600 hover:bg-gray-200'
              }
              whileHover={{ scale: 1.05 }}
              whileTap={{ scale: 0.95 }}
            >
              <span className="text-sm">{reactionData.emoji}</span>
              <span className="font-medium">{reaction.count}</span>
            </motion.button>
          );
        })}

        {/* Reaction Picker Toggle */}
        <motion.button
          onClick={() => setIsOpen(!isOpen)}
          className="flex items-center gap-1 px-2 py-1 rounded-full text-gray-500 hover:text-gray-700 hover:bg-gray-100 transition-colors"
          whileHover={{ scale: 1.05 }}
          whileTap={{ scale: 0.95 }}
        >
          <Smile className="h-4 w-4" />
        </motion.button>
      </div>

      {/* Reaction Picker Popup */}
      <AnimatePresence>
        {isOpen && (
          <motion.div
            initial={{ opacity: 0, scale: 0.8, y: 10 }}
            animate={{ opacity: 1, scale: 1, y: 0 }}
            exit={{ opacity: 0, scale: 0.8, y: 10 }}
            className="absolute bottom-full left-0 mb-2 bg-white rounded-lg shadow-lg border border-gray-200 p-2 z-50"
          >
            <div className="grid grid-cols-4 gap-1">
              {REACTIONS.map((reaction) => (
                <motion.button
                  key={reaction.type}
                  onClick={() => handleReaction(reaction.type)}
                  onMouseEnter={() => setHoveredReaction(reaction.type)}
                  onMouseLeave={() => setHoveredReaction(null)}
                  className={
                    hasUserReacted(reaction.type) 
                      ? 'bg-blue-100 text-blue-700' 
                      : 'hover:bg-gray-100 text-gray-600'
                  }
                  whileHover={{ scale: 1.2 }}
                  whileTap={{ scale: 0.9 }}
                >
                  <span className="text-lg">{reaction.emoji}</span>
                  
                  {/* Tooltip */}
                  <AnimatePresence>
                    {hoveredReaction === reaction.type && (
                      <motion.div
                        initial={{ opacity: 0, y: 5 }}
                        animate={{ opacity: 1, y: 0 }}
                        exit={{ opacity: 0, y: 5 }}
                        className="absolute bottom-full left-1/2 transform -translate-x-1/2 mb-1 px-2 py-1 bg-gray-900 text-white text-xs rounded whitespace-nowrap z-10"
                      >
                        {reaction.label}
                        {getReactionCount(reaction.type) > 0 && (
                          <span className="ml-1">({getReactionCount(reaction.type)})</span>
                        )}
                      </motion.div>
                    )}
                  </AnimatePresence>
                </motion.button>
              ))}
            </div>
          </motion.div>
        )}
      </AnimatePresence>

      {/* Backdrop to close picker */}
      {isOpen && (
        <div
          className="fixed inset-0 z-40"
          onClick={() => setIsOpen(false)}
        />
      )}
    </div>
  );
};

export default ReactionPicker; 

CasperSecurity Mini