ultimatepos/Modules/Portal/Http/Controllers/Customer/CommunicationController.php

225 lines
7.7 KiB
PHP

<?php
namespace Modules\Portal\Http\Controllers\Customer;
use App\Business;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Schema;
use Modules\Communication\Entities\ChatMessage;
use Modules\Communication\Entities\ChatRoom;
use Modules\Communication\Events\MessageSent;
use Modules\Communication\Services\ChatRoomService;
use Modules\Communication\Services\PresenceService;
use Modules\Portal\Http\Controllers\BasePortalController;
use Modules\Portal\Services\CustomerSpecialistService;
class CommunicationController extends BasePortalController
{
public function __construct(
protected CustomerSpecialistService $specialistService,
protected ChatRoomService $chatRoomService,
protected PresenceService $presenceService
) {}
public function index()
{
$this->ensureCrmSubscription();
$business_id = $this->businessId();
$contact_id = $this->contactId();
$specialists = $this->specialistsWithPresence($business_id, $contact_id);
$onlineSpecialists = $specialists->where('is_online', true)->values();
$business = Business::with(['locations' => fn ($q) => $q->limit(1)])->findOrFail($business_id);
$chatEnabled = $this->chatEnabled();
$presenceEnabled = $this->presenceEnabled();
$support_phone = optional($business->locations->first())->mobile;
return view('portal::customer.communications.index', compact(
'specialists', 'onlineSpecialists', 'business', 'chatEnabled', 'presenceEnabled', 'support_phone'
));
}
public function chat(int $specialist_id)
{
$this->ensureCrmSubscription();
if (! $this->chatEnabled()) {
abort(404);
}
$business_id = $this->businessId();
$contact_id = $this->contactId();
$specialist = $this->specialistService->assertSpecialistForContact($business_id, $contact_id, $specialist_id);
$room = $this->chatRoomService->findOrCreateDirectRoom($business_id, auth()->user(), $specialist->id);
if ($this->presenceEnabled()) {
$this->presenceService->heartbeat($business_id, auth()->id());
}
$is_online = $this->presenceEnabled()
&& $this->presenceService->isOnline($business_id, $specialist->id);
return view('portal::customer.communications.chat', [
'specialist' => [
'id' => $specialist->id,
'name' => trim($specialist->surname.' '.$specialist->first_name.' '.$specialist->last_name),
'mobile' => $specialist->contact_no,
'email' => $specialist->email,
'is_online' => $is_online,
],
'room_id' => $room->id,
'presenceEnabled' => $this->presenceEnabled(),
]);
}
public function presence()
{
$this->ensureCrmSubscription();
$business_id = $this->businessId();
$contact_id = $this->contactId();
return response()->json($this->specialistsWithPresence($business_id, $contact_id));
}
public function specialistPresence(int $specialist_id)
{
$this->ensureCrmSubscription();
$business_id = $this->businessId();
$contact_id = $this->contactId();
$specialist = $this->specialistService->assertSpecialistForContact($business_id, $contact_id, $specialist_id);
if ($this->presenceEnabled()) {
$this->presenceService->heartbeat($business_id, auth()->id());
}
return response()->json([
'id' => $specialist->id,
'is_online' => $this->presenceEnabled()
&& $this->presenceService->isOnline($business_id, $specialist->id),
]);
}
public function heartbeat()
{
$this->ensureCrmSubscription();
if ($this->presenceEnabled()) {
$this->presenceService->heartbeat($this->businessId(), auth()->id());
}
return response()->json(['success' => true]);
}
public function messages(Request $request, int $room_id)
{
$this->ensureCrmSubscription();
$room = $this->assertCustomerRoom($room_id);
$messages = ChatMessage::where('chat_room_id', $room->id)
->with('user:id,surname,first_name,last_name')
->orderBy('created_at')
->get()
->map(fn ($m) => [
'id' => $m->id,
'body' => $m->body,
'user_id' => $m->user_id,
'created_at' => $m->created_at?->format('Y-m-d H:i'),
'is_mine' => (int) $m->user_id === (int) auth()->id(),
]);
return response()->json($messages);
}
public function sendMessage(Request $request, int $room_id)
{
$this->ensureCrmSubscription();
$validated = $request->validate([
'body' => 'required|string|max:5000',
]);
$room = $this->assertCustomerRoom($room_id);
$business_id = $this->businessId();
$message = ChatMessage::create([
'chat_room_id' => $room->id,
'user_id' => auth()->id(),
'body' => $validated['body'],
'type' => 'text',
]);
$room->update(['last_message_at' => now()]);
$room->members()->updateExistingPivot(auth()->id(), ['last_read_at' => now()]);
try {
event(new MessageSent($message->load('user:id,surname,first_name,last_name,username,email'), $business_id));
} catch (\Throwable $e) {
report($e);
}
return response()->json([
'id' => $message->id,
'body' => $message->body,
'user_id' => $message->user_id,
'created_at' => $message->created_at?->format('Y-m-d H:i'),
'is_mine' => true,
]);
}
public function markRead(int $room_id)
{
$this->ensureCrmSubscription();
$room = $this->assertCustomerRoom($room_id);
$room->members()->updateExistingPivot(auth()->id(), ['last_read_at' => now()]);
return response()->json(['success' => true]);
}
private function chatEnabled(): bool
{
return Schema::hasTable('chat_rooms')
&& Schema::hasTable('chat_messages')
&& class_exists(ChatRoomService::class);
}
private function presenceEnabled(): bool
{
return $this->chatEnabled() && class_exists(PresenceService::class);
}
private function specialistsWithPresence(int $business_id, int $contact_id)
{
$specialists = $this->specialistService->specialistsForContact($business_id, $contact_id);
if (! $this->presenceEnabled()) {
return $specialists->map(fn ($s) => array_merge($s, ['is_online' => false]));
}
$this->presenceService->heartbeat($business_id, auth()->id());
$onlineIds = $this->presenceService->onlineUserIds(
$business_id,
$specialists->pluck('id')->all()
);
return $specialists
->map(function ($s) use ($onlineIds) {
$s['is_online'] = in_array($s['id'], $onlineIds, true);
return $s;
})
->sortByDesc('is_online')
->values();
}
private function assertCustomerRoom(int $room_id): ChatRoom
{
if (! $this->chatEnabled()) {
abort(404);
}
$business_id = $this->businessId();
$contact_id = $this->contactId();
$room = ChatRoom::where('business_id', $business_id)->findOrFail($room_id);
$this->chatRoomService->assertRoomMember($room, auth()->user());
$otherMember = $room->members()->where('users.id', '!=', auth()->id())->first();
if ($otherMember) {
$this->specialistService->assertSpecialistForContact($business_id, $contact_id, $otherMember->id);
}
return $room;
}
}