Initial commit
This commit is contained in:
151
resources/views/livewire/user-presence.blade.php
Normal file
151
resources/views/livewire/user-presence.blade.php
Normal file
@@ -0,0 +1,151 @@
|
||||
<div class="user-presence-container border rounded p-4 my-3 bg-white">
|
||||
<div class="mb-4">
|
||||
<h4 class="font-bold text-lg">Online Users ({{ $guard }})</h4>
|
||||
|
||||
@if($showCount)
|
||||
<div class="flex items-center space-x-2 text-sm text-theme-secondary mt-2">
|
||||
<div class="w-2 h-2 bg-green-500 rounded-full animate-pulse"></div>
|
||||
<span>{{ count($onlineUsers) }} {{__('online') }}</span>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="space-y-2 mb-4">
|
||||
@forelse($onlineUsers as $user)
|
||||
<div class="flex items-center space-x-2 bg-gray-50 rounded">
|
||||
<div class="w-2 h-2 bg-green-500 rounded-full"></div>
|
||||
<span class="text-sm font-medium">{{ $user['name'] ?? 'Unknown' }}</span>
|
||||
<small class="text-theme-muted">
|
||||
@if(isset($user['last_seen']))
|
||||
{{ \Carbon\Carbon::parse($user['last_seen'])->diffForHumans() }}
|
||||
@else
|
||||
{{__('Now')}}
|
||||
@endif
|
||||
</small>
|
||||
</div>
|
||||
@empty
|
||||
<div class="text-theme-muted text-sm italic">{{__('No users online') }}</div>
|
||||
@endforelse
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{{-- Enhanced JavaScript with offline detection --}}
|
||||
@push('scripts')
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
let lastActivity = Date.now();
|
||||
let offlineTimeout;
|
||||
|
||||
function dispatchUserActivity() {
|
||||
let success = false;
|
||||
|
||||
try {
|
||||
// Method 1: Direct component method call (most reliable)
|
||||
const presenceContainers = document.querySelectorAll('.user-presence-container');
|
||||
presenceContainers.forEach(container => {
|
||||
const wireId = container.getAttribute('wire:id');
|
||||
if (wireId) {
|
||||
try {
|
||||
const component = window.Livewire.find(wireId);
|
||||
if (component && typeof component.call === 'function') {
|
||||
component.call('handleUserActivity');
|
||||
success = true;
|
||||
}
|
||||
} catch (e) {
|
||||
// component not available
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Method 2: Global dispatch (as backup)
|
||||
if (!success && window.Livewire && typeof window.Livewire.dispatch === 'function') {
|
||||
window.Livewire.dispatch('user-activity');
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
// dispatch failed
|
||||
}
|
||||
}
|
||||
|
||||
function dispatchUserOffline() {
|
||||
try {
|
||||
// Direct component method call (most reliable)
|
||||
const presenceContainers = document.querySelectorAll('.user-presence-container');
|
||||
presenceContainers.forEach(container => {
|
||||
const wireId = container.getAttribute('wire:id');
|
||||
if (wireId) {
|
||||
try {
|
||||
const component = window.Livewire.find(wireId);
|
||||
if (component && typeof component.call === 'function') {
|
||||
component.call('handleUserOffline');
|
||||
}
|
||||
} catch (e) {
|
||||
// component not available
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
} catch (e) {
|
||||
// dispatch failed
|
||||
}
|
||||
}
|
||||
|
||||
function updateActivity() {
|
||||
const now = Date.now();
|
||||
|
||||
// Clear existing offline timeout
|
||||
if (offlineTimeout) {
|
||||
clearTimeout(offlineTimeout);
|
||||
}
|
||||
|
||||
// Only dispatch if 15 seconds have passed
|
||||
if (now - lastActivity > 15000) {
|
||||
lastActivity = now;
|
||||
dispatchUserActivity();
|
||||
}
|
||||
|
||||
// Set offline timeout for 2 minutes of inactivity
|
||||
offlineTimeout = setTimeout(() => {
|
||||
dispatchUserOffline();
|
||||
}, 120000);
|
||||
}
|
||||
|
||||
// Activity tracking
|
||||
['click', 'keypress', 'mousemove', 'scroll'].forEach(event => {
|
||||
document.addEventListener(event, updateActivity, { passive: true });
|
||||
});
|
||||
|
||||
// Page visibility handling
|
||||
document.addEventListener('visibilitychange', function() {
|
||||
if (document.hidden) {
|
||||
// User switched tabs - set shorter offline timeout
|
||||
if (offlineTimeout) clearTimeout(offlineTimeout);
|
||||
offlineTimeout = setTimeout(() => {
|
||||
dispatchUserOffline();
|
||||
}, 30000);
|
||||
} else {
|
||||
// User came back - immediate activity
|
||||
updateActivity();
|
||||
}
|
||||
});
|
||||
|
||||
// Handle page unload
|
||||
window.addEventListener('beforeunload', function() {
|
||||
dispatchUserOffline();
|
||||
});
|
||||
|
||||
// Initial activity setup
|
||||
updateActivity();
|
||||
|
||||
// Manual triggers for testing
|
||||
window.triggerPresenceActivity = function() {
|
||||
dispatchUserActivity();
|
||||
};
|
||||
|
||||
window.triggerPresenceOffline = function() {
|
||||
dispatchUserOffline();
|
||||
};
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
Reference in New Issue
Block a user