Spaces:
Sleeping
Sleeping
| import { useState } from 'react'; | |
| import { motion, AnimatePresence } from 'motion/react'; | |
| import { ThumbsUp, ThumbsDown, X, MessageSquare } from 'lucide-react'; | |
| import { Button } from './ui/button'; | |
| import { Textarea } from './ui/textarea'; | |
| interface FeedbackPopupProps { | |
| isOpen: boolean; | |
| onClose: () => void; | |
| messageId: string; | |
| isUnivAiPlusMode?: boolean; | |
| } | |
| export function FeedbackPopup({ isOpen, onClose, messageId, isUnivAiPlusMode }: FeedbackPopupProps) { | |
| const [feedbackType, setFeedbackType] = useState<'positive' | 'negative' | null>(null); | |
| const [comment, setComment] = useState(''); | |
| const [isSubmitted, setIsSubmitted] = useState(false); | |
| const handleSubmit = () => { | |
| // Here you would typically send feedback to your backend | |
| console.log('Feedback submitted:', { messageId, feedbackType, comment }); | |
| setIsSubmitted(true); | |
| setTimeout(() => { | |
| setIsSubmitted(false); | |
| setFeedbackType(null); | |
| setComment(''); | |
| onClose(); | |
| }, 1500); | |
| }; | |
| const handleClose = () => { | |
| setFeedbackType(null); | |
| setComment(''); | |
| setIsSubmitted(false); | |
| onClose(); | |
| }; | |
| return ( | |
| <AnimatePresence> | |
| {isOpen && ( | |
| <> | |
| {/* Backdrop */} | |
| <motion.div | |
| initial={{ opacity: 0 }} | |
| animate={{ opacity: 1 }} | |
| exit={{ opacity: 0 }} | |
| className="fixed inset-0 bg-black/50 backdrop-blur-sm z-50" | |
| onClick={handleClose} | |
| /> | |
| {/* Popup */} | |
| <motion.div | |
| initial={{ opacity: 0, scale: 0.95, y: 20 }} | |
| animate={{ opacity: 1, scale: 1, y: 0 }} | |
| exit={{ opacity: 0, scale: 0.95, y: 20 }} | |
| className={`fixed top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 z-50 w-96 rounded-2xl border backdrop-blur-sm shadow-2xl transition-all duration-300 ${ | |
| isUnivAiPlusMode | |
| ? 'bg-gradient-to-br from-white/95 to-purple-50/95 border-purple-200/50 shadow-purple-500/20' | |
| : 'bg-gradient-to-br from-white/95 to-red-50/95 border-red-200/50 shadow-red-500/20' | |
| }`} | |
| > | |
| {/* Header */} | |
| <div className="flex items-center justify-between p-6 border-b border-current/10"> | |
| <div className="flex items-center gap-3"> | |
| <div className={`w-10 h-10 rounded-full flex items-center justify-center transition-all duration-300 ${ | |
| isUnivAiPlusMode | |
| ? 'bg-gradient-to-r from-purple-500 to-pink-500 shadow-purple-500/30' | |
| : 'bg-gradient-to-r from-red-500 to-orange-500 shadow-red-500/30' | |
| }`}> | |
| <MessageSquare className="text-white" size={20} /> | |
| </div> | |
| <div> | |
| <h3 className={`transition-all duration-300 ${ | |
| isUnivAiPlusMode | |
| ? 'text-purple-900 dark:text-purple-100' | |
| : 'text-red-900 dark:text-red-100' | |
| }`}> | |
| Share Feedback | |
| </h3> | |
| <p className={`text-sm transition-all duration-300 ${ | |
| isUnivAiPlusMode | |
| ? 'text-purple-700/80 dark:text-purple-300/80' | |
| : 'text-red-700/80 dark:text-red-300/80' | |
| }`}> | |
| Help us improve our responses | |
| </p> | |
| </div> | |
| </div> | |
| <Button | |
| variant="ghost" | |
| size="sm" | |
| onClick={handleClose} | |
| className={`transition-all duration-300 ${ | |
| 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' | |
| }`} | |
| > | |
| <X size={18} /> | |
| </Button> | |
| </div> | |
| {/* Content */} | |
| <div className="p-6"> | |
| {!isSubmitted ? ( | |
| <> | |
| {/* Rating */} | |
| <div className="mb-4"> | |
| <p className={`text-sm mb-3 transition-all duration-300 ${ | |
| isUnivAiPlusMode | |
| ? 'text-purple-700/80 dark:text-purple-300/80' | |
| : 'text-red-700/80 dark:text-red-300/80' | |
| }`}> | |
| How was this response? | |
| </p> | |
| <div className="flex gap-3"> | |
| <Button | |
| variant={feedbackType === 'positive' ? 'default' : 'outline'} | |
| size="sm" | |
| onClick={() => setFeedbackType('positive')} | |
| className={`flex items-center gap-2 transition-all duration-300 ${ | |
| feedbackType === 'positive' | |
| ? isUnivAiPlusMode | |
| ? 'bg-gradient-to-r from-purple-500 to-pink-500 text-white shadow-purple-500/30' | |
| : 'bg-gradient-to-r from-red-500 to-orange-500 text-white shadow-red-500/30' | |
| : isUnivAiPlusMode | |
| ? 'border-purple-200 text-purple-700 hover:bg-purple-50 dark:border-purple-600 dark:text-purple-300 dark:hover:bg-purple-900/30' | |
| : 'border-red-200 text-red-700 hover:bg-red-50 dark:border-red-600 dark:text-red-300 dark:hover:bg-red-900/30' | |
| }`} | |
| > | |
| <ThumbsUp size={16} /> | |
| Helpful | |
| </Button> | |
| <Button | |
| variant={feedbackType === 'negative' ? 'default' : 'outline'} | |
| size="sm" | |
| onClick={() => setFeedbackType('negative')} | |
| className={`flex items-center gap-2 transition-all duration-300 ${ | |
| feedbackType === 'negative' | |
| ? isUnivAiPlusMode | |
| ? 'bg-gradient-to-r from-purple-500 to-pink-500 text-white shadow-purple-500/30' | |
| : 'bg-gradient-to-r from-red-500 to-orange-500 text-white shadow-red-500/30' | |
| : isUnivAiPlusMode | |
| ? 'border-purple-200 text-purple-700 hover:bg-purple-50 dark:border-purple-600 dark:text-purple-300 dark:hover:bg-purple-900/30' | |
| : 'border-red-200 text-red-700 hover:bg-red-50 dark:border-red-600 dark:text-red-300 dark:hover:bg-red-900/30' | |
| }`} | |
| > | |
| <ThumbsDown size={16} /> | |
| Not helpful | |
| </Button> | |
| </div> | |
| </div> | |
| {/* Comment */} | |
| <div className="mb-4"> | |
| <p className={`text-sm mb-2 transition-all duration-300 ${ | |
| isUnivAiPlusMode | |
| ? 'text-purple-700/80 dark:text-purple-300/80' | |
| : 'text-red-700/80 dark:text-red-300/80' | |
| }`}> | |
| Additional comments (optional) | |
| </p> | |
| <Textarea | |
| value={comment} | |
| onChange={(e) => setComment(e.target.value)} | |
| placeholder="Tell us more about your experience..." | |
| className={`transition-all duration-300 ${ | |
| isUnivAiPlusMode | |
| ? 'border-purple-200 focus:border-purple-400 dark:border-purple-600' | |
| : 'border-red-200 focus:border-red-400 dark:border-red-600' | |
| }`} | |
| rows={3} | |
| /> | |
| </div> | |
| {/* Actions */} | |
| <div className="flex gap-3 justify-end"> | |
| <Button | |
| variant="outline" | |
| size="sm" | |
| onClick={handleClose} | |
| className={`transition-all duration-300 ${ | |
| isUnivAiPlusMode | |
| ? 'border-purple-200 text-purple-700 hover:bg-purple-50 dark:border-purple-600 dark:text-purple-300 dark:hover:bg-purple-900/30' | |
| : 'border-red-200 text-red-700 hover:bg-red-50 dark:border-red-600 dark:text-red-300 dark:hover:bg-red-900/30' | |
| }`} | |
| > | |
| Cancel | |
| </Button> | |
| <Button | |
| size="sm" | |
| onClick={handleSubmit} | |
| disabled={!feedbackType} | |
| className={`transition-all duration-300 ${ | |
| isUnivAiPlusMode | |
| ? 'bg-gradient-to-r from-purple-500 to-pink-500 hover:from-purple-600 hover:to-pink-600 text-white shadow-purple-500/30' | |
| : 'bg-gradient-to-r from-red-500 to-orange-500 hover:from-red-600 hover:to-orange-600 text-white shadow-red-500/30' | |
| }`} | |
| > | |
| Submit Feedback | |
| </Button> | |
| </div> | |
| </> | |
| ) : ( | |
| /* Success state */ | |
| <motion.div | |
| initial={{ opacity: 0, y: 10 }} | |
| animate={{ opacity: 1, y: 0 }} | |
| className="text-center py-4" | |
| > | |
| <div className={`w-16 h-16 rounded-full flex items-center justify-center mx-auto mb-4 transition-all duration-300 ${ | |
| isUnivAiPlusMode | |
| ? 'bg-gradient-to-r from-purple-400 to-pink-500 shadow-purple-500/30' | |
| : 'bg-gradient-to-r from-green-400 to-green-500 shadow-green-500/30' | |
| }`}> | |
| <ThumbsUp className="text-white" size={24} /> | |
| </div> | |
| <h4 className={`mb-2 transition-all duration-300 ${ | |
| isUnivAiPlusMode | |
| ? 'text-purple-900 dark:text-purple-100' | |
| : 'text-red-900 dark:text-red-100' | |
| }`}> | |
| Thank you! | |
| </h4> | |
| <p className={`text-sm transition-all duration-300 ${ | |
| isUnivAiPlusMode | |
| ? 'text-purple-700/80 dark:text-purple-300/80' | |
| : 'text-red-700/80 dark:text-red-300/80' | |
| }`}> | |
| Your feedback helps us improve | |
| </p> | |
| </motion.div> | |
| )} | |
| </div> | |
| </motion.div> | |
| </> | |
| )} | |
| </AnimatePresence> | |
| ); | |
| } |