import { useState, useEffect, useRef } from 'react'; import { ArrowLeft, Send, Clock, AlertCircle, CheckCircle } from 'lucide-react'; import axios from 'axios'; import { API_URL } from '../config'; import { notify } from './NotificationSystem'; export default function TicketChat({ ticket, token, user, onBack }) { const [messages, setMessages] = useState(ticket.messages || []); const [newMessage, setNewMessage] = useState(''); const [currentTicket, setCurrentTicket] = useState(ticket); const [loading, setLoading] = useState(false); const [previousMessagesCount, setPreviousMessagesCount] = useState(ticket.messages?.length || 0); const messagesEndRef = useRef(null); useEffect(() => { scrollToBottom(); const interval = setInterval(loadTicket, 3000); return () => clearInterval(interval); }, []); useEffect(() => { scrollToBottom(); }, [messages]); const scrollToBottom = () => { messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }); }; const loadTicket = async () => { try { const { data } = await axios.get(`${API_URL}/api/tickets/${ticket.id}`, { headers: { Authorization: `Bearer ${token}` } }); // Проверяем новые сообщения if (data.messages.length > previousMessagesCount) { const newMessagesCount = data.messages.length - previousMessagesCount; const lastMessage = data.messages[data.messages.length - 1]; // Уведомляем только если сообщение не от текущего пользователя if (lastMessage.author !== user.username && lastMessage.author !== 'system') { notify('info', 'Новое сообщение', `${lastMessage.author}: ${lastMessage.text.substring(0, 50)}${lastMessage.text.length > 50 ? '...' : ''}`); } setPreviousMessagesCount(data.messages.length); } // Проверяем изменение статуса if (data.status !== currentTicket.status) { const statusNames = { 'pending': 'На рассмотрении', 'in_progress': 'В работе', 'closed': 'Закрыт' }; notify('info', 'Статус изменён', `Тикет #${ticket.id}: ${statusNames[data.status]}`); } setCurrentTicket(data); setMessages(data.messages || []); } catch (error) { console.error('Ошибка загрузки тикета:', error); } }; const sendMessage = async (e) => { e.preventDefault(); if (!newMessage.trim() || loading) return; setLoading(true); try { const { data } = await axios.post( `${API_URL}/api/tickets/${ticket.id}/message`, { text: newMessage.trim() }, { headers: { Authorization: `Bearer ${token}` } } ); setMessages(data.ticket.messages); setCurrentTicket(data.ticket); setPreviousMessagesCount(data.ticket.messages.length); setNewMessage(''); notify('success', 'Сообщение отправлено', 'Ваше сообщение успешно отправлено'); } catch (error) { console.error('Ошибка отправки сообщения:', error); notify('error', 'Ошибка отправки', error.response?.data?.detail || 'Не удалось отправить сообщение'); alert(error.response?.data?.detail || 'Ошибка отправки сообщения'); } finally { setLoading(false); } }; const changeStatus = async (newStatus) => { const statusNames = { 'pending': 'На рассмотрении', 'in_progress': 'В работе', 'closed': 'Закрыт' }; try { const { data } = await axios.put( `${API_URL}/api/tickets/${ticket.id}/status`, { status: newStatus }, { headers: { Authorization: `Bearer ${token}` } } ); setCurrentTicket(data.ticket); setMessages(data.ticket.messages); setPreviousMessagesCount(data.ticket.messages.length); notify('success', 'Статус изменён', `Тикет #${ticket.id} теперь: ${statusNames[newStatus]}`); } catch (error) { console.error('Ошибка изменения статуса:', error); notify('error', 'Ошибка изменения статуса', error.response?.data?.detail || 'Не удалось изменить статус'); alert(error.response?.data?.detail || 'Ошибка изменения статуса'); } }; const getStatusIcon = (status) => { switch (status) { case 'pending': return ; case 'in_progress': return ; case 'closed': return ; default: return ; } }; const getStatusText = (status) => { switch (status) { case 'pending': return 'На рассмотрении'; case 'in_progress': return 'В работе'; case 'closed': return 'Закрыт'; default: return status; } }; const getStatusColor = (status) => { switch (status) { case 'pending': return 'bg-yellow-500/20 text-yellow-500 border-yellow-500/50'; case 'in_progress': return 'bg-blue-500/20 text-blue-500 border-blue-500/50'; case 'closed': return 'bg-green-500/20 text-green-500 border-green-500/50'; default: return 'bg-gray-500/20 text-gray-500 border-gray-500/50'; } }; const canChangeStatus = user.role === 'owner' || user.role === 'admin' || user.role === 'support'; return (
{/* Header */}

{currentTicket.title}

Автор: {currentTicket.author} • Создан: {new Date(currentTicket.created_at).toLocaleString('ru-RU')}

{getStatusIcon(currentTicket.status)} {getStatusText(currentTicket.status)}
{/* Status Controls */} {canChangeStatus && (
)}
{/* Messages */}
{messages.map((msg, index) => (
{msg.author !== 'system' && msg.author !== user.username && (
{msg.author}
)}
{msg.text}
{new Date(msg.timestamp).toLocaleTimeString('ru-RU')}
))}
{/* Input */} {currentTicket.status !== 'closed' && (
setNewMessage(e.target.value)} placeholder="Введите сообщение..." disabled={loading} className="input flex-1" />
)}
); }