Spaces:
Sleeping
Sleeping
| import { useState } from 'react'; | |
| import { motion } from 'motion/react'; | |
| import { Bot, User, Crown, Sparkles, MessageSquare } from 'lucide-react'; | |
| import { Button } from './ui/button'; | |
| import { FeedbackPopup } from './FeedbackPopup'; | |
| export interface MessageProps { | |
| content: string; | |
| isUser: boolean; | |
| timestamp: Date; | |
| isPlusResponse?: boolean; | |
| isUnivAiPlusMode?: boolean; | |
| } | |
| export function Message({ content, isUser, timestamp, isPlusResponse, isUnivAiPlusMode }: MessageProps) { | |
| const [showFeedback, setShowFeedback] = useState(false); | |
| return ( | |
| <> | |
| <motion.div | |
| initial={{ opacity: 0, y: 20 }} | |
| animate={{ opacity: 1, y: 0 }} | |
| transition={{ duration: 0.3 }} | |
| className={`flex items-start gap-3 mb-4 ${isUser ? 'flex-row-reverse' : 'flex-row'}`} | |
| > | |
| <div className={` | |
| flex-shrink-0 w-10 h-10 rounded-full flex items-center justify-center relative transition-all duration-300 | |
| ${isUser | |
| ? isUnivAiPlusMode | |
| ? 'bg-gradient-to-r from-purple-500 to-purple-600 text-white shadow-lg shadow-purple-500/30' | |
| : 'bg-gradient-to-r from-red-500 to-red-600 text-white shadow-lg shadow-red-500/30' | |
| : isPlusResponse | |
| ? 'bg-gradient-to-r from-purple-400 to-pink-500 text-white shadow-lg shadow-purple-500/30' | |
| : isUnivAiPlusMode | |
| ? 'bg-gradient-to-r from-purple-400 to-pink-500 text-white shadow-lg shadow-purple-500/30' | |
| : 'bg-gradient-to-r from-yellow-400 to-orange-500 text-white shadow-lg shadow-yellow-500/30' | |
| } | |
| `}> | |
| {isUser ? ( | |
| <User size={20} /> | |
| ) : isPlusResponse ? ( | |
| <Crown size={20} /> | |
| ) : isUnivAiPlusMode ? ( | |
| <Crown size={20} /> | |
| ) : ( | |
| <Bot size={20} /> | |
| )} | |
| {/* Premium indicator sparkle */} | |
| {isPlusResponse && ( | |
| <motion.div | |
| initial={{ scale: 0, opacity: 0 }} | |
| animate={{ scale: 1, opacity: 1 }} | |
| className="absolute -top-1 -right-1 w-4 h-4 bg-gradient-to-r from-amber-400 to-yellow-500 rounded-full flex items-center justify-center" | |
| > | |
| <Sparkles size={10} className="text-white" /> | |
| </motion.div> | |
| )} | |
| </div> | |
| <div className={`flex flex-col max-w-[70%] ${isUser ? 'items-end' : 'items-start'}`}> | |
| {/* Premium response indicator - moved outside and above the message bubble */} | |
| {isPlusResponse && ( | |
| <motion.div | |
| initial={{ opacity: 0, scale: 0.8 }} | |
| animate={{ opacity: 1, scale: 1 }} | |
| className="flex items-center gap-1 px-3 py-1 mb-2 bg-gradient-to-r from-purple-500 to-pink-500 text-white text-xs rounded-full shadow-lg mr-4" | |
| > | |
| <Crown size={12} /> | |
| <span>Premium Response</span> | |
| </motion.div> | |
| )} | |
| <div className={` | |
| px-4 py-3 rounded-2xl backdrop-blur-sm border shadow-sm transition-all duration-300 relative | |
| ${isUser | |
| ? isUnivAiPlusMode | |
| ? 'bg-gradient-to-r from-purple-50 to-purple-100 border-purple-200 text-purple-900 ml-4' | |
| : 'bg-gradient-to-r from-red-50 to-red-100 border-red-200 text-red-900 ml-4' | |
| : isPlusResponse | |
| ? 'bg-gradient-to-r from-purple-50 via-pink-50 to-amber-50 border-purple-300 text-purple-900 mr-4 shadow-lg shadow-purple-200/50' | |
| : isUnivAiPlusMode | |
| ? 'bg-gradient-to-r from-white to-purple-50 border-purple-200 text-purple-900 mr-4' | |
| : 'bg-gradient-to-r from-white to-yellow-50 border-yellow-200 text-red-900 mr-4' | |
| } | |
| `}> | |
| <p className="whitespace-pre-wrap"> | |
| {content} | |
| </p> | |
| </div> | |
| <div className={`flex items-center gap-2 mt-1 px-2 ${isUser ? 'flex-row-reverse' : 'flex-row'}`}> | |
| <span className={`text-xs transition-all duration-300 ${ | |
| isUnivAiPlusMode | |
| ? 'text-purple-600/60' | |
| : 'text-red-600/60' | |
| }`}> | |
| {timestamp.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })} | |
| {isPlusResponse && <span className="ml-2 text-purple-600/80">• Premium</span>} | |
| </span> | |
| {/* Feedback button for bot responses */} | |
| {!isUser && ( | |
| <Button | |
| variant="ghost" | |
| size="sm" | |
| onClick={() => setShowFeedback(true)} | |
| className={`text-xs p-1 h-6 transition-all duration-300 opacity-60 hover:opacity-100 ${ | |
| isUnivAiPlusMode | |
| ? 'hover:bg-purple-100 text-purple-600 dark:hover:bg-purple-900/30 dark:text-purple-400' | |
| : 'hover:bg-red-100 text-red-600 dark:hover:bg-red-900/30 dark:text-red-400' | |
| }`} | |
| > | |
| <MessageSquare size={12} /> | |
| </Button> | |
| )} | |
| </div> | |
| </div> | |
| </motion.div> | |
| {/* Feedback Popup */} | |
| <FeedbackPopup | |
| isOpen={showFeedback} | |
| onClose={() => setShowFeedback(false)} | |
| messageId={`msg-${timestamp.getTime()}`} | |
| isUnivAiPlusMode={isUnivAiPlusMode} | |
| /> | |
| </> | |
| ); | |
| } |