132 lines
6.3 KiB
TypeScript
132 lines
6.3 KiB
TypeScript
import React, { useState, useEffect } from 'react';
|
|
import { X, Archive, Trash2, RefreshCcw } from 'lucide-react';
|
|
import api from '../services/api';
|
|
import type { INotification } from '../types';
|
|
|
|
interface ArchivedNotificationsModalProps {
|
|
isOpen: boolean;
|
|
onClose: () => void;
|
|
}
|
|
|
|
export const ArchivedNotificationsModal: React.FC<ArchivedNotificationsModalProps> = ({
|
|
isOpen,
|
|
onClose,
|
|
}) => {
|
|
const [notifications, setNotifications] = useState<INotification[]>([]);
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
|
|
const fetchArchived = async () => {
|
|
setIsLoading(true);
|
|
try {
|
|
const response = await api.get<INotification[]>('/notifications?includeArchived=true');
|
|
// Filtrar apenas as arquivadas (no frontend por segurança, embora o backend já devesse ajudar)
|
|
// Na verdade, passamos includeArchived=true, o backend retornará unread + archived.
|
|
// Vamos filtrar para mostrar apenas o "Log" (arquivadas).
|
|
setNotifications(response.data.filter(n => n.isArchived || n.archivedBy?.length > 0));
|
|
} catch (error) {
|
|
console.error('Error fetching archived notifications:', error);
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
if (isOpen) {
|
|
fetchArchived();
|
|
}
|
|
}, [isOpen]);
|
|
|
|
const deleteForever = async (id: string) => {
|
|
if (!window.confirm('Excluir permanentemente este registro do log?')) return;
|
|
try {
|
|
await api.delete(`/notifications/${id}`);
|
|
setNotifications(prev => prev.filter(n => n._id !== id));
|
|
} catch (error) {
|
|
console.error('Error deleting archived notification:', error);
|
|
}
|
|
};
|
|
|
|
if (!isOpen) return null;
|
|
|
|
return (
|
|
<div className="fixed inset-0 bg-black/60 backdrop-blur-sm z-[60] flex items-center justify-center p-4 animate-in fade-in">
|
|
<div className="bg-zinc-900 rounded-2xl shadow-2xl max-w-2xl w-full border border-zinc-800 animate-in slide-in-from-bottom-4 max-h-[80vh] flex flex-col overflow-hidden">
|
|
{/* Header */}
|
|
<div className="flex items-center justify-between p-6 border-b border-zinc-800 bg-zinc-900">
|
|
<div className="flex items-center gap-3">
|
|
<div className="w-10 h-10 rounded-lg bg-zinc-800 flex items-center justify-center">
|
|
<Archive className="text-zinc-400" size={20} />
|
|
</div>
|
|
<div>
|
|
<h2 className="text-lg font-bold text-white">Log de Mensagens (Arquivadas)</h2>
|
|
<p className="text-sm text-zinc-500">
|
|
Histórico de notificações sistema
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<button
|
|
onClick={onClose}
|
|
className="p-2 hover:bg-zinc-800 rounded-lg transition-colors"
|
|
>
|
|
<X size={20} className="text-zinc-500" />
|
|
</button>
|
|
</div>
|
|
|
|
{/* Body */}
|
|
<div className="flex-1 overflow-y-auto p-6 space-y-4 bg-zinc-950/50">
|
|
{isLoading ? (
|
|
<div className="text-center py-8">
|
|
<RefreshCcw className="animate-spin text-primary mx-auto mb-2" size={24} />
|
|
<p className="text-zinc-500">Carregando histórico...</p>
|
|
</div>
|
|
) : notifications.length === 0 ? (
|
|
<div className="text-center py-12">
|
|
<Archive size={48} className="text-zinc-800 mx-auto mb-4" />
|
|
<p className="text-zinc-500 font-semibold">Nenhuma mensagem arquivada</p>
|
|
<p className="text-zinc-600 text-sm mt-1">
|
|
Mensagens arquivadas aparecerão aqui para consulta.
|
|
</p>
|
|
</div>
|
|
) : (
|
|
<div className="space-y-3">
|
|
{notifications.map((msg) => (
|
|
<div
|
|
key={msg._id}
|
|
className="bg-zinc-900 border border-zinc-800 rounded-xl p-4 hover:border-zinc-700 transition-all group"
|
|
>
|
|
<div className="flex items-start justify-between mb-2">
|
|
<div className="flex flex-col">
|
|
<span className="font-bold text-zinc-200 text-sm">{msg.title}</span>
|
|
<span className="text-[10px] text-zinc-500">
|
|
{new Date(msg.createdAt).toLocaleString('pt-BR')}
|
|
</span>
|
|
</div>
|
|
<button
|
|
onClick={() => deleteForever(msg._id)}
|
|
className="opacity-0 group-hover:opacity-100 p-1.5 text-zinc-600 hover:text-red-500 transition-all"
|
|
title="Excluir permanentemente"
|
|
>
|
|
<Trash2 size={14} />
|
|
</button>
|
|
</div>
|
|
<p className="text-zinc-400 text-xs leading-relaxed">{msg.message}</p>
|
|
</div>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* Footer */}
|
|
<div className="p-4 border-t border-zinc-800 bg-zinc-900 flex justify-end">
|
|
<button
|
|
onClick={onClose}
|
|
className="px-6 py-2 bg-zinc-800 hover:bg-zinc-700 text-white rounded-lg font-bold text-sm transition-colors"
|
|
>
|
|
Fechar
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|