Initial commit

This commit is contained in:
Ronald Huynen
2026-03-23 21:37:59 +01:00
commit 2547717edb
2193 changed files with 972171 additions and 0 deletions

View File

@@ -0,0 +1,197 @@
<div class="online-reacted-profiles" wire:poll.{{ $refreshInterval }}s="loadOnlineReactedProfiles">
{{-- Header with count --}}
@if ($headerText && $showCount && $totalCount > 0)
<div class="mb-4 flex items-center justify-between">
<div class="flex items-center space-x-2 text-xs text-theme-muted">
<div class="h-2 w-2 rounded-full bg-green-500"></div>
<span class="font-sm">
{{ $headerText }}
</span>
</div>
{{-- Count by type if multiple guards --}}
@if (count($countByType) > 1)
<div class="flex items-center space-x-3 text-xs text-theme-muted">
@foreach ($countByType as $type => $count)
<span class="ml-2">
{{ __($modelLabels[$type]) ?? __(class_basename($type)) }}: {{ $count }}
</span>
@endforeach
</div>
@endif
</div>
@endif
{{-- Profiles Display --}}
@if ($groupByModel && is_array($onlineReactedProfiles))
{{-- Grouped by Model Type --}}
@foreach ($onlineReactedProfiles as $modelType => $profiles)
<div class="grouped-profiles mb-6">
<h3 class="mb-3 text-sm font-medium text-theme-primary border-l-4 border-theme-border pl-3">
{{ __($modelLabels[$modelType]) ?? __(class_basename($modelType)) }}
</h3>
<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 gap-3">
@foreach ($profiles as $profile)
<div class="profile-card">
<a href="{{ $profile['profile_url'] }}" class="block">
<div class="flex items-center p-2 rounded-lg hover:bg-gray-50 transition-colors duration-150">
<div class="flex-shrink-0">
<div class="relative block cursor-pointer">
<img alt="profile"
class="h-8 w-8 rounded-full object-cover outline outline-1 outline-offset-1 outline-gray-500"
src="{{ Storage::url($profile['avatar']) }}" />
</div>
</div>
<div class="ml-3 min-w-0 flex-1">
<div class="font-bold text-sm text-theme-primary truncate">
{{ $profile['name'] }}
</div>
<div class="text-xs font-normal text-theme-muted truncate">
{{ $profile['location'] }}
</div>
@if ($lastSeen)
<div class="text-xs text-theme-muted truncate">
@if ($profile['last_seen'])
{{ \Carbon\Carbon::parse($profile['last_seen'])->diffForHumans() }}
@else
{{ __('online') }}
@endif
</div>
@endif
@if (getActiveProfileType() === 'Admin' && !$this->isCurrentUserProfile($profile['id'], $profile['model_type']))
<button wire:click="openLogoutModal({{ $profile['id'] }}, '{{ addslashes($profile['model_type']) }}')"
class="text-xs text-red-600 hover:text-red-800 underline mt-1"
onclick="event.preventDefault(); event.stopPropagation();">
{{ __('Log out') }}
</button>
@endif
</div>
</div>
</a>
</div>
@endforeach
</div>
</div>
@endforeach
@else
{{-- Not grouped --}}
@if(count($onlineReactedProfiles) > 0)
<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 gap-3">
@foreach($onlineReactedProfiles as $profile)
<div class="profile-card">
<a href="{{ $profile['profile_url'] }}" class="block">
<div class="flex items-center p-2 rounded-lg hover:bg-gray-50 transition-colors duration-150">
<div class="flex-shrink-0">
<div class="relative block cursor-pointer">
<img alt="profile"
class="h-8 w-8 rounded-full object-cover outline outline-1 outline-offset-1 outline-gray-500"
src="{{ Storage::url($profile['avatar']) }}" />
</div>
</div>
<div class="ml-3 min-w-0 flex-1">
<div class="font-bold text-sm text-theme-primary truncate">
{{ $profile['name'] }}
</div>
<div class="text-xs font-normal text-theme-muted truncate">
{{ $profile['location'] }}
</div>
@if ($lastSeen)
<div class="text-xs text-theme-muted truncate">
@if ($profile['last_seen'])
{{ \Carbon\Carbon::parse($profile['last_seen'])->diffForHumans() }}
@else
{{ __('online') }}
@endif
</div>
@endif
@if (getActiveProfileType() === 'Admin' && !$this->isCurrentUserProfile($profile['id'], $profile['model_type']))
<button wire:click="openLogoutModal({{ $profile['id'] }}, '{{ addslashes($profile['model_type']) }}')"
class="text-xs text-red-600 hover:text-red-800 underline mt-1"
onclick="event.preventDefault(); event.stopPropagation();">
{{ __('Log out') }}
</button>
@endif
</div>
</div>
</a>
</div>
@endforeach
</div>
@else
<div class="mb-4 flex items-center justify-between">
<div class="flex items-center space-x-2 text-sm text-theme-muted">
<span class="font-sm">
{{trans_choice('messages.reactions_contacts_online', 0, ['count' => 0]) }}
</span>
</div>
</div>
@endif
@endif
{{-- Logout Confirmation Modal --}}
@if (getActiveProfileType() === 'Admin')
<x-jetstream.dialog-modal wire:model.live="showLogoutModal">
<x-slot name="title">
{{ __('Log out user') }}
</x-slot>
<x-slot name="content">
<div class="text-base mb-4">{{ __('Are you sure you want to log out this user?') }}</div>
@if ($selectedProfileId && $selectedProfileType)
@php
$selectedProfile = $selectedProfileType::find($selectedProfileId);
@endphp
@if ($selectedProfile)
<div class="flex items-center p-2">
<div class="flex-shrink-0">
<div class="relative block">
<img alt="profile"
class="h-8 w-8 rounded-full profile-photo object-cover outline outline-1 outline-offset-1 outline-gray-500"
src="{{ Storage::url($selectedProfile->profile_photo_path) }}" />
</div>
</div>
<div class="ml-3 min-w-0 flex-1">
<div class="font-bold text-sm text-theme-primary truncate">
{{ $selectedProfile->name }}
</div>
<div class="text-xs font-normal text-theme-muted truncate">
{{ $selectedProfile->getLocationFirst()['name_short'] ?? '' }}
</div>
</div>
</div>
@endif
@endif
</x-slot>
<x-slot name="footer">
<x-jetstream.secondary-button wire:click="closeLogoutModal">
{{ __('Cancel') }}
</x-jetstream.secondary-button>
<x-jetstream.danger-button wire:click="logoutUser" wire:loading.attr="disabled" class="ml-3">
<span wire:loading.remove wire:target="logoutUser">{{ __('Log out') }}</span>
<span wire:loading wire:target="logoutUser">{{ __('Loading...') }}</span>
</x-jetstream.danger-button>
</x-slot>
</x-jetstream.dialog-modal>
@endif
</div>
{{-- Include JavaScript for real-time updates --}}
@push('scripts')
<script>
document.addEventListener('DOMContentLoaded', function() {
// Listen for presence updates from other components
window.addEventListener('presence-channel-updated', function(event) {
@this.call('loadOnlineReactedProfiles');
});
// Listen for reaction changes
window.addEventListener('reaction-toggled', function(event) {
@this.call('loadOnlineReactedProfiles');
});
});
</script>
@endpush