From af4320596e0ce24619cd2517796ef579694e863f Mon Sep 17 00:00:00 2001 From: EL OUFIR Hatim Date: Mon, 19 Sep 2022 23:10:39 +0100 Subject: [PATCH 1/2] Chat system --- app/Http/Livewire/Chat.php | 63 +++++++++++++++++++ app/Http/Livewire/TicketDetails.php | 3 +- app/Models/Chat.php | 38 +++++++++++ app/Models/Ticket.php | 7 +++ .../2022_09_19_212320_create_chats_table.php | 34 ++++++++++ lang/fr.json | 8 ++- resources/css/app.scss | 10 +++ resources/js/app.js | 48 +++++++------- resources/views/livewire/chat.blade.php | 50 +++++++++++++++ .../ticket-details-comments.blade.php | 5 +- .../views/livewire/ticket-details.blade.php | 7 ++- 11 files changed, 245 insertions(+), 28 deletions(-) create mode 100644 app/Http/Livewire/Chat.php create mode 100644 app/Models/Chat.php create mode 100644 database/migrations/2022_09_19_212320_create_chats_table.php create mode 100644 resources/views/livewire/chat.blade.php diff --git a/app/Http/Livewire/Chat.php b/app/Http/Livewire/Chat.php new file mode 100644 index 0000000..cd71862 --- /dev/null +++ b/app/Http/Livewire/Chat.php @@ -0,0 +1,63 @@ +form->fill(); + } + + public function render() + { + $messages = Model::where('ticket_id', $this->ticket->id)->get(); + return view('livewire.chat', compact('messages')); + } + + /** + * Form schema definition + * + * @return array + */ + protected function getFormSchema(): array + { + return [ + RichEditor::make('message') + ->label(__('Type a message..')) + ->disableLabel() + ->placeholder(__('Type a message..')) + ->required() + ->fileAttachmentsDisk(config('filesystems.default')) + ->fileAttachmentsDirectory('chat') + ->fileAttachmentsVisibility('private'), + ]; + } + + /** + * Send a message + * + * @return void + */ + public function send(): void + { + $data = $this->form->getState(); + Model::create([ + 'message' => $data['message'], + 'user_id' => auth()->user()->id, + 'ticket_id' => $this->ticket->id + ]); + $this->form->fill(); + } +} diff --git a/app/Http/Livewire/TicketDetails.php b/app/Http/Livewire/TicketDetails.php index ca7d2e1..7b2c83a 100644 --- a/app/Http/Livewire/TicketDetails.php +++ b/app/Http/Livewire/TicketDetails.php @@ -18,7 +18,7 @@ public function mount(): void { $this->menu = [ 'Comments', - 'Activities', + 'Chat', ]; $this->activeMenu = $this->menu[0]; } @@ -37,6 +37,7 @@ public function render() public function selectMenu($item) { $this->activeMenu = $item; + $this->dispatchBrowserEvent('initMagnificPopupOnTicketComments'); } /** diff --git a/app/Models/Chat.php b/app/Models/Chat.php new file mode 100644 index 0000000..68a783a --- /dev/null +++ b/app/Models/Chat.php @@ -0,0 +1,38 @@ +orderBy('created_at', 'desc'); + }); + } + + public function ticket(): BelongsTo + { + return $this->belongsTo(Ticket::class); + } + + public function user(): BelongsTo + { + return $this->belongsTo(User::class); + } +} diff --git a/app/Models/Ticket.php b/app/Models/Ticket.php index 1a194c2..a391075 100644 --- a/app/Models/Ticket.php +++ b/app/Models/Ticket.php @@ -10,6 +10,7 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasMany; +use Illuminate\Database\Eloquent\Relations\HasOne; use Illuminate\Database\Eloquent\SoftDeletes; class Ticket extends Model implements HasLogsActivity @@ -79,4 +80,10 @@ public function activityLogLink(): string { return route('tickets.number', $this->ticket_number); } + + public function chat(): HasOne + { + return $this->hasOne(Chat::class); + } + } diff --git a/database/migrations/2022_09_19_212320_create_chats_table.php b/database/migrations/2022_09_19_212320_create_chats_table.php new file mode 100644 index 0000000..bc12f83 --- /dev/null +++ b/database/migrations/2022_09_19_212320_create_chats_table.php @@ -0,0 +1,34 @@ +id(); + $table->longText('message'); + $table->foreignId('ticket_id')->constrained('tickets'); + $table->foreignId('user_id')->constrained('users'); + $table->softDeletes(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('chats'); + } +}; diff --git a/lang/fr.json b/lang/fr.json index 184e442..64566fc 100644 --- a/lang/fr.json +++ b/lang/fr.json @@ -277,5 +277,11 @@ "Activity logs": "Journaux d'activité", "Here you can see all activity logs of :app": "Ici vous pouvez voir tous les journaux d'activité de :app", "Below is the list of activity logs of :app": "Ci-dessous les journaux d'activité de :app", - "Search for activity logs": "Rechercher les journaux d'activité" + "Search for activity logs": "Rechercher les journaux d'activité", + "Chat": "Chat", + "Chat section": "Section de chat", + "Use the section below to chat with the speakers of this ticket": "Utilisez la section ci-dessous pour échanger avec les intervenants de ce ticket", + "Type a message..": "Tapez un message..", + "Send": "Envoyer", + "No messages yet!": "Aucun message pour le moment !" } diff --git a/resources/css/app.scss b/resources/css/app.scss index 2473b67..c996c87 100644 --- a/resources/css/app.scss +++ b/resources/css/app.scss @@ -75,3 +75,13 @@ table { } } } + +#chat { + height: 500px; + + #chat-container { + img { + max-width: 50%; + } + } +} diff --git a/resources/js/app.js b/resources/js/app.js index 0a9ef0f..72e4837 100644 --- a/resources/js/app.js +++ b/resources/js/app.js @@ -25,29 +25,33 @@ window.Alpine = Alpine Alpine.start() -// Open image as magnific popup -if ($('.magnificpopup-container').length) { - $('.magnificpopup-container').magnificPopup({ - type: 'image', - delegate: 'img', - gallery: { - enabled: true - }, - callbacks: { - elementParse: function (qw) { - qw.src = qw.el.attr('src'); +// Open image as magnific popup (Ticket comments) +window.initMagnificPopupOnTicketComments = function () { + if ($('.magnificpopup-container').length) { + $('.magnificpopup-container').magnificPopup({ + type: 'image', + delegate: 'img', + gallery: { + enabled: true + }, + callbacks: { + elementParse: function (qw) { + qw.src = qw.el.attr('src'); + } + }, + image: { + titleSrc: function (item) { + let title = ''; + if (item.el.closest('figure').children('figcaption')) + title = item.el.closest('figure').children('figcaption').text(); + return title; + } } - }, - image: { - titleSrc: function (item) { - let title = ''; - if (item.el.closest('figure').children('figcaption')) - title = item.el.closest('figure').children('figcaption').text(); - return title; - } - } - }); -} + }); + } +}; + +(() => window.initMagnificPopupOnTicketComments())(); // Copy text to clipboard window.unsecuredCopyToClipboard = function (text) { diff --git a/resources/views/livewire/chat.blade.php b/resources/views/livewire/chat.blade.php new file mode 100644 index 0000000..e67d6ca --- /dev/null +++ b/resources/views/livewire/chat.blade.php @@ -0,0 +1,50 @@ +
+
+
+ + @lang('Chat section') + + + @lang('Use the section below to chat with the speakers of this ticket') + +
+
+
+
+ @if($messages->count()) +
+ @foreach($messages as $message) +
+ {{ $message->user->name }} +
+ {!! $message->message !!} +
+ {{ $message->created_at->diffForHumans() }} +
+ @endforeach +
+ @else +
+ No comments + + @lang('No messages yet!') + +
+ @endif +
+
+
+ {{ $this->form }} +
+
+ +
+
+
+
diff --git a/resources/views/livewire/ticket-details-comments.blade.php b/resources/views/livewire/ticket-details-comments.blade.php index b6bfe1f..c7549ff 100644 --- a/resources/views/livewire/ticket-details-comments.blade.php +++ b/resources/views/livewire/ticket-details-comments.blade.php @@ -5,7 +5,8 @@ {{ $this->form }}
-