From 31523741ab3ff005a37dfdd5b03ce28c3a1ccbb9 Mon Sep 17 00:00:00 2001 From: DariusIII Date: Mon, 27 Oct 2025 22:15:05 +0100 Subject: [PATCH] Update recent activity --- .../Controllers/Admin/AdminPageController.php | 107 +++ resources/css/csp-safe.css | 772 +----------------- resources/views/admin/dashboard.blade.php | 19 +- 3 files changed, 139 insertions(+), 759 deletions(-) diff --git a/app/Http/Controllers/Admin/AdminPageController.php b/app/Http/Controllers/Admin/AdminPageController.php index b732d0b51..680bc0e91 100644 --- a/app/Http/Controllers/Admin/AdminPageController.php +++ b/app/Http/Controllers/Admin/AdminPageController.php @@ -43,9 +43,116 @@ class AdminPageController extends BasePageController 'userStats' => $userStats, 'stats' => $this->getDefaultStats(), 'systemMetrics' => $this->getSystemMetrics(), + 'recent_activity' => $this->getRecentUserActivity(), ])); } + /** + * Get recent user activity (registrations, deletions, activations, role changes) + */ + protected function getRecentUserActivity(): array + { + $activities = []; + + // Get newly registered users (last 7 days) + $newUsers = \App\Models\User::select('id', 'username', 'created_at') + ->where('created_at', '>=', now()->subDays(7)) + ->orderBy('created_at', 'desc') + ->limit(10) + ->get(); + + foreach ($newUsers as $user) { + $activities[] = (object) [ + 'type' => 'registration', + 'message' => "New user registered: {$user->username}", + 'icon' => 'user-plus', + 'icon_bg' => 'bg-green-100 dark:bg-green-900', + 'icon_color' => 'text-green-600 dark:text-green-400', + 'created_at' => $user->created_at, + 'username' => $user->username, + ]; + } + + // Get recently deleted users (last 7 days) - only soft deleted + $deletedUsers = \App\Models\User::onlyTrashed() + ->select('id', 'username', 'deleted_at') + ->where('deleted_at', '>=', now()->subDays(7)) + ->orderBy('deleted_at', 'desc') + ->limit(10) + ->get(); + + foreach ($deletedUsers as $user) { + $activities[] = (object) [ + 'type' => 'deletion', + 'message' => "User deleted: {$user->username}", + 'icon' => 'user-minus', + 'icon_bg' => 'bg-red-100 dark:bg-red-900', + 'icon_color' => 'text-red-600 dark:text-red-400', + 'created_at' => $user->deleted_at, + 'username' => $user->username, + ]; + } + + // Get recently activated users (last 7 days) + $activatedUsers = \App\Models\User::select('id', 'username', 'email_verified_at') + ->whereNotNull('email_verified_at') + ->where('email_verified_at', '>=', now()->subDays(7)) + ->orderBy('email_verified_at', 'desc') + ->limit(10) + ->get(); + + foreach ($activatedUsers as $user) { + $activities[] = (object) [ + 'type' => 'activation', + 'message' => "User activated: {$user->username}", + 'icon' => 'user-check', + 'icon_bg' => 'bg-blue-100 dark:bg-blue-900', + 'icon_color' => 'text-blue-600 dark:text-blue-400', + 'created_at' => $user->email_verified_at, + 'username' => $user->username, + ]; + } + + // Get users with recent role changes (last 7 days) + $roleChanges = \App\Models\User::select('id', 'username', 'rolechangedate', 'roles_id') + ->whereNotNull('rolechangedate') + ->where('rolechangedate', '>=', now()->subDays(7)) + ->orderBy('rolechangedate', 'desc') + ->limit(10) + ->get(); + + foreach ($roleChanges as $user) { + // Get role name safely + $roleName = 'Unknown'; + if ($user->roles_id) { + try { + $role = \Spatie\Permission\Models\Role::find($user->roles_id); + $roleName = $role ? $role->name : 'Unknown'; + } catch (\Exception $e) { + $roleName = 'Role #'.$user->roles_id; + } + } + + $activities[] = (object) [ + 'type' => 'role_change', + 'message' => "User role changed: {$user->username} → {$roleName}", + 'icon' => 'user-tag', + 'icon_bg' => 'bg-purple-100 dark:bg-purple-900', + 'icon_color' => 'text-purple-600 dark:text-purple-400', + 'created_at' => \Carbon\Carbon::parse($user->rolechangedate), + 'username' => $user->username, + ]; + } + + // Sort all activities by date (most recent first) + usort($activities, function ($a, $b) { + return $b->created_at <=> $a->created_at; + }); + + // Return only the 10 most recent + return array_slice($activities, 0, 10); + } + /** * Get default dashboard statistics */ diff --git a/resources/css/csp-safe.css b/resources/css/csp-safe.css index 8aa3f98b6..87630fe8d 100644 --- a/resources/css/csp-safe.css +++ b/resources/css/csp-safe.css @@ -1,774 +1,44 @@ -/* Sidebar Menu Animations */ -.rotate-180 { - transform: rotate(180deg); +/* Admin Dashboard - Recent Activity Styles */ +.activity-item { + transition: background-color 0.2s ease-in-out; } -.sidebar-toggle .fa-chevron-down, -[data-toggle-submenu] .fa-chevron-down { - transition: transform 0.3s ease; +.activity-item:hover { + transform: translateX(2px); } -.sidebar-submenu { - transition: all 0.3s ease; -} - -/* Mobile Sidebar */ -@media (max-width: 768px) { - #sidebar { - position: fixed; - top: 0; - left: -100%; - height: 100vh; - width: 280px; - z-index: 999; - transition: left 0.3s ease-in-out; - overflow-y: auto; - } - - #sidebar.mobile-open { - left: 0; - display: flex !important; - } - - /* Mobile overlay */ - .mobile-sidebar-overlay { - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: rgba(0, 0, 0, 0.5); - z-index: 998; - display: none; - } - - .mobile-sidebar-overlay.active { - display: block; - } -} - -/* Admin Dashboard Charts */ +/* Chart Container Responsive Sizing */ .chart-container { position: relative; - height: 300px; + height: 250px; width: 100%; } -@media (max-width: 768px) { - .chart-container { - height: 250px; - } +/* Smooth transitions for metric updates */ +[data-metric] { + transition: color 0.3s ease-in-out, transform 0.3s ease-in-out; } -/* Toast Notifications */ -#toast-container { - position: fixed; - top: 1rem; - right: 1rem; - z-index: 9999; - display: flex; - flex-direction: column; - gap: 0.5rem; - pointer-events: none; +[data-metric].metric-updated { + animation: pulse 0.5s ease-in-out; } -/* Mobile Toast Notifications */ -@media (max-width: 640px) { - #toast-container { - top: 0.5rem; - right: 0.5rem; - left: 0.5rem; - max-width: 100%; - } -} - -.toast-notification { - display: flex; - align-items: center; - gap: 0.75rem; - min-width: 300px; - max-width: 500px; - padding: 1rem 1.25rem; - border-radius: 0.5rem; - box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); - animation: slideIn 0.3s ease-out; - pointer-events: auto; - transition: all 0.3s ease; -} - -.toast-notification.removing { - animation: slideOut 0.3s ease-in; - opacity: 0; - transform: translateX(100%); -} - -/* Success Toast */ -.toast-notification.success { - background-color: #10b981; - color: white; -} - -.dark .toast-notification.success { - background-color: #059669; -} - -/* Error Toast */ -.toast-notification.error { - background-color: #ef4444; - color: white; -} - -.dark .toast-notification.error { - background-color: #dc2626; -} - -/* Info Toast */ -.toast-notification.info { - background-color: #3b82f6; - color: white; -} - -.dark .toast-notification.info { - background-color: #2563eb; -} - -/* Warning Toast */ -.toast-notification.warning { - background-color: #f59e0b; - color: white; -} - -.dark .toast-notification.warning { - background-color: #d97706; -} - -.toast-icon { - flex-shrink: 0; - font-size: 1.25rem; -} - -.toast-message { - flex: 1; - font-size: 0.875rem; - font-weight: 500; - line-height: 1.5; -} - -.toast-close { - flex-shrink: 0; - background: transparent; - border: none; - color: inherit; - font-size: 1.5rem; - line-height: 1; - cursor: pointer; - padding: 0; - margin-left: 0.5rem; - opacity: 0.8; - transition: opacity 0.2s; -} - -.toast-close:hover { - opacity: 1; -} - -@keyframes slideIn { - from { - transform: translateX(100%); - opacity: 0; - } - to { - transform: translateX(0); +@keyframes pulse { + 0%, 100% { opacity: 1; } -} - -@keyframes slideOut { - from { - transform: translateX(0); - opacity: 1; - } - to { - transform: translateX(100%); - opacity: 0; + 50% { + opacity: 0.7; } } -/* Inline form display */ -.inline-form { - display: inline; +/* Quick Links hover effects */ +.quick-link-item { + transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out; } -/* Line clamp utility for text truncation */ -.line-clamp-2 { - display: -webkit-box; - -webkit-line-clamp: 2; - -webkit-box-orient: vertical; - overflow: hidden; -} - -/* Admin Tmux - Select color states - Light mode */ -#tmuxForm select.select-yes { - background-color: #d1e7dd !important; - border-color: #badbcc !important; - color: #0f5132 !important; -} - -#tmuxForm select.select-no { - background-color: #f8d7da !important; - border-color: #f5c2c7 !important; - color: #842029 !important; -} - -#tmuxForm select.select-other { - background-color: #e2e3e5 !important; - border-color: #d3d6d8 !important; - color: #41464b !important; -} - -#tmuxForm select:focus { - box-shadow: 0 0 0 .25rem rgba(13,110,253,.25); -} - -/* Admin Tmux - Select color states - Dark mode */ -@media (prefers-color-scheme: dark) { - #tmuxForm select.select-yes { - background-color: #1a3a2a !important; - border-color: #2d5a3d !important; - color: #7fc99b !important; - } - - #tmuxForm select.select-no { - background-color: #3a1a1d !important; - border-color: #5a2d31 !important; - color: #f5a9b0 !important; - } - - #tmuxForm select.select-other { - background-color: #2a2a2a !important; - border-color: #3d3d3d !important; - color: #b0b0b0 !important; - } -} - -/* Also support dark mode class on html element */ -html.dark #tmuxForm select.select-yes { - background-color: #1a3a2a !important; - border-color: #2d5a3d !important; - color: #7fc99b !important; -} - -html.dark #tmuxForm select.select-no { - background-color: #3a1a1d !important; - border-color: #5a2d31 !important; - color: #f5a9b0 !important; -} - -html.dark #tmuxForm select.select-other { - background-color: #2a2a2a !important; - border-color: #3d3d3d !important; - color: #b0b0b0 !important; -} -/* Dropdown menu hidden by default */ -.dropdown-menu { - display: none; -} - -.dropdown-menu.show { - display: block; -} - -/* Chart container heights */ -.chart-container { - height: 250px; - max-height: 250px; - position: relative; -} - -/* Fixed widths for table columns */ -.col-width-180 { - width: 180px; -} - -.col-width-160 { - width: 160px; -} - -.col-width-170 { - width: 170px; -} - -.col-width-200 { - width: 200px; -} - -/* Image max heights */ -.img-max-h-400 { - max-height: 400px; -} - -/* Forum quote styling */ -.forum-quote { - border-color: #eee; -} - -.dark .forum-quote { - border-color: #374151; -} - -/* Email styles (for email templates) */ -.email-text-center { - text-align: center; -} - -.email-code-block { - word-break: break-all; - background-color: #f8f9fa; - padding: 10px; - border-radius: 4px; -} - -/* Profile Page Tab Content */ -.tab-content { - display: none; -} - -.tab-content:first-of-type, -.tab-content.active { - display: block; -} - -.dark .email-code-block { - background-color: #1f2937; -} - -/* Modal z-index and display */ -.modal-hidden { - display: none; - z-index: 9999 !important; -} - -.modal-visible { - display: flex; - z-index: 9999 !important; -} - -/* Modal content max height */ -.modal-content-scroll { - max-height: calc(90vh - 80px); -} - -/* Cart table column width */ -.cart-checkbox-col { - width: 30px; -} - -/* Checkbox visibility improvements for dark mode */ -input[type="checkbox"].form-checkbox, -input[type="checkbox"].cart-checkbox { - border-width: 2px; -} - -@media (prefers-color-scheme: dark) { - input[type="checkbox"].form-checkbox, - input[type="checkbox"].cart-checkbox { - background-color: #374151; - border-color: #6b7280; - } - - input[type="checkbox"].form-checkbox:checked, - input[type="checkbox"].cart-checkbox:checked { - background-color: #3b82f6; - border-color: #3b82f6; - } -} - -html.dark input[type="checkbox"].form-checkbox, -html.dark input[type="checkbox"].cart-checkbox { - background-color: #374151; - border-color: #6b7280; -} - -html.dark input[type="checkbox"].form-checkbox:checked, -html.dark input[type="checkbox"].cart-checkbox:checked { - background-color: #3b82f6; - border-color: #3b82f6; -} - -/* Admin Groups Management - Fade Out Animation */ -.fade-out { - transition: opacity 0.3s ease; - opacity: 0; -} - -/* My Movies/Shows Page Styles */ -.header-gradient { - background: linear-gradient(135deg, #2563eb 0%, #1e40af 100%); -} - -.info-card-gradient { - background: linear-gradient(135deg, #eff6ff 0%, #e0e7ff 100%); -} - -.dark .info-card-gradient { - background: linear-gradient(135deg, #1e3a8a 0%, #1e40af 100%); -} - -.table-header-gradient { - background: linear-gradient(135deg, #f9fafb 0%, #f3f4f6 100%); -} - -.dark .table-header-gradient { - background: linear-gradient(135deg, #1f2937 0%, #374151 100%); -} - -.movie-poster-shadow { +.quick-link-item:hover { + transform: translateY(-2px); box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); } -.category-badge { - background: linear-gradient(135deg, #dbeafe 0%, #bfdbfe 100%); -} - -.dark .category-badge { - background: linear-gradient(135deg, #1e40af 0%, #1e3a8a 100%); - color: #93c5fd !important; - border-color: #2563eb !important; -} - -.empty-state-bg { - background: linear-gradient(135deg, #dbeafe 0%, #e0e7ff 100%); -} - -.dark .empty-state-bg { - background: linear-gradient(135deg, #1e3a8a 0%, #1e40af 100%); -} - -.show-avatar { - background: linear-gradient(135deg, #3b82f6 0%, #6366f1 100%); -} - -/* My Shows Table Borders */ -table { - border-collapse: collapse; -} - -table thead tr { - border-bottom: 2px solid #e5e7eb; -} - -.dark table thead tr { - border-bottom-color: #4b5563; -} - -table tbody tr { - border-bottom: 1px solid #e5e7eb; -} - -.dark table tbody tr { - border-bottom-color: #374151; -} - -table tbody tr:last-child { - border-bottom: none; -} - -/* Checkbox :has() fallback for older browsers */ -@supports not selector(:has(*)) { - label:has(input[type="checkbox"]:checked) { - background-color: #eff6ff !important; - border-color: #3b82f6 !important; - color: #1e40af !important; - } -} - -/* Content Page Prose Styles */ -.prose h1, .prose h2, .prose h3, .prose h4, .prose h5, .prose h6 { - margin-top: 1.5em; - margin-bottom: 0.75em; - font-weight: 600; -} - -.prose p { - margin-bottom: 1em; -} - -.prose ul, .prose ol { - margin-bottom: 1em; - padding-left: 1.5em; -} - -.prose a { - color: #2563eb; - text-decoration: underline; -} - -/* Preview Modal Styles */ -#previewModal { - display: none; - z-index: 9999 !important; -} - -#previewModal:not(.hidden) { - display: flex; -} - -.prose a:hover { - color: #1d4ed8; -} - -.prose img { - max-width: 100%; - height: auto; - border-radius: 0.5rem; - margin: 1.5em 0; -} - -.prose blockquote { - border-left: 4px solid #e5e7eb; - padding-left: 1em; - color: #6b7280; - font-style: italic; - margin: 1.5em 0; -} - -.prose code { - background-color: #f3f4f6; - padding: 0.2em 0.4em; - border-radius: 0.25rem; - font-size: 0.875em; -} - -/* Cart Confirmation Modal Styles */ -.confirmation-modal { - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - background-color: rgba(0, 0, 0, 0.5); - display: flex; - align-items: center; - justify-content: center; - z-index: 99999; - animation: fadeIn 0.2s ease-out; -} - -.confirmation-modal-content { - background: white; - border-radius: 12px; - box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2); - max-width: 500px; - width: 90%; - padding: 24px; - animation: slideUp 0.3s ease-out; -} - -@media (prefers-color-scheme: dark) { - .confirmation-modal-content { - background: #1f2937; - box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5); - } -} - -.confirmation-modal-header { - display: flex; - align-items: center; - margin-bottom: 16px; -} - -.confirmation-modal-icon { - width: 48px; - height: 48px; - background-color: #fee2e2; - border-radius: 50%; - display: flex; - align-items: center; - justify-content: center; - margin-right: 16px; -} - -@media (prefers-color-scheme: dark) { - .confirmation-modal-icon { - background-color: #7f1d1d; - } -} - -html.dark .confirmation-modal-icon { - background-color: #7f1d1d; -} - -.confirmation-modal-icon i { - color: #ef4444; - font-size: 24px; -} - -@media (prefers-color-scheme: dark) { - .confirmation-modal-icon i { - color: #fca5a5; - } -} - -html.dark .confirmation-modal-icon i { - color: #fca5a5; -} - -.confirmation-modal-title { - font-size: 20px; - font-weight: 600; - color: #1f2937; -} - -@media (prefers-color-scheme: dark) { - .confirmation-modal-title { - color: #f3f4f6; - } -} - -html.dark .confirmation-modal-title { - color: #f3f4f6; -} - -.confirmation-modal-body { - color: #6b7280; - margin-bottom: 24px; - line-height: 1.6; -} - -@media (prefers-color-scheme: dark) { - .confirmation-modal-body { - color: #d1d5db; - } -} - -html.dark .confirmation-modal-body { - color: #d1d5db; -} - -.confirmation-modal-footer { - display: flex; - justify-content: flex-end; - gap: 12px; -} - -.confirmation-modal-footer button { - padding: 10px 20px; - border-radius: 6px; - font-weight: 500; - cursor: pointer; - transition: all 0.2s; - border: none; - font-size: 14px; -} - -.btn-cancel { - background-color: #f3f4f6; - color: #374151; -} - -.btn-cancel:hover { - background-color: #e5e7eb; -} - -@media (prefers-color-scheme: dark) { - .btn-cancel { - background-color: #374151; - color: #d1d5db; - } - - .btn-cancel:hover { - background-color: #4b5563; - } -} - -html.dark .btn-cancel { - background-color: #374151; - color: #d1d5db; -} - -html.dark .btn-cancel:hover { - background-color: #4b5563; -} - -.btn-confirm { - background-color: #ef4444; - color: white; -} - -.btn-confirm:hover { - background-color: #dc2626; -} - -@media (prefers-color-scheme: dark) { - .btn-confirm { - background-color: #dc2626; - } - - .btn-confirm:hover { - background-color: #b91c1c; - } -} - -html.dark .btn-confirm { - background-color: #dc2626; -} - -html.dark .btn-confirm:hover { - background-color: #b91c1c; -} - -@keyframes fadeIn { - from { - opacity: 0; - } - to { - opacity: 1; - } -} - -@keyframes fadeOut { - from { - opacity: 1; - } - to { - opacity: 0; - } -} - -@keyframes slideUp { - from { - transform: translateY(20px); - opacity: 0; - } - to { - transform: translateY(0); - opacity: 1; - } -} - -/* Contact Page Container */ -.contact-page-container { - max-width: 75% !important; - width: 75% !important; -} - -@media (min-width: 1536px) { - .contact-page-container { - max-width: 1200px !important; - } -} - -/* Toast Container Override */ -#toast-container { - position: fixed; - top: 20px; - right: 20px; - z-index: 99999; - max-width: 350px; - pointer-events: none; -} - -/* Preview/Sample Image Modal */ -#previewModal { - z-index: 9999 !important; -} diff --git a/resources/views/admin/dashboard.blade.php b/resources/views/admin/dashboard.blade.php index c3bbcbbee..f18c8cc31 100644 --- a/resources/views/admin/dashboard.blade.php +++ b/resources/views/admin/dashboard.blade.php @@ -441,23 +441,26 @@ -
-

Recent Activity

+
+

+ + Recent User Activity +

@if(isset($recent_activity) && count($recent_activity) > 0) @foreach($recent_activity as $activity) -
-
- +
+
+
-

{{ $activity->message }}

-

{{ $activity->created_at->diffForHumans() }}

+

{{ $activity->message }}

+

{{ $activity->created_at->diffForHumans() }}

@endforeach @else -

No recent activity

+

No recent activity

@endif