/**
* Bug Reports Panel Component
*
* User feedback and bug report management:
* - View all bug reports
* - Filter by status/severity
* - Update report status
* - Add admin notes
*/
import React, { useState, useEffect, useCallback } from 'react';
import {
Bug, RefreshCw, Filter, MessageSquare, Clock, User,
Check, AlertTriangle, XCircle, ChevronDown, ExternalLink,
Edit3, Save, X
} from 'lucide-react';
import { getToken } from '../../services/api';
const API_BASE = import.meta.env.VITE_API_URL || '';
// Severity badge
const SeverityBadge = ({ severity }) => {
const config = {
critical: { color: '#dc2626', bg: '#fee2e2' },
high: { color: '#f97316', bg: '#ffedd5' },
medium: { color: '#f59e0b', bg: '#fef3c7' },
low: { color: '#10b981', bg: '#d1fae5' }
};
const { color, bg } = config[severity] || config.medium;
return (
{severity}
);
};
// Status badge
const StatusBadge = ({ status }) => {
const config = {
new: { color: '#dc2626', bg: '#fee2e2', label: 'New' },
in_progress: { color: '#f59e0b', bg: '#fef3c7', label: 'In Progress' },
resolved: { color: '#10b981', bg: '#d1fae5', label: 'Resolved' },
closed: { color: '#6b7280', bg: '#f3f4f6', label: 'Closed' },
wont_fix: { color: '#8b5cf6', bg: '#ede9fe', label: "Won't Fix" }
};
const { color, bg, label } = config[status] || config.new;
return (
{label}
);
};
// Bug report detail modal
const BugReportModal = ({ report, onClose, onUpdate }) => {
const [status, setStatus] = useState(report.status);
const [adminNotes, setAdminNotes] = useState(report.admin_notes || '');
const [saving, setSaving] = useState(false);
const handleSave = async () => {
setSaving(true);
try {
await onUpdate(report.id, { status, admin_notes: adminNotes });
onClose();
} catch (err) {
console.error('Error updating report:', err);
} finally {
setSaving(false);
}
};
return (
e.stopPropagation()}>
Bug Report Details
{report.category}
{report.title}
User ID: {report.user_id?.substring(0, 8)}...
{new Date(report.created_at).toLocaleString()}
{report.page_url && (
)}
{report.description}
{report.browser_info && (
{report.browser_info}
)}
);
};
function BugReportsPanel() {
const [reports, setReports] = useState([]);
const [stats, setStats] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const [selectedReport, setSelectedReport] = useState(null);
// Filters
const [status, setStatus] = useState('');
const [severity, setSeverity] = useState('');
const [autoRefresh, setAutoRefresh] = useState(false);
// Fetch reports
const fetchReports = useCallback(async () => {
setLoading(true);
setError(null);
try {
const token = getToken();
const params = new URLSearchParams();
if (status) params.append('status', status);
if (severity) params.append('severity', severity);
const response = await fetch(`${API_BASE}/api/admin/bug-reports?${params}`, {
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
});
if (!response.ok) throw new Error('Failed to fetch bug reports');
const data = await response.json();
if (data.success) {
setReports(data.reports);
setStats(data.stats);
}
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
}, [status, severity]);
// Update report
const updateReport = async (reportId, updates) => {
const token = getToken();
const response = await fetch(`${API_BASE}/api/admin/bug-reports/${reportId}`, {
method: 'PUT',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(updates)
});
if (!response.ok) throw new Error('Failed to update report');
fetchReports();
};
// Initial fetch
useEffect(() => {
fetchReports();
}, [fetchReports]);
// Auto-refresh every 60 seconds
useEffect(() => {
if (!autoRefresh) return;
const interval = setInterval(fetchReports, 60000);
return () => clearInterval(interval);
}, [autoRefresh, fetchReports]);
if (loading) {
return (
);
}
return (
{/* Header */}
{/* Filters */}
{/* Reports List */}
{reports.length === 0 ? (
) : (
| Severity |
Title |
Category |
Status |
Submitted |
Actions |
{reports.map((report) => (
|
{report.title} |
{report.category} |
|
{new Date(report.created_at).toLocaleDateString()}
|
|
))}
)}
{/* Detail Modal */}
{selectedReport && (
setSelectedReport(null)}
onUpdate={updateReport}
/>
)}
);
}
export default BugReportsPanel;