Update New Features

This commit is contained in:
Koncept Kit
2025-12-10 17:52:47 +07:00
parent 1f27c3224b
commit 36017e8693
39 changed files with 4977 additions and 196 deletions

View File

@@ -15,7 +15,12 @@ import {
ChevronLeft,
ChevronRight,
LogOut,
Menu
Menu,
Image,
FileText,
DollarSign,
Scale,
HardDrive
} from 'lucide-react';
const AdminSidebar = ({ isOpen, onToggle, isMobile }) => {
@@ -23,6 +28,9 @@ const AdminSidebar = ({ isOpen, onToggle, isMobile }) => {
const navigate = useNavigate();
const { user, logout } = useAuth();
const [pendingCount, setPendingCount] = useState(0);
const [storageUsed, setStorageUsed] = useState(0);
const [storageLimit, setStorageLimit] = useState(0);
const [storagePercentage, setStoragePercentage] = useState(0);
// Fetch pending approvals count
useEffect(() => {
@@ -44,6 +52,33 @@ const AdminSidebar = ({ isOpen, onToggle, isMobile }) => {
return () => clearInterval(interval);
}, []);
// Fetch storage usage
useEffect(() => {
const fetchStorageUsage = async () => {
try {
const response = await api.get('/admin/storage/usage');
setStorageUsed(response.data.total_bytes_used);
setStorageLimit(response.data.max_bytes_allowed);
setStoragePercentage(response.data.percentage);
} catch (error) {
console.error('Failed to fetch storage usage:', error);
}
};
fetchStorageUsage();
// Refresh storage usage every 60 seconds
const interval = setInterval(fetchStorageUsage, 60000);
return () => clearInterval(interval);
}, []);
const formatBytes = (bytes) => {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
};
const handleLogout = () => {
logout();
navigate('/login');
@@ -85,7 +120,31 @@ const AdminSidebar = ({ isOpen, onToggle, isMobile }) => {
name: 'Events',
icon: Calendar,
path: '/admin/events',
disabled: true
disabled: false
},
{
name: 'Gallery',
icon: Image,
path: '/admin/gallery',
disabled: false
},
{
name: 'Newsletters',
icon: FileText,
path: '/admin/newsletters',
disabled: false
},
{
name: 'Financials',
icon: DollarSign,
path: '/admin/financials',
disabled: false
},
{
name: 'Bylaws',
icon: Scale,
path: '/admin/bylaws',
disabled: false
},
{
name: 'Roles',
@@ -233,6 +292,48 @@ const AdminSidebar = ({ isOpen, onToggle, isMobile }) => {
</div>
)}
{/* Storage Usage Widget */}
<div className="mb-2">
{isOpen ? (
<div className="px-4 py-3 bg-[#F8F7FB] rounded-lg">
<div className="flex items-center justify-between mb-2">
<span className="text-sm font-medium text-[#422268]">Storage Usage</span>
<span className="text-xs text-[#664fa3]">{storagePercentage}%</span>
</div>
<div className="w-full bg-[#ddd8eb] rounded-full h-2">
<div
className={`h-2 rounded-full transition-all ${
storagePercentage > 90 ? 'bg-red-500' :
storagePercentage > 75 ? 'bg-yellow-500' :
'bg-[#81B29A]'
}`}
style={{ width: `${storagePercentage}%` }}
/>
</div>
<p className="text-xs text-[#664fa3] mt-1">
{formatBytes(storageUsed)} / {formatBytes(storageLimit)}
</p>
</div>
) : (
<div className="flex justify-center">
<div className="relative group">
<HardDrive className={`h-5 w-5 ${
storagePercentage > 90 ? 'text-red-500' :
storagePercentage > 75 ? 'text-yellow-500' :
'text-[#664fa3]'
}`} />
{storagePercentage > 75 && (
<div className="absolute -top-1 -right-1 bg-red-500 h-2 w-2 rounded-full" />
)}
{/* Tooltip */}
<div className="absolute left-full ml-2 top-1/2 -translate-y-1/2 px-3 py-2 bg-[#422268] text-white text-sm rounded-lg opacity-0 group-hover:opacity-100 pointer-events-none transition-opacity whitespace-nowrap z-50">
Storage: {storagePercentage}%
</div>
</div>
</div>
)}
</div>
{/* Logout Button */}
<button
onClick={handleLogout}