Files
Virtnet.bond/extensions/Others/SocialBase/resources/views/livewire/messaging-interface.blade.php
2025-11-30 11:57:22 +01:00

957 lines
76 KiB
PHP

<div class="container mx-auto px-4 py-12">
@include('socialbase::components.scrollbar-styles')
<div class="bg-white dark:bg-gray-800 rounded-2xl shadow-2xl border-2 border-gray-200 dark:border-gray-600 overflow-hidden" style="height: 800px; display: grid; grid-template-columns: 1fr 2fr;">
<!-- Conversations List -->
<div class="border-r-2 border-gray-200 dark:border-gray-600 bg-gray-50 dark:bg-gray-900 flex flex-col" style="height: 800px;">
<div class="px-4 py-5 border-b-2 border-gray-200 dark:border-gray-600 bg-gray-50 dark:bg-gray-900 flex-shrink-0">
<div class="flex items-center justify-between">
<h2 class="text-xl font-semibold text-gray-900 dark:text-white flex items-center gap-2">
<i class="ri-message-3-line"></i>
Messages
</h2>
<button
@click="$dispatch('open-create-group')"
class="px-3 py-2 bg-primary hover:from-blue-700 hover:to-purple-700 text-white rounded-lg font-medium shadow-md hover:shadow-lg transition-all text-sm flex items-center gap-2"
title="Create Group Chat">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"/>
</svg>
<span>New</span>
</button>
</div>
</div>
<div class="flex-1 overflow-y-auto socialbase-scroll divide-y divide-gray-200 dark:divide-gray-700">
@forelse($conversations as $conversation)
<div
wire:click="selectConversation({{ $conversation['id'] }})"
class="p-4 cursor-pointer transition-colors border-b border-gray-100 dark:border-gray-800 {{ $selectedConversation == $conversation['id'] ? 'bg-blue-50 dark:bg-blue-900/20 border-l-4 border-l-blue-500' : 'hover:bg-gray-50 dark:hover:bg-gray-800 border-l-4 border-l-transparent' }} group relative"
>
<!-- Pin Button (hidden for system conversations) -->
@if($conversation['type'] !== 'system')
<button
wire:click.stop="togglePin({{ $conversation['id'] }})"
class="absolute top-2 right-2 p-1.5 rounded-lg transition-colors {{ $conversation['is_pinned'] ? 'text-yellow-500 hover:text-yellow-600' : 'text-gray-400 hover:text-gray-600 dark:text-gray-500 dark:hover:text-gray-300 opacity-0 group-hover:opacity-100' }}"
title="{{ $conversation['is_pinned'] ? 'Unpin conversation' : 'Pin conversation' }}"
>
<svg class="w-4 h-4 {{ $conversation['is_pinned'] ? 'fill-current' : '' }}" fill="{{ $conversation['is_pinned'] ? 'currentColor' : 'none' }}" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 5a2 2 0 012-2h10a2 2 0 012 2v16l-7-3.5L5 21V5z"/>
</svg>
</button>
@endif
<div class="flex items-center gap-3">
@if($conversation['type'] === 'direct' && $conversation['other_user'])
<img
src="{{ $conversation['other_user']['avatar'] }}"
alt="{{ $conversation['other_user']['name'] }}"
class="w-12 h-12 rounded-full object-cover"
>
<div class="flex-1 min-w-0">
<div class="flex items-center justify-between">
<h3 class="font-semibold text-gray-900 dark:text-white truncate">
{{ $conversation['other_user']['name'] }}
</h3>
@if($conversation['unread_count'] > 0)
<span class="bg-blue-500 text-white text-xs px-2 py-1 rounded-full">
{{ $conversation['unread_count'] }}
</span>
@endif
</div>
@if($conversation['last_message'])
<p class="text-sm text-gray-500 dark:text-gray-400 truncate">
{{ \Illuminate\Support\Str::limit(strip_tags(preg_replace('/\*\*|\*|__|_|~~|`|```|\|\||\[([^\]]+)\]\([^\)]+\)/', '$1', $conversation['last_message']->content)), 50) }}
</p>
@endif
@if($conversation['last_message_at'])
<p class="text-xs text-gray-400 dark:text-gray-500">
{{ $conversation['last_message_at']->diffForHumans() }}
</p>
@endif
</div>
@elseif($conversation['type'] === 'group')
<!-- Group Avatar -->
<div class="relative flex-shrink-0">
@if(count($conversation['participants']) > 0)
<div class="flex -space-x-2">
@foreach(array_slice($conversation['participants'], 0, 2) as $participant)
@if($participant['avatar'])
<img src="{{ $participant['avatar'] }}"
alt="{{ $participant['name'] }}"
class="w-8 h-8 rounded-full border-2 border-white dark:border-gray-800 object-cover" />
@else
<div class="w-8 h-8 rounded-full border-2 border-white dark:border-gray-800 bg-gradient-to-br from-purple-500 to-pink-600 flex items-center justify-center text-white text-xs font-bold">
{{ strtoupper(substr($participant['name'], 0, 1)) }}
</div>
@endif
@endforeach
</div>
@else
<div class="w-12 h-12 rounded-full bg-gradient-to-br from-purple-500 to-pink-600 flex items-center justify-center">
<svg class="w-6 h-6 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z"/>
</svg>
</div>
@endif
</div>
<div class="flex-1 min-w-0">
<div class="flex items-center justify-between">
<div class="flex items-center gap-2">
<h3 class="font-semibold text-gray-900 dark:text-white truncate">
{{ $conversation['subject'] ?? 'Group Chat' }}
</h3>
<span class="text-xs text-gray-500 dark:text-gray-400">
({{ $conversation['participants_count'] }})
</span>
</div>
@if($conversation['unread_count'] > 0)
<span class="bg-blue-500 text-white text-xs px-2 py-1 rounded-full">
{{ $conversation['unread_count'] }}
</span>
@endif
</div>
@if($conversation['last_message'])
<p class="text-sm text-gray-500 dark:text-gray-400 truncate">
{{ \Illuminate\Support\Str::limit(strip_tags(preg_replace('/\*\*|\*|__|_|~~|`|```|\|\||\[([^\]]+)\]\([^\)]+\)/', '$1', $conversation['last_message']->content)), 50) }}
</p>
@endif
@if($conversation['last_message_at'])
<p class="text-xs text-gray-400 dark:text-gray-500">
{{ $conversation['last_message_at']->diffForHumans() }}
</p>
@endif
</div>
@elseif($conversation['type'] === 'system')
<div class="w-12 h-12 rounded-full bg-blue-500 flex items-center justify-center">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-6 h-6 text-white">
<path d="M20 17H22V19H2V17H4V10C4 5.58172 7.58172 2 12 2C16.4183 2 20 5.58172 20 10V17ZM9 21H15V23H9V21Z"></path>
</svg>
</div>
<div class="flex-1 min-w-0">
<div class="flex items-center justify-between">
<h3 class="font-semibold text-gray-900 dark:text-white">
System Messages
</h3>
@if($conversation['unread_count'] > 0)
<span class="bg-blue-500 text-white text-xs px-2 py-1 rounded-full">
{{ $conversation['unread_count'] }}
</span>
@endif
</div>
@if($conversation['last_message'])
<p class="text-sm text-gray-500 dark:text-gray-400 truncate">
{{ \Illuminate\Support\Str::limit(strip_tags(preg_replace('/\*\*|\*|__|_|~~|`|```|\|\||\[([^\]]+)\]\([^\)]+\)/', '$1', $conversation['last_message']->content)), 50) }}
</p>
@endif
</div>
@endif
</div>
</div>
@empty
<div class="p-8 text-center text-gray-500 dark:text-gray-400">
<i class="ri-message-3-line text-4xl mb-2"></i>
<p>No messages yet</p>
</div>
@endforelse
</div>
</div>
<!-- Message Thread -->
<div class="flex flex-col bg-white dark:bg-gray-900" style="height: 800px;">
@if($selectedConversation)
<!-- Chat Header -->
@php
$currentConversation = collect($conversations)->firstWhere('id', $selectedConversation);
$otherUser = $currentConversation['other_user'] ?? null;
@endphp
@if($otherUser)
<div class="flex-shrink-0 px-4 py-5 border-b-2 border-gray-200 dark:border-gray-600 bg-white dark:bg-gray-800">
<div class="flex items-center justify-between">
<a href="{{ route('socialbase.profile.show', $otherUser['id']) }}" class="flex items-center gap-3 hover:opacity-80 transition-opacity">
<img
src="{{ $otherUser['avatar'] }}"
alt="{{ $otherUser['name'] }}"
class="w-10 h-10 rounded-full object-cover"
>
<div>
<h3 class="font-semibold text-gray-900 dark:text-white">{{ $otherUser['name'] }}</h3>
<p class="text-xs text-gray-500 dark:text-gray-400">View Profile</p>
</div>
</a>
<div class="relative" x-data="{ open: false }">
<button
@click="open = !open"
class="p-2 hover:bg-gray-200 dark:hover:bg-gray-700 rounded-lg transition-colors"
>
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-gray-600 dark:text-gray-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="1"/>
<circle cx="19" cy="12" r="1"/>
<circle cx="5" cy="12" r="1"/>
</svg>
</button>
<div
x-show="open"
@click.away="open = false"
x-transition
class="absolute right-0 mt-2 w-48 bg-white dark:bg-gray-800 rounded-lg shadow-lg border border-gray-200 dark:border-gray-700 z-10"
>
<a
href="{{ route('socialbase.profile.show', $otherUser['id']) }}"
class="block px-4 py-2 text-sm text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-t-lg"
>
<i class="ri-user-line mr-2"></i>View Profile
</a>
<button
@click="$dispatch('open-report-modal'); userDropdownOpen = false"
class="w-full text-left px-4 py-2 text-sm text-red-600 dark:text-red-400 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-b-lg"
>
<i class="ri-flag-line mr-2"></i>Report User
</button>
</div>
</div>
</div>
</div>
@elseif($currentConversation && $currentConversation['type'] === 'group')
<!-- Group Chat Header -->
<div class="flex-shrink-0 px-4 py-5 border-b-2 border-gray-200 dark:border-gray-600 bg-gradient-to-r from-purple-50 to-pink-50 dark:from-purple-900/20 dark:to-pink-900/20">
<div class="flex items-center justify-between">
<div class="flex items-center gap-3">
<!-- Group Avatar -->
<div class="relative flex-shrink-0">
@if(count($currentConversation['participants']) > 0)
<div class="flex -space-x-2">
@foreach(array_slice($currentConversation['participants'], 0, 3) as $participant)
@if($participant['avatar'])
<img src="{{ $participant['avatar'] }}"
alt="{{ $participant['name'] }}"
class="w-8 h-8 rounded-full border-2 border-white dark:border-gray-800 object-cover" />
@else
<div class="w-8 h-8 rounded-full border-2 border-white dark:border-gray-800 bg-gradient-to-br from-purple-500 to-pink-600 flex items-center justify-center text-white text-xs font-bold">
{{ strtoupper(substr($participant['name'], 0, 1)) }}
</div>
@endif
@endforeach
</div>
@endif
</div>
<div>
<h3 class="font-semibold text-gray-900 dark:text-white flex items-center gap-2">
{{ $currentConversation['subject'] ?? 'Group Chat' }}
<span class="text-xs text-gray-500 dark:text-gray-400 font-normal">
({{ $currentConversation['participants_count'] }} members)
</span>
</h3>
<p class="text-xs text-gray-500 dark:text-gray-400">
{{ implode(', ', array_slice(array_column($currentConversation['participants'], 'name'), 0, 3)) }}
@if($currentConversation['participants_count'] > 3)
and {{ $currentConversation['participants_count'] - 3 }} more
@endif
</p>
</div>
</div>
<div class="flex items-center gap-2">
<!-- Group Management Dropdown -->
<div class="relative" x-data="{ groupMenuOpen: false }">
<button
@click="groupMenuOpen = !groupMenuOpen"
class="p-2 hover:bg-purple-100 dark:hover:bg-purple-900/30 rounded-lg transition-colors"
title="Group Options">
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 text-gray-600 dark:text-gray-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="1"/>
<circle cx="19" cy="12" r="1"/>
<circle cx="5" cy="12" r="1"/>
</svg>
</button>
<div
x-show="groupMenuOpen"
@click.away="groupMenuOpen = false"
x-transition
class="absolute right-0 mt-2 w-56 bg-white dark:bg-gray-800 rounded-lg shadow-lg border border-gray-200 dark:border-gray-700 z-50"
style="display: none;">
<div class="py-1">
<div class="px-4 py-2 text-xs text-gray-500 dark:text-gray-400 border-b border-gray-200 dark:border-gray-700">
Group Options
</div>
@if(Auth::id() == $currentConversation['created_by'])
<button
wire:click="openAddMembersModal"
@click="groupMenuOpen = false"
class="w-full text-left px-4 py-2 text-sm text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 flex items-center gap-2">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M18 9v3m0 0v3m0-3h3m-3 0h-3m-2-5a4 4 0 11-8 0 4 4 0 018 0zM3 20a6 6 0 0112 0v1H3v-1z"/>
</svg>
<span>Add Members</span>
</button>
<button
wire:click="openRenameModal"
@click="groupMenuOpen = false"
class="w-full text-left px-4 py-2 text-sm text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 flex items-center gap-2">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"/>
</svg>
<span>Rename Group</span>
</button>
@endif
<button
wire:click="openViewMembersModal"
@click="groupMenuOpen = false"
class="w-full text-left px-4 py-2 text-sm text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 flex items-center gap-2">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z"/>
</svg>
<span>View Members ({{ $currentConversation['participants_count'] }})</span>
</button>
<button
wire:click="leaveGroup"
onclick="return confirm('Are you sure you want to leave this group?')"
@click="groupMenuOpen = false"
class="w-full text-left px-4 py-2 text-sm text-red-600 dark:text-red-400 hover:bg-gray-100 dark:hover:bg-gray-700 flex items-center gap-2 border-t border-gray-200 dark:border-gray-700">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1"/>
</svg>
<span>Leave Group</span>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
@endif
<!-- Messages -->
<div class="flex-1 overflow-y-auto overflow-x-hidden socialbase-scroll p-6 space-y-4"
id="main-chat-messages"
style="background: linear-gradient(to bottom, #f8f9fa 0%, #ffffff 100%); background-image: url('data:image/svg+xml,%3Csvg width=&quot;60&quot; height=&quot;60&quot; viewBox=&quot;0 0 60 60&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;%3E%3Cg fill=&quot;none&quot; fill-rule=&quot;evenodd&quot;%3E%3Cg fill=&quot;%239C92AC&quot; fill-opacity=&quot;0.05&quot;%3E%3Cpath d=&quot;M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z&quot;/%3E%3C/g%3E%3C/g%3E%3C/svg%3E');">
@forelse($messages as $message)
<div class="flex {{ $message['is_mine'] ? 'justify-end' : 'justify-start' }}">
<div class="flex gap-3 max-w-[65%] {{ $message['is_mine'] ? 'flex-row-reverse' : '' }}">
@if(!$message['is_system'])
<img
src="{{ $message['sender_avatar'] }}"
alt="{{ $message['sender_name'] }}"
class="w-10 h-10 rounded-full object-cover flex-shrink-0 ring-2 ring-white shadow-sm"
>
@endif
<div>
@if($message['is_system'])
<div class="flex justify-center my-1">
<div class="max-w-lg w-full">
<div class="bg-gradient-to-br from-blue-50 to-indigo-50 dark:from-blue-900/10 dark:to-indigo-900/10 border border-blue-200 dark:border-blue-800/30 rounded-xl p-2.5 shadow-sm">
<div class="flex items-start gap-2">
<div class="flex-shrink-0">
<div class="w-6 h-6 bg-blue-500/10 dark:bg-blue-500/20 rounded-full flex items-center justify-center">
<svg class="w-3 h-3 text-blue-600 dark:text-blue-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
</svg>
</div>
</div>
<div class="flex-1 min-w-0">
<div class="text-xs text-gray-700 dark:text-gray-300 leading-snug prose prose-sm dark:prose-invert max-w-none [&>strong]:font-semibold [&>strong]:text-blue-700 [&>strong]:dark:text-blue-300 [&>strong]:block [&>strong]:mb-0.5">
{!! \Paymenter\Extensions\Others\SocialBase\Helpers\MessageFormatter::format($message['content']) !!}
</div>
<p class="text-[10px] text-gray-500 dark:text-gray-400 mt-0.5">
{{ $message['created_at']->format('M j, g:i A') }}
</p>
</div>
</div>
</div>
</div>
</div>
@else
<div class="group relative">
<div class="{{ $message['is_mine'] ? 'bg-blue-500 text-white shadow-lg' : 'bg-white dark:bg-gray-700 text-gray-900 dark:text-white shadow-sm border-2 border-gray-200 dark:border-gray-600' }} rounded-2xl px-4 py-3">
@if(!$message['is_mine'])
<p class="font-semibold text-xs mb-1.5 text-gray-700 dark:text-gray-300">{{ $message['sender_name'] }}</p>
@endif
@if(!empty($message['content']))
<div class="text-[15px] leading-relaxed break-words prose prose-sm {{ $message['is_mine'] ? 'prose-invert' : 'dark:prose-invert' }} max-w-none">
{!! \Paymenter\Extensions\Others\SocialBase\Helpers\MessageFormatter::format($message['content']) !!}
</div>
@endif
@if(!empty($message['attachments']))
<div class="mt-2 flex flex-wrap gap-2">
@foreach($message['attachments'] as $index => $attachment)
@php
$isImage = in_array(strtolower($attachment['extension'] ?? ''), ['jpg', 'jpeg', 'png', 'gif', 'webp']);
$isVideo = in_array(strtolower($attachment['extension'] ?? ''), ['mp4', 'mov', 'avi']);
$secureUrl = route('socialbase.messages.attachment.download', ['messageId' => $message['id'], 'attachmentIndex' => $index]);
@endphp
@if($isImage)
<a href="{{ $secureUrl }}" target="_blank" class="block">
<img src="{{ $secureUrl }}" alt="{{ $attachment['name'] ?? 'Image' }}" class="max-w-xs max-h-64 rounded-lg {{ $message['is_mine'] ? 'border-2 border-white/30' : 'border-2 border-gray-300 dark:border-gray-600' }} hover:opacity-90 transition-opacity">
</a>
@elseif($isVideo)
<video controls class="max-w-xs max-h-64 rounded-lg {{ $message['is_mine'] ? 'border-2 border-white/30' : 'border-2 border-gray-300 dark:border-gray-600' }}">
<source src="{{ $secureUrl }}" type="{{ $attachment['type'] ?? 'video/mp4' }}">
</video>
@else
<a href="{{ $secureUrl }}" download="{{ $attachment['name'] ?? 'file' }}" class="flex items-center gap-2 px-3 py-2 {{ $message['is_mine'] ? 'bg-blue-600 hover:bg-blue-700' : 'bg-gray-200 dark:bg-gray-600 hover:bg-gray-300 dark:hover:bg-gray-500' }} rounded-lg transition-colors">
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M4 4a2 2 0 012-2h4.586A2 2 0 0112 2.586L15.414 6A2 2 0 0116 7.414V16a2 2 0 01-2 2H6a2 2 0 01-2-2V4z" clip-rule="evenodd"/>
</svg>
<div class="text-left">
<div class="text-sm font-medium truncate max-w-[200px]">{{ $attachment['name'] ?? 'file' }}</div>
<div class="text-xs opacity-75">{{ strtoupper($attachment['extension'] ?? 'file') }} • {{ number_format(($attachment['size'] ?? 0) / 1024, 1) }} KB</div>
</div>
</a>
@endif
@endforeach
</div>
@endif
</div>
<!-- Message Actions Dropdown -->
@if(!$message['is_system'])
<div class="absolute {{ $message['is_mine'] ? '-left-12' : '-right-12' }} top-1/2 -translate-y-1/2 opacity-0 group-hover:opacity-100 transition-opacity" x-data="{ open: false, showReactions: false }">
<button @click="open = !open" class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg px-2 py-1 shadow-lg hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors">
<svg class="w-4 h-4 text-gray-600 dark:text-gray-300" fill="currentColor" viewBox="0 0 20 20">
<path d="M10 6a2 2 0 110-4 2 2 0 010 4zM10 12a2 2 0 110-4 2 2 0 010 4zM10 18a2 2 0 110-4 2 2 0 010 4z"></path>
</svg>
</button>
<div x-show="open"
@click.away="open = false"
x-transition:enter="transition ease-out duration-100"
x-transition:enter-start="transform opacity-0 scale-95"
x-transition:enter-end="transform opacity-100 scale-100"
x-transition:leave="transition ease-in duration-75"
x-transition:leave-start="transform opacity-100 scale-100"
x-transition:leave-end="transform opacity-0 scale-95"
class="absolute {{ $message['is_mine'] ? 'right-full mr-2' : 'left-full ml-2' }} top-0 w-48 bg-white dark:bg-gray-800 rounded-lg shadow-xl border border-gray-200 dark:border-gray-700 z-50"
style="display: none;">
@if(!$message['is_mine'])
<button @click="showReactions = !showReactions; open = false" class="w-full text-left px-4 py-2 text-sm text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 flex items-center rounded-t-lg transition-colors">
<span class="text-lg mr-2">😊</span>
<span>React</span>
</button>
<button @click="open = false; $dispatch('open-report-modal')" class="w-full text-left px-4 py-2 text-sm text-red-600 dark:text-red-400 hover:bg-red-50 dark:hover:bg-red-900/20 flex items-center transition-colors">
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 21v-4m0 0V5a2 2 0 012-2h6.5l1 1H21l-3 6 3 6h-8.5l-1-1H5a2 2 0 00-2 2zm9-13.5V9"></path>
</svg>
<span>Report</span>
</button>
@else
<button wire:click="deleteMessage({{ $message['id'] }})" @click="open = false" class="w-full text-left px-4 py-2 text-sm text-red-600 dark:text-red-400 hover:bg-red-50 dark:hover:bg-red-900/20 flex items-center rounded-lg transition-colors">
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"></path>
</svg>
<span>Delete</span>
</button>
@endif
</div>
<!-- Reaction Picker (Inside x-data scope) -->
@if(!$message['is_mine'])
<div x-show="showReactions"
@click.away="showReactions = false"
class="absolute {{ $message['is_mine'] ? 'right-0 mr-12' : 'left-0 ml-12' }} top-0 bg-white dark:bg-gray-800 rounded-lg shadow-xl border border-gray-200 dark:border-gray-700 p-3 z-[60]"
style="display: none; min-width: 280px;">
<div class="grid grid-cols-5 gap-2">
<button wire:click="reactToMessage({{ $message['id'] }}, 'like')" @click="showReactions = false" class="text-3xl hover:scale-125 transition-transform p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded" title="Like">👍</button>
<button wire:click="reactToMessage({{ $message['id'] }}, 'love')" @click="showReactions = false" class="text-3xl hover:scale-125 transition-transform p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded" title="Love">❤️</button>
<button wire:click="reactToMessage({{ $message['id'] }}, 'laugh')" @click="showReactions = false" class="text-3xl hover:scale-125 transition-transform p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded" title="Laugh">😂</button>
<button wire:click="reactToMessage({{ $message['id'] }}, 'wow')" @click="showReactions = false" class="text-3xl hover:scale-125 transition-transform p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded" title="Wow">😮</button>
<button wire:click="reactToMessage({{ $message['id'] }}, 'sad')" @click="showReactions = false" class="text-3xl hover:scale-125 transition-transform p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded" title="Sad">😢</button>
<button wire:click="reactToMessage({{ $message['id'] }}, 'angry')" @click="showReactions = false" class="text-3xl hover:scale-125 transition-transform p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded" title="Angry">😠</button>
<button wire:click="reactToMessage({{ $message['id'] }}, 'celebrate')" @click="showReactions = false" class="text-3xl hover:scale-125 transition-transform p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded" title="Celebrate">🎉</button>
<button wire:click="reactToMessage({{ $message['id'] }}, 'thinking')" @click="showReactions = false" class="text-3xl hover:scale-125 transition-transform p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded" title="Thinking">🤔</button>
<button wire:click="reactToMessage({{ $message['id'] }}, 'clap')" @click="showReactions = false" class="text-3xl hover:scale-125 transition-transform p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded" title="Clap">👏</button>
<button wire:click="reactToMessage({{ $message['id'] }}, 'fire')" @click="showReactions = false" class="text-3xl hover:scale-125 transition-transform p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded" title="Fire">🔥</button>
</div>
</div>
@endif
</div>
@endif
</div>
@endif
<!-- Reactions Display -->
@if(isset($message['reactions']) && count($message['reactions']) > 0)
<div class="flex flex-wrap gap-1 mt-2">
@foreach($message['reactions'] as $type => $reaction)
<button
wire:click="reactToMessage({{ $message['id'] }}, '{{ $type }}')"
class="inline-flex items-center gap-1 px-2 py-1 rounded-full text-xs transition-all {{ $reaction['hasCurrentUser'] ? 'bg-blue-100 dark:bg-blue-900 border-2 border-blue-500' : 'bg-gray-100 dark:bg-gray-700 border border-gray-300 dark:border-gray-600 hover:bg-gray-200 dark:hover:bg-gray-600' }}"
title="{{ implode(', ', $reaction['users']) }}">
<span class="text-sm">{{ $reaction['emoji'] }}</span>
<span class="font-medium {{ $reaction['hasCurrentUser'] ? 'text-blue-700 dark:text-blue-300' : 'text-gray-700 dark:text-gray-300' }}">{{ $reaction['count'] }}</span>
</button>
@endforeach
</div>
@endif
<p class="text-[11px] text-gray-500 dark:text-gray-400 mt-1.5 {{ $message['is_mine'] ? 'text-right' : '' }}">
{{ $message['created_at']->format('g:i A') }}
</p>
</div>
</div>
</div>
@empty
<div class="text-center text-gray-500 dark:text-gray-400 py-8">
<i class="ri-chat-3-line text-4xl mb-2"></i>
<p>No messages yet. Start the conversation!</p>
</div>
@endforelse
</div>
<!-- Message Input -->
<div class="flex-shrink-0 border-t-2 border-gray-200 dark:border-gray-600 p-4 bg-white dark:bg-gray-800">
@php
$currentConversation = collect($conversations)->firstWhere('id', $selectedConversation);
$isSystemConversation = $currentConversation && $currentConversation['type'] === 'system';
@endphp
@if($isSystemConversation)
<div class="text-center py-3 px-4 bg-gray-100 dark:bg-gray-700/50 rounded-lg">
<p class="text-sm text-gray-600 dark:text-gray-400 flex items-center justify-center gap-2">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"/>
</svg>
<span>You can only receive system messages, not send them</span>
</p>
</div>
@else
<!-- File Upload Previews -->
@if(!empty($attachments))
<div class="mb-3 p-3 bg-gray-50 dark:bg-gray-700/50 rounded-lg border border-gray-200 dark:border-gray-600">
<div class="flex flex-wrap gap-2">
@foreach($attachments as $index => $attachment)
<div class="relative group">
@php
$isImage = in_array(strtolower($attachment->getClientOriginalExtension()), ['jpg', 'jpeg', 'png', 'gif', 'webp']);
$isVideo = in_array(strtolower($attachment->getClientOriginalExtension()), ['mp4', 'mov', 'avi']);
@endphp
@if($isImage)
<img src="{{ $attachment->temporaryUrl() }}" alt="Preview" class="w-20 h-20 object-cover rounded-lg border-2 border-gray-300 dark:border-gray-600">
@elseif($isVideo)
<div class="w-20 h-20 bg-gray-800 rounded-lg border-2 border-gray-300 dark:border-gray-600 flex items-center justify-center">
<svg class="w-8 h-8 text-white" fill="currentColor" viewBox="0 0 20 20">
<path d="M2 6a2 2 0 012-2h6a2 2 0 012 2v8a2 2 0 01-2 2H4a2 2 0 01-2-2V6zM14.553 7.106A1 1 0 0014 8v4a1 1 0 00.553.894l2 1A1 1 0 0018 13V7a1 1 0 00-1.447-.894l-2 1z"/>
</svg>
</div>
@else
<div class="w-20 h-20 bg-blue-100 dark:bg-blue-900/30 rounded-lg border-2 border-blue-300 dark:border-blue-600 flex flex-col items-center justify-center p-2">
<svg class="w-6 h-6 text-blue-600 dark:text-blue-400" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M4 4a2 2 0 012-2h4.586A2 2 0 0112 2.586L15.414 6A2 2 0 0116 7.414V16a2 2 0 01-2 2H6a2 2 0 01-2-2V4z" clip-rule="evenodd"/>
</svg>
<span class="text-[10px] font-medium text-blue-700 dark:text-blue-300 mt-1 uppercase">{{ $attachment->getClientOriginalExtension() }}</span>
</div>
@endif
<button
type="button"
wire:click="removeAttachment({{ $index }})"
class="absolute -top-2 -right-2 bg-red-500 hover:bg-red-600 text-white rounded-full p-1 opacity-0 group-hover:opacity-100 transition-opacity shadow-lg"
>
<svg class="w-3 h-3" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"/>
</svg>
</button>
<div class="absolute bottom-0 left-0 right-0 bg-black/70 text-white text-[9px] px-1 py-0.5 rounded-b-lg truncate">
{{ $attachment->getClientOriginalName() }}
</div>
</div>
@endforeach
</div>
</div>
@endif
<form wire:submit.prevent="sendMessage" class="flex items-center gap-3">
<input
type="file"
wire:model="attachments"
id="attachment-input-{{ $selectedConversation }}"
multiple
accept="image/*,video/*,.txt,.php,.js,.css,.html,.json,.xml,.md,.zip"
class="hidden"
>
<button
type="button"
onclick="document.getElementById('attachment-input-{{ $selectedConversation }}').click()"
class="text-gray-400 hover:text-blue-500 dark:hover:text-blue-400 transition-colors"
>
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.172 7l-6.586 6.586a2 2 0 102.828 2.828l6.414-6.586a4 4 0 00-5.656-5.656l-6.415 6.585a6 6 0 108.486 8.486L20.5 13"></path>
</svg>
</button>
<input
type="text"
wire:model="newMessage"
placeholder="Type a message..."
class="flex-1 px-5 py-3 bg-gray-100 dark:bg-gray-700 border-0 rounded-full focus:ring-2 focus:ring-blue-500 focus:bg-white dark:focus:bg-gray-600 dark:text-white placeholder-gray-500 transition-all"
>
<button
type="submit"
class="bg-blue-500 hover:bg-blue-600 text-white p-3 rounded-full transition-colors shadow-lg hover:shadow-xl disabled:opacity-50 disabled:cursor-not-allowed"
wire:loading.attr="disabled"
>
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" wire:loading.remove>
<path d="M10.894 2.553a1 1 0 00-1.788 0l-7 14a1 1 0 001.169 1.409l5-1.429A1 1 0 009 15.571V11a1 1 0 112 0v4.571a1 1 0 00.725.962l5 1.428a1 1 0 001.17-1.408l-7-14z"></path>
</svg>
<svg class="animate-spin w-5 h-5" wire:loading xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
</button>
</form>
@error('newMessage')
<p class="text-red-500 text-sm mt-2">{{ $message }}</p>
@enderror
@error('attachments.*')
<p class="text-red-500 text-sm mt-2">{{ $message }}</p>
@enderror
@endif
</div>
@else
<div class="flex-1 flex items-center justify-center text-gray-500 dark:text-gray-400">
<div class="text-center">
<i class="ri-chat-3-line text-6xl mb-4"></i>
<p class="text-lg">Select a conversation to start messaging</p>
</div>
</div>
@endif
</div>
</div>
<script>
function scrollToBottom(force = false) {
const messagesContainer = document.getElementById('main-chat-messages');
if (!messagesContainer) return;
// Check if user is already at the bottom (within 100px threshold)
const isAtBottom = messagesContainer.scrollHeight - messagesContainer.clientHeight <= messagesContainer.scrollTop + 100;
// Scroll if forced or user is already at bottom
if (force || isAtBottom) {
messagesContainer.scrollTo({
top: messagesContainer.scrollHeight,
behavior: force ? 'instant' : 'smooth'
});
}
}
// Auto-scroll to bottom when new messages arrive or messages are loaded
document.addEventListener('livewire:initialized', () => {
// Listen for new message sent
Livewire.on('messageSent', () => {
setTimeout(() => scrollToBottom(false), 100);
});
// Listen for messages loaded (when conversation is selected)
Livewire.on('messagesLoaded', () => {
setTimeout(() => scrollToBottom(true), 150);
});
// Scroll when DOM is updated
Livewire.hook('morph.updated', ({ el, component }) => {
if (el.id === 'main-chat-messages') {
setTimeout(() => scrollToBottom(true), 100);
}
});
});
// Scroll to bottom on initial page load
window.addEventListener('load', () => {
setTimeout(() => scrollToBottom(true), 400);
});
// Scroll to bottom when Livewire finishes initial load
document.addEventListener('livewire:load', () => {
setTimeout(() => scrollToBottom(true), 300);
});
// Additional check after any Livewire update
document.addEventListener('DOMContentLoaded', () => {
const observer = new MutationObserver(() => {
const container = document.getElementById('main-chat-messages');
if (container && container.children.length > 0) {
setTimeout(() => scrollToBottom(true), 100);
}
});
setTimeout(() => {
const container = document.getElementById('main-chat-messages');
if (container) {
observer.observe(container, { childList: true, subtree: false });
}
}, 100);
});
// Mark as read when window/tab gains focus
window.addEventListener('focus', () => {
if (window.Livewire) {
// Trigger refresh to mark messages as read
@this.call('refreshAll');
}
});
// Mark as read periodically if chat is visible and focused
setInterval(() => {
if (!document.hidden && document.hasFocus()) {
@this.call('refreshAll');
}
}, 10000); // Every 10 seconds
</script>
<!-- Report User Component -->
@if($selectedConversation)
@php
$currentConversation = collect($conversations)->firstWhere('id', $selectedConversation);
$otherUser = $currentConversation['other_user'] ?? null;
@endphp
@if($otherUser)
<livewire:socialbase.report-user :userId="$otherUser['id']" :key="'report-user-'.$otherUser['id']" />
@endif
@endif
<!-- Create Group Component -->
<livewire:socialbase.create-group />
<!-- View Members Modal -->
@if($showMembersModal)
<div class="fixed inset-0 z-50 overflow-y-auto" x-data="{ show: @entangle('showMembersModal') }">
<div class="flex items-center justify-center min-h-screen px-4 pt-4 pb-20 text-center sm:p-0">
<div class="fixed inset-0 bg-black/50 backdrop-blur-sm transition-opacity" @click="$wire.closeViewMembersModal()"></div>
<div class="relative inline-block w-full max-w-md my-8 text-left align-middle transition-all transform bg-white dark:bg-gray-800 rounded-2xl shadow-2xl">
<!-- Header -->
<div class="flex items-center justify-between p-6 border-b border-gray-200 dark:border-gray-700">
<div>
<h3 class="text-2xl font-bold text-gray-900 dark:text-white">Group Members</h3>
<p class="text-sm text-gray-500 dark:text-gray-400 mt-1">Manage your group members</p>
</div>
<button wire:click="closeViewMembersModal" class="text-gray-400 hover:text-gray-500 dark:hover:text-gray-300 transition-colors">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
</svg>
</button>
</div>
<div class="p-6">
<div class="space-y-3 max-h-96 overflow-y-auto socialbase-scroll">
@foreach($groupMembers as $member)
<div class="flex items-center justify-between p-4 rounded-lg transition-colors {{ $member['is_creator'] ? 'bg-purple-50 dark:bg-purple-900/20 border border-purple-200 dark:border-purple-800' : 'bg-gray-50 dark:bg-gray-700/50 hover:bg-gray-100 dark:hover:bg-gray-700' }}">
<div class="flex items-center gap-3">
<img src="{{ $member['avatar'] }}" alt="{{ $member['name'] }}" class="w-12 h-12 rounded-full object-cover">
<div>
<p class="font-semibold text-gray-900 dark:text-white flex items-center gap-2">
{{ $member['name'] }}
@if($member['is_creator'])
<span class="text-xs bg-purple-500 text-white px-2 py-1 rounded-full">Creator</span>
@endif
</p>
<p class="text-sm text-gray-500 dark:text-gray-400">{{ $member['email'] }}</p>
</div>
</div>
@if(!$member['is_creator'] && Auth::id() == collect($conversations)->firstWhere('id', $selectedConversation)['created_by'])
<button
wire:click="removeMember({{ $member['id'] }})"
onclick="return confirm('Remove this member from the group?')"
class="text-red-600 hover:text-red-700 dark:text-red-400 p-2 rounded-lg hover:bg-red-50 dark:hover:bg-red-900/20 transition-colors"
title="Remove member">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
</svg>
</button>
@endif
</div>
@endforeach
</div>
<div class="mt-6 pt-4 border-t border-gray-200 dark:border-gray-700">
<button wire:click="closeViewMembersModal" class="w-full px-4 py-3 bg-gray-100 hover:bg-gray-200 dark:bg-gray-700 dark:hover:bg-gray-600 text-gray-900 dark:text-white rounded-lg font-medium transition-colors">
Close
</button>
</div>
</div>
</div>
</div>
</div>
@endif
<!-- Add Members Modal -->
@if($showAddMembersModal)
<div class="fixed inset-0 z-50 overflow-y-auto" x-data="{ show: @entangle('showAddMembersModal'), searchQuery: '' }">
<div class="flex items-center justify-center min-h-screen px-4 pt-4 pb-20 text-center sm:p-0">
<div class="fixed inset-0 bg-black/50 backdrop-blur-sm transition-opacity" @click="$wire.closeAddMembersModal()"></div>
<div class="relative inline-block w-full max-w-md my-8 text-left align-middle transition-all transform bg-white dark:bg-gray-800 rounded-2xl shadow-2xl">
<!-- Header -->
<div class="flex items-center justify-between p-6 border-b border-gray-200 dark:border-gray-700">
<div>
<h3 class="text-2xl font-bold text-gray-900 dark:text-white">Add Members</h3>
<p class="text-sm text-gray-500 dark:text-gray-400 mt-1">Invite more people to the group</p>
</div>
<button wire:click="closeAddMembersModal" class="text-gray-400 hover:text-gray-500 dark:hover:text-gray-300 transition-colors">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
</svg>
</button>
</div>
<div class="p-6 space-y-4">
<!-- Search Input -->
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Search Users</label>
<input
type="text"
x-model="searchQuery"
placeholder="Search users by name..."
class="w-full px-4 py-3 bg-white dark:bg-gray-900 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent text-gray-900 dark:text-white placeholder-gray-400 transition-all">
</div>
<!-- Users List -->
<div class="space-y-2 max-h-64 overflow-y-auto socialbase-scroll">
@foreach($availableUsers as $user)
<div
x-show="searchQuery === '' || '{{ strtolower($user['name']) }}'.includes(searchQuery.toLowerCase())"
class="flex items-center gap-3 p-3 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700 cursor-pointer transition-colors"
wire:click="toggleUserToAdd({{ $user['id'] }})">
<div class="relative flex-shrink-0">
<div class="w-5 h-5 border-2 rounded {{ in_array($user['id'], $selectedUsersToAdd) ? 'bg-purple-600 border-purple-600' : 'border-gray-300 dark:border-gray-600' }} flex items-center justify-center transition-all">
@if(in_array($user['id'], $selectedUsersToAdd))
<svg class="w-3 h-3 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="4" d="M5 13l4 4L19 7"/>
</svg>
@endif
</div>
</div>
<img src="{{ $user['avatar'] }}" alt="{{ $user['name'] }}" class="w-10 h-10 rounded-full object-cover flex-shrink-0">
<div class="flex-1 min-w-0">
<p class="font-semibold text-gray-900 dark:text-white truncate">{{ $user['name'] }}</p>
</div>
</div>
@endforeach
</div>
<!-- Selected Count -->
@if(count($selectedUsersToAdd) > 0)
<div class="p-4 bg-purple-50 dark:bg-purple-900/20 rounded-lg border border-purple-200 dark:border-purple-800">
<p class="text-sm font-medium text-purple-700 dark:text-purple-300">
{{ count($selectedUsersToAdd) }} {{ count($selectedUsersToAdd) === 1 ? 'user' : 'users' }} selected
</p>
</div>
@endif
<!-- Actions -->
<div class="flex gap-3 pt-4 border-t border-gray-200 dark:border-gray-700">
<button
wire:click="closeAddMembersModal"
class="flex-1 px-4 py-3 bg-gray-100 hover:bg-gray-200 dark:bg-gray-700 dark:hover:bg-gray-600 text-gray-900 dark:text-white rounded-lg font-medium transition-colors">
Cancel
</button>
<button
wire:click="addMembersToGroup"
class="flex-1 px-4 py-3 bg-purple-600 hover:bg-purple-700 disabled:bg-gray-400 disabled:cursor-not-allowed text-white rounded-lg font-medium transition-colors"
{{ count($selectedUsersToAdd) === 0 ? 'disabled' : '' }}>
Add Members
</button>
</div>
</div>
</div>
</div>
</div>
@endif
<!-- Rename Group Modal -->
@if($showRenameModal)
<div class="fixed inset-0 z-50 overflow-y-auto" x-data="{ show: @entangle('showRenameModal') }">
<div class="flex items-center justify-center min-h-screen px-4 pt-4 pb-20 text-center sm:p-0">
<div class="fixed inset-0 bg-black/50 backdrop-blur-sm transition-opacity" @click="$wire.closeRenameModal()"></div>
<div class="relative inline-block w-full max-w-md my-8 text-left align-middle transition-all transform bg-white dark:bg-gray-800 rounded-2xl shadow-2xl">
<!-- Header -->
<div class="flex items-center justify-between p-6 border-b border-gray-200 dark:border-gray-700">
<div>
<h3 class="text-2xl font-bold text-gray-900 dark:text-white">Rename Group</h3>
<p class="text-sm text-gray-500 dark:text-gray-400 mt-1">Choose a new name for your group</p>
</div>
<button wire:click="closeRenameModal" class="text-gray-400 hover:text-gray-500 dark:hover:text-gray-300 transition-colors">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
</svg>
</button>
</div>
<form wire:submit.prevent="renameGroup" class="p-6 space-y-6">
<div>
<label for="newGroupName" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
Group Name <span class="text-red-500">*</span>
</label>
<input
type="text"
id="newGroupName"
wire:model="newGroupName"
class="w-full px-4 py-3 bg-white dark:bg-gray-900 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent text-gray-900 dark:text-white placeholder-gray-400 transition-all"
placeholder="Enter new group name...">
@error('newGroupName')
<p class="text-red-500 text-sm mt-2">{{ $message }}</p>
@enderror
</div>
<div class="flex gap-3 pt-4 border-t border-gray-200 dark:border-gray-700">
<button
type="button"
wire:click="closeRenameModal"
class="flex-1 px-4 py-3 bg-gray-100 hover:bg-gray-200 dark:bg-gray-700 dark:hover:bg-gray-600 text-gray-900 dark:text-white rounded-lg font-medium transition-colors">
Cancel
</button>
<button
type="submit"
class="flex-1 px-4 py-3 bg-purple-600 hover:bg-purple-700 text-white rounded-lg font-medium transition-colors">
Rename Group
</button>
</div>
</form>
</div>
</div>
</div>
@endif
@include('socialbase::components.scrollbar-styles')
<script>
// Notification sound function
function playNotificationSound() {
try {
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
const oscillator = audioContext.createOscillator();
const gainNode = audioContext.createGain();
oscillator.connect(gainNode);
gainNode.connect(audioContext.destination);
oscillator.frequency.setValueAtTime(800, audioContext.currentTime);
oscillator.frequency.exponentialRampToValueAtTime(400, audioContext.currentTime + 0.1);
gainNode.gain.setValueAtTime(0.3, audioContext.currentTime);
gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.3);
oscillator.start(audioContext.currentTime);
oscillator.stop(audioContext.currentTime + 0.3);
} catch (e) {
console.log('Could not play notification sound');
}
}
// Listen for message sent events
document.addEventListener('livewire:initialized', () => {
Livewire.on('messageSent', () => {
playNotificationSound();
});
});
</script>
</div>