imkFinal/frontend/src/components/dashboard/Dashboard.jsx
dimitar c7d4b95631 final version
complete redesign
2025-02-24 23:40:35 +01:00

154 lines
5.4 KiB
JavaScript

import { useState, useEffect } from 'react';
import { useAuth } from '../../hooks/useAuth';
import { getSharedDocuments } from '../../services/api';
import { format } from 'date-fns';
import { FiFolder, FiFile, FiDownload, FiChevronRight, FiLoader } from 'react-icons/fi';
import { downloadDocument } from '../../services/api';
function Dashboard() {
const [documents, setDocuments] = useState({});
const [expandedFolders, setExpandedFolders] = useState({});
const [loading, setLoading] = useState(true);
const [error, setError] = useState('');
const { user } = useAuth();
useEffect(() => {
const fetchDocuments = async () => {
try {
if (!user?.id) return;
const response = await getSharedDocuments(user.id);
// Group the documents by company and date
const groupedDocs = groupDocumentsByCompanyAndDate(response.data);
setDocuments(groupedDocs);
} catch (err) {
console.error('Error fetching documents:', err);
setError('Failed to fetch documents');
} finally {
setLoading(false);
}
};
fetchDocuments();
}, [user]);
const groupDocumentsByCompanyAndDate = (docs) => {
if (!Array.isArray(docs)) {
console.error('Expected array of documents, received:', docs);
return {};
}
return docs.reduce((acc, doc) => {
const folderName = `${doc.sharedWith?.name || 'Unknown'}-${format(new Date(doc.createdAt), 'yyyy-MM-dd')}`;
if (!acc[folderName]) {
acc[folderName] = [];
}
acc[folderName].push(doc);
return acc;
}, {});
};
const handleDownload = async (s3Key, fileName) => {
try {
await downloadDocument(s3Key);
} catch (err) {
console.error('Error downloading document:', err);
alert('Failed to download document. Please try again.');
}
};
const toggleFolder = (folderName) => {
setExpandedFolders(prev => ({
...prev,
[folderName]: !prev[folderName]
}));
};
if (loading) {
return (
<div className="min-h-screen flex items-center justify-center bg-gray-900">
<div className="flex items-center space-x-3 text-blue-500">
<FiLoader className="w-6 h-6 animate-spin" />
<span className="text-lg font-medium">Loading documents...</span>
</div>
</div>
);
}
if (error) {
return (
<div className="min-h-screen flex items-center justify-center bg-gray-900">
<div className="p-4 bg-red-500/10 border border-red-500/20 rounded-lg text-red-200">
{error}
</div>
</div>
);
}
return (
<div className="min-h-screen bg-gradient-to-br from-gray-900 to-gray-800 p-6">
<div className="max-w-7xl mx-auto">
<header className="mb-8 mt-20">
<h1 className="text-3xl font-bold text-white mb-2">Your Documents</h1>
<p className="text-gray-400">Access and manage your shared documents</p>
</header>
<div className="grid gap-6">
{Object.entries(documents).length > 0 ? (
Object.entries(documents).map(([folderName, docs]) => (
<div
key={folderName}
className="bg-white/5 backdrop-blur-lg rounded-xl overflow-hidden transition-all duration-200 hover:bg-white/10"
>
<button
onClick={() => toggleFolder(folderName)}
className="w-full px-6 py-4 flex items-center justify-between text-white hover:bg-white/5 transition-colors"
>
<div className="flex items-center space-x-3">
<FiFolder className="w-5 h-5 text-blue-400" />
<span className="font-medium">{folderName}</span>
<span className="text-sm text-gray-400">({docs.length} files)</span>
</div>
<FiChevronRight
className={`w-5 h-5 transition-transform duration-200 ${
expandedFolders[folderName] ? 'rotate-90' : ''
}`}
/>
</button>
{expandedFolders[folderName] && (
<div className="border-t border-gray-700">
{docs.map((doc) => (
<div
key={doc.id}
className="px-6 py-3 flex items-center justify-between hover:bg-white/5 transition-colors"
>
<div className="flex items-center space-x-3">
<FiFile className="w-4 h-4 text-gray-400" />
<span className="text-gray-200">{doc.title}</span>
</div>
<button
onClick={() => handleDownload(doc.s3Key)}
className="p-2 text-gray-400 hover:text-blue-400 rounded-lg hover:bg-blue-500/10 transition-colors"
title="Download document"
>
<FiDownload className="w-4 h-4" />
</button>
</div>
))}
</div>
)}
</div>
))
) : (
<div className="text-center py-12">
<p className="text-gray-400">No documents available</p>
</div>
)}
</div>
</div>
</div>
);
}
export default Dashboard;