From bacaf522cb670356c0e86e67193f46f301186662 Mon Sep 17 00:00:00 2001 From: dimitar Date: Sat, 2 Nov 2024 10:01:12 +0100 Subject: [PATCH] admin panel redesign and functionality fix --- .../imk-backend/src/admin/admin.service.ts | 3 + .../src/components/adminPanel/AdminPanel.jsx | 1080 +++-------------- 2 files changed, 188 insertions(+), 895 deletions(-) diff --git a/backend/imk-backend/src/admin/admin.service.ts b/backend/imk-backend/src/admin/admin.service.ts index fce6114..7e29822 100644 --- a/backend/imk-backend/src/admin/admin.service.ts +++ b/backend/imk-backend/src/admin/admin.service.ts @@ -30,6 +30,9 @@ export class AdminService { }, }, }, + orderBy: { + createdAt: 'desc', + }, }); } diff --git a/frontend/imk/src/components/adminPanel/AdminPanel.jsx b/frontend/imk/src/components/adminPanel/AdminPanel.jsx index 7052cb3..2c414fc 100644 --- a/frontend/imk/src/components/adminPanel/AdminPanel.jsx +++ b/frontend/imk/src/components/adminPanel/AdminPanel.jsx @@ -1,8 +1,8 @@ import { useState, useEffect } from 'react'; import { getAllUsers, getAllDocuments, getUserInfo, createUser } from '../../services/api'; import DocumentUpload from '../documentUpload/DocumentUpload'; -//import UserCreate from '../UserCreate'; import { useNavigate } from 'react-router-dom'; +import { FiUsers, FiFile, FiUpload, FiUserPlus, FiLoader } from 'react-icons/fi'; function AdminPanel() { const navigate = useNavigate(); @@ -16,13 +16,19 @@ function AdminPanel() { name: '', email: '', password: '', - isAdmin: false + isAdmin: false }); useEffect(() => { checkAdminStatus(); }, []); + useEffect(() => { + if (isAdmin) { + fetchData(); + } + }, [activeTab, isAdmin]); + const checkAdminStatus = async () => { try { const response = await getUserInfo(); @@ -38,13 +44,6 @@ function AdminPanel() { } }; - useEffect(() => { - if (isAdmin) { - fetchData(); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [activeTab, isAdmin]); - const fetchData = async () => { setLoading(true); setError(''); @@ -54,29 +53,17 @@ function AdminPanel() { setUsers(response.data); } else if (activeTab === 'documents') { const response = await getAllDocuments(); + console.log('Documents data:', response.data); setDocuments(response.data); } } catch (err) { + console.error('Fetch error:', err); setError('Failed to fetch data. Please try again.'); } finally { setLoading(false); } }; - const getStatusColor = (status) => { - const colors = { - pending: 'bg-yellow-100 text-yellow-800', - uploading: 'bg-blue-100 text-blue-800', - completed: 'bg-green-100 text-green-800', - failed: 'bg-red-100 text-red-800' - }; - return colors[status] || 'bg-gray-100 text-gray-800'; - }; - - if (!isAdmin) { - return null; - } - const handleCreateUser = async (e) => { e.preventDefault(); try { @@ -85,7 +72,7 @@ function AdminPanel() { name: '', email: '', password: '', - isAdmin: false // Reset isAdmin too + isAdmin: false }); fetchData(); } catch (err) { @@ -93,892 +80,195 @@ function AdminPanel() { } }; + if (!isAdmin) return null; + + const tabs = [ + { id: 'documents', name: 'Documents', icon: FiFile }, + { id: 'users', name: 'Users', icon: FiUsers }, + { id: 'upload', name: 'Upload Document', icon: FiUpload } + ]; + + if (loading) { + return ( +
+
+ + Loading... +
+
+ ); + } return ( -
-
- {/* Admin Header */} -
-

Admin Dashboard

+
+
+
+

Admin Dashboard

+

Manage users and documents

+
+ + {/* Tabs */} +
+ {tabs.map(({ id, name, icon: Icon }) => ( + + ))}
- {/* Tab Navigation */} -
- -
+ {error && ( +
+ {error} +
+ )} - {/* Content Area */} -
- {error && ( -
- {error} +
+ {activeTab === 'documents' && ( +
+
+ + + + + + + + + + + + {documents.map((doc) => ( + + + + + + + + ))} + +
TitleStatusUploaded ByShared WithCreated At
{doc.title} + + {doc.status} + + + {doc.uploadedBy?.name} ({doc.uploadedBy?.email}) + + {doc.sharedWith && doc.sharedWith.length > 0 + ? doc.sharedWith.map(user => ( +
+ {user.name} ({user.email}) +
+ )) + : 'None'} +
+ {new Date(doc.createdAt).toLocaleString()} +
+
)} - {loading ? ( -
-
-
- ) : ( + {activeTab === 'users' && ( <> - {activeTab === 'documents' && ( -
- - - - - - - +
+

Create New User

+
+ setNewUser({ ...newUser, name: e.target.value })} + className="bg-white/5 border border-gray-700 rounded-lg px-4 py-2 text-white placeholder-gray-400 focus:outline-none focus:border-blue-500" + required + /> + setNewUser({ ...newUser, email: e.target.value })} + className="bg-white/5 border border-gray-700 rounded-lg px-4 py-2 text-white placeholder-gray-400 focus:outline-none focus:border-blue-500" + required + /> + setNewUser({ ...newUser, password: e.target.value })} + className="bg-white/5 border border-gray-700 rounded-lg px-4 py-2 text-white placeholder-gray-400 focus:outline-none focus:border-blue-500" + required + /> +
+ setNewUser({ ...newUser, isAdmin: e.target.checked })} + className="rounded border-gray-700 bg-white/5 text-blue-500 focus:ring-blue-500" + /> + +
+ + +
+ +
+
TitleStatusShared WithCreated At
+ + + + + + + + + {users.map((user) => ( + + + + - - - {documents.map((doc) => ( - - - - {/* */} - - - - ))} - -
NameEmailRole
{user.name}{user.email} + + {user.isAdmin ? 'Admin' : 'User'} + +
{doc.title} - - {doc.status} - - - {doc.sharedWith?.map((user) => user.name).join(', ') || 'None'} - - {doc.sharedWith ? `${doc.sharedWith.name} (${doc.sharedWith.email})` : 'None'} - - {new Date(doc.createdAt).toLocaleDateString()} -
-
- )} - - {activeTab === 'users' && ( - <> -
-
- setNewUser({ ...newUser, name: e.target.value })} - className="rounded border p-2" - /> - setNewUser({ ...newUser, email: e.target.value })} - className="rounded border p-2" - /> - setNewUser({ ...newUser, password: e.target.value })} - className="rounded border p-2" - /> -
- setNewUser({ ...newUser, isAdmin: e.target.checked })} - className="mr-2" - /> - -
- -
-
- - - - - - - - - - - - {users.map((user) => ( - - - - - - - ))} - -
NameEmailAdmin StatusActions
{user.name}{user.email} - - {user.isAdmin ? 'Admin' : 'User'} - - - {/* Add actions if needed */} -
- - )} - - {activeTab === 'upload' && } + ))} + + +
)} + + {activeTab === 'upload' && ( +
+ +
+ )}
); } -export default AdminPanel; -// import { useState, useEffect } from 'react'; -// import { useAuth } from '../../hooks/useAuth'; -// import { format } from 'date-fns'; -// import { FiUpload, FiUsers, FiFile, FiTrash2, FiShare2, FiLoader, FiSearch, FiChevronRight } from 'react-icons/fi'; -// import api from '../../services/api'; - -// function AdminPanel() { -// const [documents, setDocuments] = useState([]); -// const [users, setUsers] = useState([]); -// const [loading, setLoading] = useState(true); -// const [error, setError] = useState(''); -// const [selectedFile, setSelectedFile] = useState(null); -// const [uploadTitle, setUploadTitle] = useState(''); -// const [selectedUser, setSelectedUser] = useState(''); -// const [searchTerm, setSearchTerm] = useState(''); -// const [expandedUsers, setExpandedUsers] = useState({}); - -// useEffect(() => { -// fetchData(); -// }, []); - -// const fetchData = async () => { -// try { -// setLoading(true); -// const [documentsRes, usersRes] = await Promise.all([ -// api.get('/admin/documents'), -// api.get('/admin/users') -// ]); - -// console.log('Documents response:', documentsRes.data); -// console.log('Users response:', usersRes.data); - -// // Group documents by user -// const groupedDocs = groupDocumentsByUser(documentsRes.data || []); -// setDocuments(groupedDocs); -// setUsers(usersRes.data || []); -// } catch (err) { -// setError('Failed to fetch data'); -// console.error('Error:', err); -// } finally { -// setLoading(false); -// } -// }; -// const groupDocumentsByUser = (docs) => { -// return docs.reduce((acc, doc) => { -// const userName = doc.sharedWith?.name || 'Unassigned'; -// if (!acc[userName]) { -// acc[userName] = []; -// } -// acc[userName].push(doc); -// return acc; -// }, {}); -// }; - -// const toggleUser = (userName) => { -// setExpandedUsers(prev => ({ -// ...prev, -// [userName]: !prev[userName] -// })); -// }; - -// const handleFileUpload = async (e) => { -// e.preventDefault(); -// if (!selectedFile || !uploadTitle || !selectedUser) { -// alert('Please fill in all fields'); -// return; -// } - -// const formData = new FormData(); -// formData.append('file', selectedFile); -// formData.append('title', uploadTitle); -// formData.append('sharedWith', selectedUser); - -// try { -// await api.post('/admin/documents', formData, { -// headers: { -// 'Content-Type': 'multipart/form-data', -// }, -// }); - -// setSelectedFile(null); -// setUploadTitle(''); -// setSelectedUser(''); -// fetchData(); -// alert('Document uploaded successfully'); -// } catch (err) { -// console.error('Upload error:', err); -// alert('Failed to upload document'); -// } -// }; - -// const handleDelete = async (documentId) => { -// if (!window.confirm('Are you sure you want to delete this document?')) { -// return; -// } - -// try { -// await api.delete(`/admin/documents/${documentId}`); -// fetchData(); -// alert('Document deleted successfully'); -// } catch (err) { -// console.error('Delete error:', err); -// alert('Failed to delete document'); -// } -// }; - -// const handleShare = async (documentId) => { -// const userId = prompt('Enter user ID to share with:'); -// if (!userId) return; - -// try { -// await api.post(`/admin/documents/${documentId}/share`, { userId }); -// fetchData(); -// alert('Document shared successfully'); -// } catch (err) { -// console.error('Share error:', err); -// alert('Failed to share document'); -// } -// }; - -// if (loading) { -// return ( -//
-//
-// -// Loading admin panel... -//
-//
-// ); -// } - -// if (error) { -// return ( -//
-//
-// {error} -//
-//
-// ); -// } - -// return ( -//
-//
-//
-//

