[done] badge uses websocket (Laravel Reverb)

This commit is contained in:
guillaume91 2024-05-29 11:57:37 +02:00
parent f44329b508
commit acd8d0ea32
19 changed files with 103 additions and 34 deletions

View file

@ -0,0 +1,40 @@
<?php
namespace App\Events;
use App\Models\ProjectMailing;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class ProjectMailingStatus implements ShouldBroadcast
{
use SerializesModels;
public ProjectMailing $projectMailing;
/**
* Create a new event instance.
*/
public function __construct(ProjectMailing $projectMailing)
{
//
$this->projectMailing = $projectMailing;
}
/**
* Get the channels the event should broadcast on.
*
* @return array<int, \Illuminate\Broadcasting\Channel>
*/
public function broadcastOn(): array
{
return [
new PrivateChannel('mailing.'.$this->projectMailing->id),
];
}
}

View file

@ -7,25 +7,39 @@
class Badge extends Component
{
public array $colorClasses;
public $status;
public $type;
public string $type;
public int $id;
public $listeners = [
'Badge:refresh' => '$refresh',
// 'Badge:refresh' => '$refresh',
];
public function mount(string $status = null, $id = 0,$type = null)
public function mount(string $status = null, $id = 0, $type = null)
{
$this->type = $type;
$this->id ??= $id ;
$this->id ??= $id;
$this->status = Status::tryFrom($status) ?? Status::Success;
$this->colorClasses = match($this->status) {
Status::Success => ['bg' => 'bg-green-100', 'text' => 'text-green-700'],
Status::Failed => ['bg' => 'bg-red-100', 'text' => 'text-red-700'],
Status::Pending => ['bg' => 'bg-gray-100', 'text' => 'text-gray-600'],
}
public function getColorClasses(): string
{
return match ($this->status) {
Status::Success => 'bg-green-100 text-green-700',
Status::Failed => 'bg-red-100 text-red-700',
Status::Pending => 'bg-gray-100 text-gray-600',
};
}
public function setStatus(string $status): void
{
$this->status = Status::tryFrom($status) ?? Status::Success;
}
public function refreshPage()
{
$this->dispatch('Badge:refresh');
}
public function render()
{
return view('livewire.components.badge');

View file

@ -11,7 +11,7 @@
class ReportRow extends Component
{
protected $listeners = [
// 'Badge:refresh' => '$refresh',
'Badge:refresh' => '$refresh',
];
#[Reactive]

View file

@ -21,6 +21,10 @@ class Mailings extends Component
public $search = '';
public $active_mailing = null;
protected $listeners = [
'Badge:refresh' => '$refresh',
];
public function mount(Project $project)
{
$this->project = $project;

View file

@ -21,7 +21,7 @@ class Report extends Component
public $showReportModal = false;
public $listeners = [
'Badge:refresh' => '$refresh'
'Badge:refresh' => '$refresh',
];
public function openCreateReportModal()

View file

@ -140,6 +140,7 @@ public function allMosaicsPresent(Carbon $endDate): bool
$mosaicsNotPresentInFilesystem = $this->getMosaicFilenameListByEndDate($endDate)
->filter(function ($filename) {
return !$this->getMosaicList()->contains(function ($mosaicFilename) use ($filename) {
// TODO check the value of the week leading 0
return Str::endsWith($mosaicFilename, substr($filename, -16));
});
});

View file

@ -2,14 +2,14 @@
namespace App\Models;
use App\Events\ProjectMailingStatus;
use App\Traits\HasStatus;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Storage;
use Str;
use Illuminate\Support\Str;
class ProjectMailing extends Model
{
@ -19,6 +19,7 @@ class ProjectMailing extends Model
protected $fillable = [
'subject',
'message',
'status'
];
@ -63,4 +64,12 @@ protected function subject(): Attribute
}
);
}
protected static function booted(): void
{
parent::booted();
static::updated(function (ProjectMailing $projectMailing) {
event(new ProjectMailingStatus($projectMailing));
});
}
}

View file

@ -19,6 +19,7 @@ public function __construct($projectId)
public function passes($attribute, $value)
{
try {
/** @var Project $project */
$project = Project::find($this->projectId);
if (!$project) {

View file

@ -15,6 +15,7 @@ class Badge extends Component
public Status $status;
public int $id;
public function __construct($status = null, $id = 0)
{
$this->id ??= $id ;

View file

@ -32,12 +32,12 @@
"src": "node_modules/@fortawesome/fontawesome-free/webfonts/fa-v4compatibility.woff2"
},
"resources/css/app.css": {
"file": "assets/app-4a859431.css",
"file": "assets/app-93dd061f.css",
"isEntry": true,
"src": "resources/css/app.css"
},
"resources/js/alpine.js": {
"file": "assets/alpine-d6afa966.js",
"file": "assets/alpine-e0ba2549.js",
"isDynamicEntry": true,
"src": "resources/js/alpine.js"
},
@ -45,7 +45,7 @@
"dynamicImports": [
"resources/js/alpine.js"
],
"file": "assets/app-f5ffacbb.js",
"file": "assets/app-eb81fffd.js",
"isEntry": true,
"src": "resources/js/app.js"
}

View file

@ -16,5 +16,4 @@ htabs(Alpine);
window.Alpine = Alpine;
Alpine.start();
Livewire.start();

View file

@ -1,4 +1,4 @@
<span {{ $attributes }} class="inline-flex items-center rounded-md {{ $colorClasses['bg'] }} px-1.5 py-0.5 text-xs font-medium {{ $colorClasses['text'] }}"
<span class="inline-flex items-center rounded-md {{ $colorClasses['bg'] }} px-1.5 py-0.5 text-xs font-medium {{ $colorClasses['text'] }}"
@if($attributes['type'])
x-init="Echo.private(`{{$attributes['type']}}.@js($id)`).listen('Project{{ucfirst($attributes['type'])}}Status', (e) => {
console.log(e.project{{ucfirst($attributes['type'])}}.status);

View file

@ -1,10 +1,13 @@
<span class="inline-flex items-center rounded-md {{ $colorClasses['bg'] }} px-1.5 py-0.5 text-xs font-medium {{ $colorClasses['text'] }}"
<span class="inline-flex items-center rounded-md {{ $this->getColorClasses() }} px-1.5 py-0.5 text-xs font-medium"
@if($this->type)
x-init="Echo.private(`{{$this->type}}.@js($id)`).listen('Project{{ucfirst($this->type)}}Status', (e) => {
x-init="Echo.private(`{{$this->type}}.@js($this->id)`).listen('Project{{ucfirst($this->type)}}Status', (e) => {
console.log(e.project{{ucfirst($this->type)}}.status);
$wire.dispatch('Badge:refresh');
if(e.project{{ucfirst($this->type)}}.status){
$wire.setStatus(e.project{{ucfirst($this->type)}}.status);
$wire.refreshPage();
}
});"
x-destroy="Echo.leaveChannel(`{{$this->type}}.@js($id)`);"
x-destroy="Echo.leaveChannel(`{{$this->type}}.@js($this->id)`);"
@endif
>
{{ $status }}

View file

@ -10,7 +10,7 @@
{{-- @else--}}
{{-- <x-badge :status="$report->status"></x-badge>--}}
{{-- @endif--}}
<x-badge :status="$report->status" :id="$report->id" type="report"></x-badge>
<livewire:components.badge :status="$report->status" :id="$report->id" :type="'report'" wire:key="{{$report->id}}"></livewire:components.badge>
</td>
<td class="py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-6 lg:pr-8 flex justify-end">
<x-menu>

View file

@ -1,10 +1,4 @@
<div
{{-- @if($project->hasPendingDownload())--}}
{{-- wire:poll.1s=""--}}
{{-- @endif--}}
{{-- TODO Put Back the poll but to the list of downloads only--}}
class="m-2"
>
<div class="m-2">
<div class="sm:flex sm:flex-col">
<div class="flex flex-col md:flex-row md:justify-between items-center w-full my-4">
<h1 class="text-base font-semibold leading-6 text-gray-900">Downloads</h1>
@ -52,7 +46,7 @@ class="px-3 py-3.5 text-right pr-4 sm:pr-8 lg:pr-8 text-sm font-semibold text-gr
</td>
<td class="relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-6 lg:pr-8"
>
<x-badge :status="$download->status" :id="$download->id" type="download"></x-badge>
<livewire:components.badge :status="$download->status" :id="$download->id" type="download" wire:key="{{$download->id}}"></livewire:components.badge>
</td>
</tr>
@endforeach

View file

@ -39,7 +39,7 @@ class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900">@lang('Attachm
<td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-gray-900 sm:pl-6 lg:pl-8">{{ $mail->id }}</td>
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">{{ $mail->subject }}</td>
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">
<x-badge :status="$mail->status"></x-badge>
<livewire:components.badge :status="$mail->status" :id="$mail->id" type="mailing" wire:key="{{$mail->id}}"></livewire:components.badge>
</td>
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">{{ $mail->recipients()->count() }}</td>
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">{{ $mail->attachments()->pluck('name')->join( ', ') }}</td>

View file

@ -45,7 +45,7 @@ class="px-3 py-3.5 text-right text-sm font-semibold text-gray-900 sm:pr-8 lg:pr-
{{ $mosaic->year }}-{{ $mosaic->week}}
</td>
<td class="relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-6 lg:pr-8">
<x-badge :status="$mosaic->status" :id="$mosaic->id" type="mosaic"></x-badge>
<livewire:components.badge :status="$mosaic->status" :id="$mosaic->id" type="mosaic" wire:key="{{$mosaic->id}}"></livewire:components.badge>
</td>
</tr>
@endforeach

View file

@ -10,7 +10,7 @@
<div class="flex-1 p-4 bg-white md:w-3/4">
@switch($currentTab)
@case('downloads')
<livewire:projects.tabs.download :project="$project"></livewire:projects.tabs.download>
<livewire:projects.tabs.download :project="$project"/>
@break
@case('mosaics')
<livewire:projects.tabs.mosaic :project="$project"></livewire:projects.tabs.mosaic>

View file

@ -26,4 +26,7 @@
Broadcast::channel('report.{reportId}', function ($user, $reportId) {
return true;
});
Broadcast::channel('mailing.{mailingId}', function ($user, $mailingId) {
return true;
});