'use client' import CreateRoomModal from '@/components/create-room-modal' import { User, createClientComponentClient } from '@supabase/auth-helpers-nextjs' import { RealtimeChannel } from '@supabase/supabase-js' import { useState, useEffect, use } from 'react' export default function Chat() { const [user, setUser] = useState(null) const [loading, setLoading] = useState(true) const [rooms, setRooms] = useState([]) const [users, setUsers] = useState>(new Set()) const [selectedRoom, setSelectedRoom] = useState() const [mainChannel, setMainChannel] = useState(null) const [channel, setChannel] = useState(null) const [showModal, setShowModal] = useState(false) const [error, setError] = useState(null) const supabase = createClientComponentClient() const getChannels = async () => { const channels = await supabase.from('rooms').select('topic') setRooms(channels.data?.map(({ topic }) => topic) || []) } const addUserToChannel = async (email: string) => { const user = await supabase.from('profiles').select('id').eq('email', email) if (!user.data?.length) { addMessage(true, true, `User ${email} not found`) } else { const room = await supabase.from('rooms').select('topic').eq('topic', selectedRoom) await supabase .from('rooms_users') .upsert({ user_id: user.data?.[0].id, room_topic: room.data?.[0].topic }) addMessage(true, true, `Added ${email} to channel ${selectedRoom}`) } } const addMessage = async (mine: boolean, system: boolean, message: string) => { const bubble = document.createElement('div') const is_self_classes = mine ? ['bg-green-600', 'self-end'] : ['bg-blue-600', 'self-start'] const is_system_classes = system ? ['bg-stone-500', 'self-center', 'italic', 'text-center'] : [] const style = [ 'flex', 'gap-2', 'items-center', 'rounded-xl', 'text-white', 'text-bold', 'w-2/3', 'p-2', ] .concat(is_self_classes) .concat(is_system_classes) bubble.classList.add(...style) bubble.innerHTML = message document.getElementById('chat')!.appendChild(bubble) } useEffect(() => { supabase.auth .getUser() .then((user) => setUser(user.data.user)) .then(async () => { await supabase.auth.getUser() const token = (await supabase.auth.getSession()).data.session?.access_token! supabase.realtime.setAuth(token) let main = supabase .channel('supaslack') .on('broadcast', { event: 'new_room' }, () => getChannels()) .subscribe() setMainChannel(main) getChannels() }) .then(() => { setLoading(false) }) }, [supabase]) useEffect(() => { if (document.getElementById('chat')) { document.getElementById('chat')!.innerHTML = '' } if (selectedRoom) { channel?.unsubscribe() setUsers(new Set()) let newChannel = supabase.channel(selectedRoom, { config: { broadcast: { self: true }, private: true, // This line will tell the server that you want to use a private channel for this connection }, }) newChannel .on('broadcast', { event: 'message' }, ({ payload: payload }) => addMessage(payload.user_id == user?.id, false, payload.message) ) .on('presence', { event: 'join' }, ({ newPresences }) => { newPresences.map(({ email }) => users.add(email)) setUsers(new Set(users)) }) .on('presence', { event: 'leave' }, ({ leftPresences }) => { leftPresences.map(({ email }) => users.delete(email)) setUsers(new Set(users)) }) .subscribe((status, err) => { setLoading(false) if (status == 'SUBSCRIBED') { setChannel(newChannel) newChannel.track({ email: user?.email }) setError(null) } if (status == 'CLOSED') { setChannel(null) } if (status == 'CHANNEL_ERROR') { setError(err?.message || null) } }) } }, [selectedRoom]) return (
{loading && (
)} {showModal ? : ''}
Rooms
{rooms?.map((room: string) => { return ( ) })}
Users in Room
{Array.from(users)?.map((email: string) => { return
{email}
})}
{error ? (

You do not have access to this room

) : (
)}
{ e.preventDefault() const form = e.target as HTMLFormElement const target = form.elements[0] as HTMLInputElement const message = target.value if (message.startsWith('/invite')) { const email = message.replace('/invite ', '') addUserToChannel(email) } else { channel?.send({ type: 'broadcast', event: 'message', payload: { message, user_id: user?.id }, }) } target.value = '' }} >
) }