Admin Dashboard

-//

Manage documents and users

-//
- -// {/* Upload Section - remains the same */} -//
-// {/* ... upload form content remains the same ... */} -//
- -// {/* Search Bar */} -//
-// -// setSearchTerm(e.target.value)} -// className="w-full pl-10 pr-4 py-3 bg-white/5 border border-gray-700 rounded-lg focus:outline-none focus:border-blue-500 text-white placeholder-gray-400" -// /> -//
- -// {/* Documents List - Grouped by User */} -//
-// {Object.entries(documents).map(([userName, userDocs]) => { -// const filteredDocs = userDocs.filter(doc => -// doc.title.toLowerCase().includes(searchTerm.toLowerCase()) -// ); - -// if (filteredDocs.length === 0) return null; - -// return ( -//
-// - -// {expandedUsers[userName] && ( -//
-// {filteredDocs.map(doc => ( -//
-//
-// -//
-//

{doc.title}

-//

-// Added: {format(new Date(doc.createdAt), 'MMM dd, yyyy')} -//

-//
-//
- -//
-// -// -//
-//
-// ))} -//
-// )} -//
-// ); -// })} - -// {Object.keys(documents).length === 0 && ( -//
-// No documents available -//
-// )} -//
-//
-//
-// ) - -// } - -// export default AdminPanel; -// import { useState, useEffect } from 'react'; -// import { useAuth } from '../../hooks/useAuth'; -// import { format } from 'date-fns'; -// import { -// FiUpload, -// FiDownload, -// FiUsers, -// FiFile, -// FiTrash2, -// FiShare2, -// FiLoader, -// FiSearch, -// FiChevronRight, -// FiUserPlus, -// FiEdit2, -// FiKey -// } from 'react-icons/fi'; -// import api from '../../services/api'; - -// function AdminPanel() { -// const [documents, setDocuments] = useState({}); -// const [users, setUsers] = useState([]); -// const [expandedUsers, setExpandedUsers] = useState({}); -// const [loading, setLoading] = useState(true); -// const [error, setError] = useState(''); -// const [selectedFile, setSelectedFile] = useState(null); -// const [uploadTitle, setUploadTitle] = useState(''); -// const [selectedUser, setSelectedUser] = useState(''); -// const [searchTerm, setSearchTerm] = useState(''); -// const [activeTab, setActiveTab] = useState('documents'); // 'documents' or 'users' -// const [newUser, setNewUser] = useState({ username: '', password: '', name: '', isAdmin: false }); - -// useEffect(() => { -// fetchData(); -// }, []); - -// const fetchData = async () => { -// try { -// setLoading(true); -// const [documentsRes, usersRes] = await Promise.all([ -// api.get('/admin/documents'), -// api.get('/admin/users') -// ]); - -// const groupedDocs = groupDocumentsByUser(documentsRes.data || []); -// const initialExpandedState = Object.keys(groupedDocs).reduce((acc, userName) => { -// acc[userName] = false; -// return acc; -// }, {}); - -// setDocuments(groupedDocs); -// setUsers(usersRes.data || []); -// setExpandedUsers(initialExpandedState); -// } catch (err) { -// setError('Failed to fetch data'); -// console.error('Error:', err); -// } finally { -// setLoading(false); -// } -// }; - -// const groupDocumentsByUser = (docs) => { -// return docs.reduce((acc, doc) => { -// const userName = doc.sharedWith?.name || 'Unassigned'; -// if (!acc[userName]) { -// acc[userName] = []; -// } -// acc[userName].push(doc); -// return acc; -// }, {}); -// }; - -// const handleAddUser = async (e) => { -// e.preventDefault(); -// try { -// await api.post('/admin/users', newUser); -// setNewUser({ username: '', password: '', name: '', isAdmin: false }); -// fetchData(); -// alert('User added successfully'); -// } catch (err) { -// console.error('Error adding user:', err); -// alert('Failed to add user'); -// } -// }; - -// const handleDeleteUser = async (userId) => { -// if (!window.confirm('Are you sure you want to delete this user?')) return; -// try { -// await api.delete(`/admin/users/${userId}`); -// fetchData(); -// alert('User deleted successfully'); -// } catch (err) { -// console.error('Error deleting user:', err); -// alert('Failed to delete user'); -// } -// }; - -// const handleResetPassword = async (userId) => { -// const newPassword = prompt('Enter new password:'); -// if (!newPassword) return; - -// try { -// await api.post(`/admin/users/${userId}/reset-password`, { password: newPassword }); -// alert('Password reset successfully'); -// } catch (err) { -// console.error('Error resetting password:', err); -// alert('Failed to reset password'); -// } -// }; - -// const handleFileUpload = async (e) => { -// e.preventDefault(); -// if (!selectedFile || !uploadTitle || !selectedUser) { -// alert('Please fill in all fields'); -// return; -// } - -// const formData = new FormData(); -// formData.append('file', selectedFile); -// formData.append('title', uploadTitle); -// formData.append('sharedWith', selectedUser); - -// try { -// await api.post('/admin/documents', formData, { -// headers: { -// 'Content-Type': 'multipart/form-data', -// }, -// }); - -// setSelectedFile(null); -// setUploadTitle(''); -// setSelectedUser(''); -// fetchData(); -// alert('Document uploaded successfully'); -// } catch (err) { -// console.error('Upload error:', err); -// alert('Failed to upload document'); -// } -// }; -// const toggleUser = (userName) => { -// console.log('Toggling user:', userName); // Debug log -// setExpandedUsers(prev => ({ -// ...prev, -// [userName]: !prev[userName] -// })); -// }; - - - -// const handleDownload = async (s3Key, fileName) => { -// try { -// const token = localStorage.getItem('token'); -// // Remove 'documents/' from the s3Key as it's already in the path -// const cleanS3Key = s3Key.replace('documents/', ''); - -// const response = await fetch(`http://localhost:3000/admin/documents/download/${cleanS3Key}`, { -// headers: { -// 'Authorization': `Bearer ${token}` -// } -// }); - -// if (!response.ok) { -// throw new Error('Download failed'); -// } - -// const blob = await response.blob(); -// const url = window.URL.createObjectURL(blob); -// const link = document.createElement('a'); -// link.href = url; -// link.download = fileName; -// document.body.appendChild(link); -// link.click(); -// document.body.removeChild(link); -// window.URL.revokeObjectURL(url); -// } catch (err) { -// console.error('Error downloading document:', err); -// alert('Failed to download document. Please try again.'); -// } -// }; - - -// if (loading) { -// return ( -//
-//
-// -// Loading admin panel... -//
-//
-// ); -// } - -// return ( -//
-//
-//
-//

