660 lines
30 KiB
TypeScript
660 lines
30 KiB
TypeScript
import React, { useState } from 'react';
|
|
import {
|
|
Headphones,
|
|
MessageCircle,
|
|
FileText,
|
|
Search,
|
|
Plus,
|
|
Edit,
|
|
Trash2,
|
|
Eye,
|
|
EyeOff,
|
|
Settings,
|
|
CheckCircle,
|
|
Clock,
|
|
AlertCircle,
|
|
Star,
|
|
Filter,
|
|
Download,
|
|
Send,
|
|
User,
|
|
Calendar,
|
|
Tag,
|
|
BarChart3,
|
|
TrendingUp,
|
|
Users,
|
|
Award,
|
|
X,
|
|
Save,
|
|
Upload
|
|
} from 'lucide-react';
|
|
|
|
interface SupportTicket {
|
|
id: string;
|
|
title: string;
|
|
description: string;
|
|
status: 'open' | 'in_progress' | 'resolved' | 'closed';
|
|
priority: 'low' | 'medium' | 'high' | 'urgent';
|
|
category: 'technical' | 'billing' | 'account' | 'general';
|
|
submittedBy: string;
|
|
assignedTo: string;
|
|
createdAt: string;
|
|
updatedAt: string;
|
|
messages: TicketMessage[];
|
|
}
|
|
|
|
interface TicketMessage {
|
|
id: string;
|
|
content: string;
|
|
sender: string;
|
|
timestamp: string;
|
|
isInternal: boolean;
|
|
}
|
|
|
|
interface FAQ {
|
|
id: string;
|
|
question: string;
|
|
answer: string;
|
|
category: string;
|
|
tags: string[];
|
|
helpful: number;
|
|
notHelpful: number;
|
|
}
|
|
|
|
interface SupportResource {
|
|
id: string;
|
|
title: string;
|
|
description: string;
|
|
type: 'documentation' | 'video' | 'guide' | 'tutorial';
|
|
url: string;
|
|
category: string;
|
|
tags: string[];
|
|
}
|
|
|
|
interface SupportAdminProps {
|
|
tickets: SupportTicket[];
|
|
faqs: FAQ[];
|
|
resources: SupportResource[];
|
|
onTicketUpdate: (id: string, updates: Partial<SupportTicket>) => void;
|
|
onTicketDelete: (id: string) => void;
|
|
onFAQAdd: (faq: Omit<FAQ, 'id'>) => void;
|
|
onFAQUpdate: (id: string, updates: Partial<FAQ>) => void;
|
|
onFAQDelete: (id: string) => void;
|
|
onResourceAdd: (resource: Omit<SupportResource, 'id'>) => void;
|
|
onResourceUpdate: (id: string, updates: Partial<SupportResource>) => void;
|
|
onResourceDelete: (id: string) => void;
|
|
onExportReport: (type: 'pdf' | 'excel' | 'csv') => void;
|
|
}
|
|
|
|
const SupportAdmin: React.FC<SupportAdminProps> = ({
|
|
tickets,
|
|
faqs,
|
|
resources,
|
|
onTicketUpdate,
|
|
onTicketDelete,
|
|
onFAQAdd,
|
|
onFAQUpdate,
|
|
onFAQDelete,
|
|
onResourceAdd,
|
|
onResourceUpdate,
|
|
onResourceDelete,
|
|
onExportReport
|
|
}) => {
|
|
const [currentView, setCurrentView] = useState<'tickets' | 'faqs' | 'resources' | 'analytics'>('tickets');
|
|
const [selectedTicket, setSelectedTicket] = useState<SupportTicket | null>(null);
|
|
const [editingFAQ, setEditingFAQ] = useState<FAQ | null>(null);
|
|
const [editingResource, setEditingResource] = useState<SupportResource | null>(null);
|
|
const [showAddFAQ, setShowAddFAQ] = useState(false);
|
|
const [showAddResource, setShowAddResource] = useState(false);
|
|
const [searchQuery, setSearchQuery] = useState('');
|
|
const [filterStatus, setFilterStatus] = useState<string>('all');
|
|
const [filterPriority, setFilterPriority] = useState<string>('all');
|
|
const [filterCategory, setFilterCategory] = useState<string>('all');
|
|
|
|
const getStatusColor = (status: string) => {
|
|
switch (status) {
|
|
case 'open': return 'bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300';
|
|
case 'in_progress': return 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-300';
|
|
case 'resolved': return 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-300';
|
|
case 'closed': return 'bg-gray-100 text-gray-800 dark:bg-gray-900 dark:text-gray-300';
|
|
default: return 'bg-gray-100 text-gray-800 dark:bg-gray-900 dark:text-gray-300';
|
|
}
|
|
};
|
|
|
|
const getPriorityColor = (priority: string) => {
|
|
switch (priority) {
|
|
case 'urgent': return 'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-300';
|
|
case 'high': return 'bg-orange-100 text-orange-800 dark:bg-orange-900 dark:text-orange-300';
|
|
case 'medium': return 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-300';
|
|
case 'low': return 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-300';
|
|
default: return 'bg-gray-100 text-gray-800 dark:bg-gray-900 dark:text-gray-300';
|
|
}
|
|
};
|
|
|
|
const filteredTickets = tickets.filter(ticket => {
|
|
const matchesSearch = ticket.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
|
ticket.description.toLowerCase().includes(searchQuery.toLowerCase());
|
|
const matchesStatus = filterStatus === 'all' || ticket.status === filterStatus;
|
|
const matchesPriority = filterPriority === 'all' || ticket.priority === filterPriority;
|
|
const matchesCategory = filterCategory === 'all' || ticket.category === filterCategory;
|
|
|
|
return matchesSearch && matchesStatus && matchesPriority && matchesCategory;
|
|
});
|
|
|
|
const handleFAQSubmit = (e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
const formData = new FormData(e.target as HTMLFormElement);
|
|
const newFAQ: Omit<FAQ, 'id'> = {
|
|
question: formData.get('question') as string,
|
|
answer: formData.get('answer') as string,
|
|
category: formData.get('category') as string,
|
|
tags: (formData.get('tags') as string).split(',').map(tag => tag.trim()),
|
|
helpful: 0,
|
|
notHelpful: 0
|
|
};
|
|
onFAQAdd(newFAQ);
|
|
setShowAddFAQ(false);
|
|
(e.target as HTMLFormElement).reset();
|
|
};
|
|
|
|
const handleResourceSubmit = (e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
const formData = new FormData(e.target as HTMLFormElement);
|
|
const newResource: Omit<SupportResource, 'id'> = {
|
|
title: formData.get('title') as string,
|
|
description: formData.get('description') as string,
|
|
type: formData.get('type') as 'documentation' | 'video' | 'guide' | 'tutorial',
|
|
url: formData.get('url') as string,
|
|
category: formData.get('category') as string,
|
|
tags: (formData.get('tags') as string).split(',').map(tag => tag.trim())
|
|
};
|
|
onResourceAdd(newResource);
|
|
setShowAddResource(false);
|
|
(e.target as HTMLFormElement).reset();
|
|
};
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
{/* Header */}
|
|
<div className="flex flex-col sm:flex-row items-start sm:items-center justify-between space-y-4 sm:space-y-0">
|
|
<div className="flex items-center space-x-3">
|
|
<div className="p-2 bg-primary-100 dark:bg-primary-900 rounded-lg">
|
|
<Settings className="w-6 h-6 text-primary-600 dark:text-primary-400" />
|
|
</div>
|
|
<div>
|
|
<h2 className="text-xl font-semibold text-secondary-900 dark:text-white">Support Administration</h2>
|
|
<p className="text-sm text-secondary-600 dark:text-secondary-400">Manage tickets, FAQs, and resources</p>
|
|
</div>
|
|
</div>
|
|
<div className="flex items-center space-x-3">
|
|
{/* View Toggle Buttons */}
|
|
<div className="flex items-center space-x-2 bg-secondary-100 dark:bg-secondary-800 rounded-lg p-1">
|
|
<button
|
|
onClick={() => setCurrentView('tickets')}
|
|
className={`px-3 py-2 rounded-md text-sm font-medium transition-colors ${
|
|
currentView === 'tickets'
|
|
? 'bg-white dark:bg-gray-700 text-secondary-900 dark:text-white shadow-sm'
|
|
: 'text-secondary-600 dark:text-secondary-400 hover:text-secondary-900 dark:hover:text-white'
|
|
}`}
|
|
>
|
|
Tickets
|
|
</button>
|
|
<button
|
|
onClick={() => setCurrentView('faqs')}
|
|
className={`px-3 py-2 rounded-md text-sm font-medium transition-colors ${
|
|
currentView === 'faqs'
|
|
? 'bg-white dark:bg-gray-700 text-secondary-900 dark:text-white shadow-sm'
|
|
: 'text-secondary-600 dark:text-secondary-400 hover:text-secondary-900 dark:hover:text-white'
|
|
}`}
|
|
>
|
|
FAQs
|
|
</button>
|
|
<button
|
|
onClick={() => setCurrentView('resources')}
|
|
className={`px-3 py-2 rounded-md text-sm font-medium transition-colors ${
|
|
currentView === 'resources'
|
|
? 'bg-white dark:bg-gray-700 text-secondary-900 dark:text-white shadow-sm'
|
|
: 'text-secondary-600 dark:text-secondary-400 hover:text-secondary-900 dark:hover:text-white'
|
|
}`}
|
|
>
|
|
Resources
|
|
</button>
|
|
<button
|
|
onClick={() => setCurrentView('analytics')}
|
|
className={`px-3 py-2 rounded-md text-sm font-medium transition-colors ${
|
|
currentView === 'analytics'
|
|
? 'bg-white dark:bg-gray-700 text-secondary-900 dark:text-white shadow-sm'
|
|
: 'text-secondary-600 dark:text-secondary-400 hover:text-secondary-900 dark:hover:text-white'
|
|
}`}
|
|
>
|
|
Analytics
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Content Based on Current View */}
|
|
{currentView === 'tickets' && (
|
|
<div className="space-y-6">
|
|
{/* Search and Filters */}
|
|
<div className="card p-6">
|
|
<div className="flex flex-col lg:flex-row gap-4">
|
|
<div className="flex-1">
|
|
<div className="relative">
|
|
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-secondary-400 w-4 h-4" />
|
|
<input
|
|
type="text"
|
|
placeholder="Search tickets..."
|
|
value={searchQuery}
|
|
onChange={(e) => setSearchQuery(e.target.value)}
|
|
className="input pl-10 w-full"
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div className="flex flex-wrap gap-2">
|
|
<select
|
|
value={filterStatus}
|
|
onChange={(e) => setFilterStatus(e.target.value)}
|
|
className="input text-sm"
|
|
>
|
|
<option value="all">All Status</option>
|
|
<option value="open">Open</option>
|
|
<option value="in_progress">In Progress</option>
|
|
<option value="resolved">Resolved</option>
|
|
<option value="closed">Closed</option>
|
|
</select>
|
|
<select
|
|
value={filterPriority}
|
|
onChange={(e) => setFilterPriority(e.target.value)}
|
|
className="input text-sm"
|
|
>
|
|
<option value="all">All Priority</option>
|
|
<option value="urgent">Urgent</option>
|
|
<option value="high">High</option>
|
|
<option value="medium">Medium</option>
|
|
<option value="low">Low</option>
|
|
</select>
|
|
<select
|
|
value={filterCategory}
|
|
onChange={(e) => setFilterCategory(e.target.value)}
|
|
className="input text-sm"
|
|
>
|
|
<option value="all">All Categories</option>
|
|
<option value="technical">Technical</option>
|
|
<option value="billing">Billing</option>
|
|
<option value="account">Account</option>
|
|
<option value="general">General</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Tickets List */}
|
|
<div className="space-y-4">
|
|
{filteredTickets.map((ticket) => (
|
|
<div key={ticket.id} className="card p-6">
|
|
<div className="flex items-start justify-between">
|
|
<div className="flex-1">
|
|
<div className="flex items-center space-x-3 mb-2">
|
|
<h3 className="text-lg font-semibold text-secondary-900 dark:text-white">{ticket.title}</h3>
|
|
<span className={`px-2 py-1 rounded-full text-xs font-medium ${getStatusColor(ticket.status)}`}>
|
|
{ticket.status.replace('_', ' ')}
|
|
</span>
|
|
<span className={`px-2 py-1 rounded-full text-xs font-medium ${getPriorityColor(ticket.priority)}`}>
|
|
{ticket.priority}
|
|
</span>
|
|
</div>
|
|
<p className="text-secondary-600 dark:text-secondary-400 mb-3">{ticket.description}</p>
|
|
<div className="flex items-center space-x-6 text-sm text-secondary-500 dark:text-secondary-400">
|
|
<div className="flex items-center space-x-1">
|
|
<User className="w-4 h-4" />
|
|
<span>{ticket.submittedBy}</span>
|
|
</div>
|
|
<div className="flex items-center space-x-1">
|
|
<Calendar className="w-4 h-4" />
|
|
<span>{new Date(ticket.createdAt).toLocaleDateString()}</span>
|
|
</div>
|
|
<div className="flex items-center space-x-1">
|
|
<MessageCircle className="w-4 h-4" />
|
|
<span>{ticket.messages.length} messages</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className="flex items-center space-x-2">
|
|
<button
|
|
onClick={() => setSelectedTicket(ticket)}
|
|
className="p-2 text-primary-600 hover:bg-primary-100 dark:hover:bg-primary-900 rounded-lg transition-colors"
|
|
>
|
|
<Eye className="w-4 h-4" />
|
|
</button>
|
|
<button className="p-2 text-secondary-600 hover:bg-secondary-100 dark:hover:bg-secondary-700 rounded-lg transition-colors">
|
|
<Edit className="w-4 h-4" />
|
|
</button>
|
|
<button
|
|
onClick={() => onTicketDelete(ticket.id)}
|
|
className="p-2 text-danger-600 hover:bg-danger-100 dark:hover:bg-danger-900 rounded-lg transition-colors"
|
|
>
|
|
<Trash2 className="w-4 h-4" />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{currentView === 'faqs' && (
|
|
<div className="space-y-6">
|
|
<div className="card p-6">
|
|
<div className="flex items-center justify-between mb-6">
|
|
<h2 className="text-xl font-semibold text-secondary-900 dark:text-white">Manage FAQs</h2>
|
|
<button
|
|
onClick={() => setShowAddFAQ(true)}
|
|
className="inline-flex items-center px-4 py-2 bg-success-600 text-white rounded-lg text-sm font-medium hover:bg-success-700 transition-colors"
|
|
>
|
|
<Plus className="w-4 h-4 mr-2" />
|
|
Add FAQ
|
|
</button>
|
|
</div>
|
|
<div className="space-y-4">
|
|
{faqs.map((faq) => (
|
|
<div key={faq.id} className="border border-gray-200 dark:border-gray-700 rounded-lg p-4">
|
|
<div className="flex items-start justify-between">
|
|
<div className="flex-1">
|
|
<h3 className="text-lg font-medium text-secondary-900 dark:text-white mb-2">{faq.question}</h3>
|
|
<p className="text-secondary-600 dark:text-secondary-400 mb-3">{faq.answer}</p>
|
|
<div className="flex items-center space-x-4 text-sm text-secondary-500 dark:text-secondary-400">
|
|
<span>Category: {faq.category}</span>
|
|
<span>Helpful: {faq.helpful}</span>
|
|
<span>Not Helpful: {faq.notHelpful}</span>
|
|
</div>
|
|
</div>
|
|
<div className="flex items-center space-x-2">
|
|
<button
|
|
onClick={() => setEditingFAQ(faq)}
|
|
className="p-2 text-secondary-600 hover:bg-secondary-100 dark:hover:bg-secondary-700 rounded-lg transition-colors"
|
|
>
|
|
<Edit className="w-4 h-4" />
|
|
</button>
|
|
<button
|
|
onClick={() => onFAQDelete(faq.id)}
|
|
className="p-2 text-danger-600 hover:bg-danger-100 dark:hover:bg-danger-900 rounded-lg transition-colors"
|
|
>
|
|
<Trash2 className="w-4 h-4" />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{currentView === 'resources' && (
|
|
<div className="space-y-6">
|
|
<div className="card p-6">
|
|
<div className="flex items-center justify-between mb-6">
|
|
<h2 className="text-xl font-semibold text-secondary-900 dark:text-white">Manage Resources</h2>
|
|
<button
|
|
onClick={() => setShowAddResource(true)}
|
|
className="inline-flex items-center px-4 py-2 bg-success-600 text-white rounded-lg text-sm font-medium hover:bg-success-700 transition-colors"
|
|
>
|
|
<Plus className="w-4 h-4 mr-2" />
|
|
Add Resource
|
|
</button>
|
|
</div>
|
|
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-6">
|
|
{resources.map((resource) => (
|
|
<div key={resource.id} className="bg-white dark:bg-gray-800 rounded-lg p-6 shadow-sm border border-gray-200 dark:border-gray-700">
|
|
<div className="flex items-center space-x-3 mb-4">
|
|
<div className="w-10 h-10 bg-primary-100 dark:bg-primary-900 rounded-lg flex items-center justify-center">
|
|
<FileText className="w-5 h-5 text-primary-600 dark:text-primary-400" />
|
|
</div>
|
|
<div>
|
|
<h3 className="font-medium text-secondary-900 dark:text-white">{resource.title}</h3>
|
|
<p className="text-sm text-secondary-500 dark:text-secondary-400">{resource.type}</p>
|
|
</div>
|
|
</div>
|
|
<p className="text-secondary-600 dark:text-secondary-400 mb-4">{resource.description}</p>
|
|
<div className="flex items-center justify-between">
|
|
<div className="flex flex-wrap gap-1">
|
|
{resource.tags.slice(0, 2).map((tag) => (
|
|
<span key={tag} className="px-2 py-1 bg-secondary-100 dark:bg-secondary-800 text-secondary-600 dark:text-secondary-400 text-xs rounded">
|
|
{tag}
|
|
</span>
|
|
))}
|
|
</div>
|
|
<div className="flex items-center space-x-2">
|
|
<button
|
|
onClick={() => setEditingResource(resource)}
|
|
className="text-secondary-600 hover:text-secondary-700 dark:text-secondary-400 dark:hover:text-secondary-300"
|
|
>
|
|
<Edit className="w-4 h-4" />
|
|
</button>
|
|
<button
|
|
onClick={() => onResourceDelete(resource.id)}
|
|
className="text-danger-600 hover:text-danger-700 dark:text-danger-400 dark:hover:text-danger-300"
|
|
>
|
|
<Trash2 className="w-4 h-4" />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{currentView === 'analytics' && (
|
|
<div className="space-y-6">
|
|
<div className="card p-6">
|
|
<h2 className="text-xl font-semibold text-secondary-900 dark:text-white mb-6">Support Analytics</h2>
|
|
<div className="grid md:grid-cols-2 lg:grid-cols-4 gap-6">
|
|
<div className="bg-primary-50 dark:bg-primary-900 rounded-lg p-6">
|
|
<div className="flex items-center space-x-3">
|
|
<div className="w-10 h-10 bg-primary-100 dark:bg-primary-800 rounded-lg flex items-center justify-center">
|
|
<MessageCircle className="w-5 h-5 text-primary-600 dark:text-primary-400" />
|
|
</div>
|
|
<div>
|
|
<p className="text-sm text-secondary-600 dark:text-secondary-400">Total Tickets</p>
|
|
<p className="text-2xl font-bold text-secondary-900 dark:text-white">{tickets.length}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className="bg-yellow-50 dark:bg-yellow-900 rounded-lg p-6">
|
|
<div className="flex items-center space-x-3">
|
|
<div className="w-10 h-10 bg-yellow-100 dark:bg-yellow-800 rounded-lg flex items-center justify-center">
|
|
<Clock className="w-5 h-5 text-yellow-600 dark:text-yellow-400" />
|
|
</div>
|
|
<div>
|
|
<p className="text-sm text-secondary-600 dark:text-secondary-400">Open Tickets</p>
|
|
<p className="text-2xl font-bold text-secondary-900 dark:text-white">
|
|
{tickets.filter(t => t.status === 'open').length}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className="bg-green-50 dark:bg-green-900 rounded-lg p-6">
|
|
<div className="flex items-center space-x-3">
|
|
<div className="w-10 h-10 bg-green-100 dark:bg-green-800 rounded-lg flex items-center justify-center">
|
|
<CheckCircle className="w-5 h-5 text-green-600 dark:text-green-400" />
|
|
</div>
|
|
<div>
|
|
<p className="text-sm text-secondary-600 dark:text-secondary-400">Resolved</p>
|
|
<p className="text-2xl font-bold text-secondary-900 dark:text-white">
|
|
{tickets.filter(t => t.status === 'resolved').length}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className="bg-blue-50 dark:bg-blue-900 rounded-lg p-6">
|
|
<div className="flex items-center space-x-3">
|
|
<div className="w-10 h-10 bg-blue-100 dark:bg-blue-800 rounded-lg flex items-center justify-center">
|
|
<FileText className="w-5 h-5 text-blue-600 dark:text-blue-400" />
|
|
</div>
|
|
<div>
|
|
<p className="text-sm text-secondary-600 dark:text-secondary-400">FAQs</p>
|
|
<p className="text-2xl font-bold text-secondary-900 dark:text-white">{faqs.length}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="card p-6">
|
|
<div className="flex items-center justify-between mb-6">
|
|
<h3 className="text-lg font-semibold text-secondary-900 dark:text-white">Quick Actions</h3>
|
|
<div className="flex items-center space-x-3">
|
|
<button
|
|
onClick={() => onExportReport('pdf')}
|
|
className="inline-flex items-center px-4 py-2 bg-primary-600 text-white rounded-lg text-sm font-medium hover:bg-primary-700 transition-colors"
|
|
>
|
|
<Download className="w-4 h-4 mr-2" />
|
|
Export PDF
|
|
</button>
|
|
<button
|
|
onClick={() => onExportReport('excel')}
|
|
className="inline-flex items-center px-4 py-2 bg-success-600 text-white rounded-lg text-sm font-medium hover:bg-success-700 transition-colors"
|
|
>
|
|
<Download className="w-4 h-4 mr-2" />
|
|
Export Excel
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
<button className="flex items-center space-x-3 p-4 bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors">
|
|
<Plus className="w-5 h-5 text-primary-600" />
|
|
<span className="text-secondary-900 dark:text-white">Create New Ticket</span>
|
|
</button>
|
|
<button className="flex items-center space-x-3 p-4 bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors">
|
|
<FileText className="w-5 h-5 text-success-600" />
|
|
<span className="text-secondary-900 dark:text-white">Add FAQ</span>
|
|
</button>
|
|
<button className="flex items-center space-x-3 p-4 bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors">
|
|
<Upload className="w-5 h-5 text-warning-600" />
|
|
<span className="text-secondary-900 dark:text-white">Upload Resource</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* Add FAQ Modal */}
|
|
{showAddFAQ && (
|
|
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
|
|
<div className="bg-white dark:bg-gray-800 rounded-lg p-6 w-full max-w-md">
|
|
<h3 className="text-lg font-semibold text-secondary-900 dark:text-white mb-4">Add New FAQ</h3>
|
|
<form onSubmit={handleFAQSubmit} className="space-y-4">
|
|
<div>
|
|
<label className="block text-sm font-medium text-secondary-700 dark:text-secondary-300 mb-1">Question</label>
|
|
<input type="text" name="question" className="input w-full" placeholder="Enter question" required />
|
|
</div>
|
|
<div>
|
|
<label className="block text-sm font-medium text-secondary-700 dark:text-secondary-300 mb-1">Answer</label>
|
|
<textarea name="answer" className="input w-full" rows={4} placeholder="Enter answer" required></textarea>
|
|
</div>
|
|
<div>
|
|
<label className="block text-sm font-medium text-secondary-700 dark:text-secondary-300 mb-1">Category</label>
|
|
<select name="category" className="input w-full" required>
|
|
<option value="">Select category</option>
|
|
<option value="billing">Billing</option>
|
|
<option value="technical">Technical</option>
|
|
<option value="account">Account</option>
|
|
<option value="general">General</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label className="block text-sm font-medium text-secondary-700 dark:text-secondary-300 mb-1">Tags (comma-separated)</label>
|
|
<input type="text" name="tags" className="input w-full" placeholder="tag1, tag2, tag3" />
|
|
</div>
|
|
<div className="flex justify-end space-x-3">
|
|
<button
|
|
type="button"
|
|
onClick={() => setShowAddFAQ(false)}
|
|
className="px-4 py-2 text-secondary-600 dark:text-secondary-400 hover:bg-secondary-100 dark:hover:bg-secondary-700 rounded-lg transition-colors"
|
|
>
|
|
Cancel
|
|
</button>
|
|
<button
|
|
type="submit"
|
|
className="px-4 py-2 bg-success-600 text-white rounded-lg hover:bg-success-700 transition-colors"
|
|
>
|
|
Add FAQ
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* Add Resource Modal */}
|
|
{showAddResource && (
|
|
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
|
|
<div className="bg-white dark:bg-gray-800 rounded-lg p-6 w-full max-w-md">
|
|
<h3 className="text-lg font-semibold text-secondary-900 dark:text-white mb-4">Add New Resource</h3>
|
|
<form onSubmit={handleResourceSubmit} className="space-y-4">
|
|
<div>
|
|
<label className="block text-sm font-medium text-secondary-700 dark:text-secondary-300 mb-1">Title</label>
|
|
<input type="text" name="title" className="input w-full" placeholder="Resource title" required />
|
|
</div>
|
|
<div>
|
|
<label className="block text-sm font-medium text-secondary-700 dark:text-secondary-300 mb-1">Description</label>
|
|
<textarea name="description" className="input w-full" rows={3} placeholder="Resource description" required></textarea>
|
|
</div>
|
|
<div className="grid grid-cols-2 gap-4">
|
|
<div>
|
|
<label className="block text-sm font-medium text-secondary-700 dark:text-secondary-300 mb-1">Type</label>
|
|
<select name="type" className="input w-full" required>
|
|
<option value="">Select type</option>
|
|
<option value="documentation">Documentation</option>
|
|
<option value="video">Video</option>
|
|
<option value="guide">Guide</option>
|
|
<option value="tutorial">Tutorial</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label className="block text-sm font-medium text-secondary-700 dark:text-secondary-300 mb-1">Category</label>
|
|
<select name="category" className="input w-full" required>
|
|
<option value="">Select category</option>
|
|
<option value="onboarding">Onboarding</option>
|
|
<option value="billing">Billing</option>
|
|
<option value="technical">Technical</option>
|
|
<option value="general">General</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<label className="block text-sm font-medium text-secondary-700 dark:text-secondary-300 mb-1">URL</label>
|
|
<input type="url" name="url" className="input w-full" placeholder="https://..." required />
|
|
</div>
|
|
<div>
|
|
<label className="block text-sm font-medium text-secondary-700 dark:text-secondary-300 mb-1">Tags (comma-separated)</label>
|
|
<input type="text" name="tags" className="input w-full" placeholder="tag1, tag2, tag3" />
|
|
</div>
|
|
<div className="flex justify-end space-x-3">
|
|
<button
|
|
type="button"
|
|
onClick={() => setShowAddResource(false)}
|
|
className="px-4 py-2 text-secondary-600 dark:text-secondary-400 hover:bg-secondary-100 dark:hover:bg-secondary-700 rounded-lg transition-colors"
|
|
>
|
|
Cancel
|
|
</button>
|
|
<button
|
|
type="submit"
|
|
className="px-4 py-2 bg-success-600 text-white rounded-lg hover:bg-success-700 transition-colors"
|
|
>
|
|
Add Resource
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default SupportAdmin;
|