feat: Realtime for Votes + Deadlines

main
Flycro 2024-03-24 01:36:16 +01:00
parent b1cb25c823
commit 5c0dab3448
9 changed files with 133 additions and 1 deletions

View File

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

View File

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

View File

@ -2,6 +2,7 @@
namespace App\Models;
use App\Events\Deadline\DeadlineCreated;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
@ -16,6 +17,13 @@ class Deadline extends Model
'target_chapter',
];
protected static function booted() :void
{
static::created(static function ($deadline) {
event(new DeadlineCreated($deadline));
});
}
public function bookRecommendation()
{
return $this->belongsTo(BookRecommendation::class);

View File

@ -2,6 +2,7 @@
namespace App\Models;
use App\Events\Vote\VoteCreated;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
@ -14,6 +15,13 @@ class Vote extends Model
'book_recommendation_id',
];
protected static function booted() :void
{
static::created(static function ($vote) {
broadcast(new VoteCreated($vote))->toOthers();
});
}
public function user()
{
return $this->belongsTo(User::class);

View File

@ -83,6 +83,12 @@ onMounted(() => {
bookRecommendationStore.createRecommendationWS(e.bookRecommendation)
})
authStore.socketId = $echo.socketId()
$echo.private(`Vote`)
.listen('.VoteCreated', (e) => {
console.log(e)
bookRecommendationStore.createVoteWS(e.vote)
})
})
</script>

View File

@ -4,6 +4,8 @@ import ConfirmUserDeadline from '~/components/modal/ConfirmUserDeadline.vue'
const props = defineProps<{
bookRecommendationId: number
}>()
const { $echo } = useNuxtApp()
const authStore = useAuthStore()
const { refresh: deadlineRefresh, status: deadlineStatus, data: deadlines } = useFetch(() => `book-recommendations/${props.bookRecommendationId}/deadlines`)
@ -40,6 +42,13 @@ const rows = computed(() => {
}
})
})
onMounted(() => {
$echo.private(`Deadline`)
.listen('.DeadlineCreated', (e) => {
deadlineRefresh()
})
})
</script>
<template>

View File

@ -43,7 +43,6 @@ export default defineNuxtPlugin({
// Conditionally add X-Socket-ID header if socket is connected
if (auth.isLoggedIn && auth.socketId) {
console.log('auth.socketId', auth.socketId)
const socketHeaders = {
'X-Socket-ID': auth.socketId,
}

View File

@ -123,6 +123,17 @@ export const useBookRecommendationStore = defineStore('bookRecommendations', ()
})
}
const createVoteWS = async (data: Partial<Vote>) => {
const index = recommendations.value.findIndex(r => r.id === data.book_recommendation_id)
// check if vote already exists otherwise add an empty array
if (index !== -1) {
if (!recommendations.value[index]?.votes) {
recommendations.value[index].votes = []
}
recommendations.value[index].votes.push(data)
}
}
function resetRecommendations() {
recommendations.value = []
}
@ -133,6 +144,7 @@ export const useBookRecommendationStore = defineStore('bookRecommendations', ()
updateRecommendationWS,
deleteRecommendationWS,
createRecommendationWS,
createVoteWS,
statusOptions,
fetchRecommendations,
fetchRecommendationsStatus,

View File

@ -9,3 +9,11 @@ Broadcast::channel('App.Models.User.{ulid}', function ($user, $ulid) {
Broadcast::channel('BookRecommendation', function ($user) {
return $user;
});
Broadcast::channel('Vote', function ($user) {
return $user;
});
Broadcast::channel('Deadline', function ($user) {
return $user;
});