Skip to content

Commit f4201ba

Browse files
committed
feat(broadcasting): add online channel
1 parent 7c21ed9 commit f4201ba

File tree

6 files changed

+93
-1
lines changed

6 files changed

+93
-1
lines changed

app/Http/Resources/UserResource.php

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
namespace App\Http\Resources;
4+
5+
use Illuminate\Http\Request;
6+
use Illuminate\Http\Resources\Json\JsonResource;
7+
use Illuminate\Support\Facades\Storage;
8+
9+
class UserResource extends JsonResource
10+
{
11+
/**
12+
* Transform the resource into an array.
13+
*
14+
* @return array<string, mixed>
15+
*/
16+
public function toArray(Request $request): array
17+
{
18+
return [
19+
'id' => $this->id,
20+
'avatar_url' => $this->avatar ? Storage::url($this->avatar) : null,
21+
'name' => $this->name,
22+
'email' => $this->email,
23+
'created_at' => $this->created_at,
24+
'updated_at' => $this->updated_at,
25+
'is_admin' => (bool) $this->is_admin
26+
];
27+
}
28+
}

resources/js/app.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import '../css/app.css';
2+
import './echo.js';
23

34
import { createInertiaApp } from '@inertiajs/react';
45
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';

resources/js/hooks/use-mobile-navigation.ts

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export function useMobileNavigation() {
44
const cleanup = useCallback(() => {
55
// Remove pointer-events style from body...
66
document.body.style.removeProperty('pointer-events');
7+
Echo.leave('online');
78
}, []);
89

910
return cleanup;

resources/js/layouts/chat/chat-sidebar-layout.tsx

+30
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,45 @@ import { ChatSidebar } from '@/components/chat-sidebar';
33
import { AppContent } from '@/components/app-content';
44
import { ChatShell } from '@/components/chat-shell';
55
import ChatHeaderLayout from '@/layouts/chat/chat-header-layout';
6+
import { useEffect, useState } from 'react';
67

78
const ChatSidebarLayout = ({children, breadcrumbs = []}) => {
89
const page = usePage();
910
const conversations = page.props.conversations;
1011
const selectedConversation = page.props.selectedConversation;
12+
const [onlineUsers, setOnlineUsers] = useState({});
1113

1214
console.log("conversations :", conversations);
1315
console.log("selectedConversation ", selectedConversation);
1416

17+
useEffect(() => {
18+
Echo.join('online')
19+
.here((users)=>{
20+
const onlineUsersObj = Object.fromEntries(
21+
users.map((user) => [user.id, user])
22+
);
23+
setOnlineUsers((prevOnlineUsers) => {
24+
return { ...prevOnlineUsers, ...onlineUsersObj}
25+
})
26+
})
27+
.joining((user)=>{
28+
setOnlineUsers((prevOnlineUsers) => {
29+
const updatedUsers = { ...prevOnlineUsers };
30+
updatedUsers[user.id] = user;
31+
return updatedUsers;
32+
})
33+
})
34+
.leaving((user)=>{
35+
setOnlineUsers((prevOnlineUsers) => {
36+
const updatedUsers = { ...prevOnlineUsers };
37+
delete updatedUsers[user.id];
38+
return updatedUsers;
39+
})
40+
})
41+
.error((error)=>{
42+
console.log("error", error)
43+
})
44+
}, [])
1545
return (
1646
<ChatShell variant="sidebar">
1747
<ChatSidebar />

resources/js/pages/chat/index.tsx

+29-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,36 @@
11
import ChatLayout from '@/layouts/chat-layout';
2+
import { Head } from '@inertiajs/react';
3+
import { PlaceholderPattern } from '@/components/ui/placeholder-pattern';
24

35
export default function Index()
46
{
57
return (
6-
<ChatLayout></ChatLayout>
8+
<ChatLayout>
9+
<Head title="Discussions" />
10+
<div className="flex h-full flex-1 flex-col gap-4 rounded-xl p-4">
11+
<div className="grid auto-rows-min gap-4 md:grid-cols-3">
12+
<div
13+
className="border-sidebar-border/70 dark:border-sidebar-border relative aspect-video overflow-hidden rounded-xl border">
14+
<PlaceholderPattern
15+
className="absolute inset-0 size-full stroke-neutral-900/20 dark:stroke-neutral-100/20" />
16+
</div>
17+
<div
18+
className="border-sidebar-border/70 dark:border-sidebar-border relative aspect-video overflow-hidden rounded-xl border">
19+
<PlaceholderPattern
20+
className="absolute inset-0 size-full stroke-neutral-900/20 dark:stroke-neutral-100/20" />
21+
</div>
22+
<div
23+
className="border-sidebar-border/70 dark:border-sidebar-border relative aspect-video overflow-hidden rounded-xl border">
24+
<PlaceholderPattern
25+
className="absolute inset-0 size-full stroke-neutral-900/20 dark:stroke-neutral-100/20" />
26+
</div>
27+
</div>
28+
<div
29+
className="border-sidebar-border/70 dark:border-sidebar-border relative min-h-[100vh] flex-1 rounded-xl border md:min-h-min">
30+
<PlaceholderPattern
31+
className="absolute inset-0 size-full stroke-neutral-900/20 dark:stroke-neutral-100/20" />
32+
</div>
33+
</div>
34+
</ChatLayout>
735
);
836
}

routes/channels.php

+4
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,7 @@
55
Broadcast::channel('App.Models.User.{id}', function ($user, $id) {
66
return (int) $user->id === (int) $id;
77
});
8+
9+
Broadcast::channel('online', function ($user) {
10+
return \App\Http\Resources\UserResource::make($user);
11+
});

0 commit comments

Comments
 (0)