Admin Dashboard

-//

Manage documents and users

-//
- -// {/* Tab Navigation */} -//
-// -// -//
- -// {activeTab === 'documents' ? ( -// <> -// {/* Upload Section */} -//
-//

Upload Document

-//
-//
-//
-// -// setUploadTitle(e.target.value)} -// className="w-full px-4 py-2 bg-white/5 border border-gray-700 rounded-lg focus:outline-none focus:border-blue-500 text-white placeholder-gray-400" -// placeholder="Enter document title" -// /> -//
- -//
-// -// -//
- -//
-// -// setSelectedFile(e.target.files[0])} -// className="w-full px-4 py-2 bg-white/5 border border-gray-700 rounded-lg focus:outline-none focus:border-blue-500 text-white file:mr-4 file:py-2 file:px-4 file:rounded-lg file:border-0 file:text-sm file:font-semibold file:bg-blue-500 file:text-white hover:file:bg-blue-600" -// /> -//
-//
- -// -//
-//
- -// {/* Documents List */} -//
-// {Object.entries(documents).map(([userName, userDocs]) => ( -//
-// -// {expandedUsers[userName] && ( -//
-// {userDocs.map(doc => ( -//
-//
-// -//
-//

{doc.title}

-//

-// Added: {format(new Date(doc.createdAt), 'MMM dd, yyyy')} -//

