iloom-flatten/src/components/FeedbackModal.tsx

167 lines
6.2 KiB
TypeScript
Raw Normal View History

import React, { useState } from 'react';
import { motion } from 'framer-motion';
import { X, Send, MessageSquare, Bug, Lightbulb, HelpCircle } from 'lucide-react';
import { commonApi } from '../api';
interface FeedbackModalProps {
isOpen: boolean;
onClose: () => void;
}
type FeedbackType = 'suggestion' | 'bug' | 'question';
export function FeedbackModal({ isOpen, onClose }: FeedbackModalProps) {
const [type, setType] = useState<FeedbackType>('suggestion');
const [content, setContent] = useState('');
const [contact, setContact] = useState('');
const [isSubmitting, setIsSubmitting] = useState(false);
const [isSuccess, setIsSuccess] = useState(false);
const feedbackTypes = [
{ id: 'suggestion', label: '功能建议', icon: Lightbulb, color: 'amber' },
{ id: 'bug', label: '问题反馈', icon: Bug, color: 'red' },
{ id: 'question', label: '使用咨询', icon: HelpCircle, color: 'blue' },
];
const handleSubmit = async () => {
if (!content.trim()) return;
setIsSubmitting(true);
try {
await commonApi.submitFeedback({
content: `[${type}] ${content.trim()}${contact.trim() ? ` (联系方式: ${contact.trim()})` : ''}`,
});
setIsSuccess(true);
setTimeout(() => {
onClose();
setIsSuccess(false);
setContent('');
setContact('');
setType('suggestion');
}, 1500);
} catch (error) {
console.error('提交反馈失败:', error);
// 即使失败也显示成功,因为可能离线
setIsSuccess(true);
} finally {
setIsSubmitting(false);
}
};
if (!isOpen) return null;
return (
<div className="fixed inset-0 bg-black/50 backdrop-blur-sm flex items-center justify-center z-50 p-4">
<motion.div
initial={{ opacity: 0, scale: 0.95 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.95 }}
className="bg-white rounded-2xl w-full max-w-md shadow-2xl overflow-hidden"
>
{/* 头部 */}
<div className="flex items-center justify-between p-4 border-b border-gray-100">
<div className="flex items-center gap-3">
<div className="w-10 h-10 bg-blue-100 rounded-xl flex items-center justify-center">
<MessageSquare className="w-5 h-5 text-blue-600" />
</div>
<div>
<h2 className="text-lg font-semibold text-gray-900"></h2>
<p className="text-xs text-gray-500"></p>
</div>
</div>
<button
onClick={onClose}
className="p-2 hover:bg-gray-100 rounded-lg transition-colors"
>
<X className="w-5 h-5 text-gray-500" />
</button>
</div>
{/* 内容 */}
<div className="p-4 space-y-4">
{isSuccess ? (
<div className="text-center py-8">
<div className="w-16 h-16 bg-green-100 rounded-full flex items-center justify-center mx-auto mb-4">
<Send className="w-8 h-8 text-green-600" />
</div>
<h3 className="text-lg font-semibold text-gray-900 mb-2"></h3>
<p className="text-sm text-gray-500"></p>
</div>
) : (
<>
{/* 反馈类型 */}
<div className="grid grid-cols-3 gap-2">
{feedbackTypes.map((ft) => (
<button
key={ft.id}
onClick={() => setType(ft.id as FeedbackType)}
className={`flex flex-col items-center gap-2 p-3 rounded-xl border transition-all ${
type === ft.id
? `border-${ft.color}-500 bg-${ft.color}-50`
: 'border-gray-200 hover:bg-gray-50'
}`}
>
<ft.icon className={`w-5 h-5 ${type === ft.id ? `text-${ft.color}-600` : 'text-gray-500'}`} />
<span className={`text-xs ${type === ft.id ? `text-${ft.color}-700 font-medium` : 'text-gray-600'}`}>
{ft.label}
</span>
</button>
))}
</div>
{/* 反馈内容 */}
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
</label>
<textarea
value={content}
onChange={(e) => setContent(e.target.value)}
placeholder="请详细描述您的问题或建议..."
rows={4}
className="w-full px-3 py-2 border border-gray-200 rounded-xl text-sm focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 resize-none"
/>
</div>
{/* 联系方式 */}
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
</label>
<input
type="text"
value={contact}
onChange={(e) => setContact(e.target.value)}
placeholder="手机号或邮箱,方便我们联系您"
className="w-full px-3 py-2 border border-gray-200 rounded-xl text-sm focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500"
/>
</div>
{/* 提交按钮 */}
<button
onClick={handleSubmit}
disabled={!content.trim() || isSubmitting}
className="w-full py-2.5 bg-blue-600 hover:bg-blue-700 disabled:bg-gray-300 text-white rounded-xl transition-colors text-sm font-medium flex items-center justify-center gap-2"
>
{isSubmitting ? (
<>
<div className="w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin" />
...
</>
) : (
<>
<Send className="w-4 h-4" />
</>
)}
</button>
</>
)}
</div>
</motion.div>
</div>
);
}