-//
-//
- -//
-// -// -// -//
-//
-// ))} -//
-// )} -//
-// ))} -//
-// -// ) : ( -// // Users Management Section -//
-// {/* Add New User Form */} -//
-//

Add New User

-//
-//
-// -// setNewUser({ ...newUser, username: e.target.value })} -// className="w-full px-4 py-2 bg-white/5 border border-gray-700 rounded-lg focus:outline-none focus:border-blue-500 text-white" -// required -// /> -//
-//
-// -// setNewUser({ ...newUser, password: e.target.value })} -// className="w-full px-4 py-2 bg-white/5 border border-gray-700 rounded-lg focus:outline-none focus:border-blue-500 text-white" -// required -// /> -//
-//
-// -// setNewUser({ ...newUser, name: e.target.value })} -// className="w-full px-4 py-2 bg-white/5 border border-gray-700 rounded-lg focus:outline-none focus:border-blue-500 text-white" -// required -// /> -//
-//
-// setNewUser({ ...newUser, isAdmin: e.target.checked })} -// className="w-4 h-4 rounded border-gray-700 text-blue-600 focus:ring-blue-500" -// /> -// -//
-//
-// -//
-//
-//
- -// {/* Users List */} -//
-//
-//

Users

-//
-//
-// {Array.isArray(users) && users.map(user => ( -//
-//
-// -//
-//

{user.name}

-//

@{user.username}

-//
-// {user.isAdmin && ( -// -// Admin -// -// )} -//
- -//
-// -// -//
-//
-// ))} -//
-//
-//
-// )} -//
-//
-// ); -// } - -// export default AdminPanel; \ No newline at end of file +export default AdminPanel; \ No newline at end of file