finnal changes

This commit is contained in:
Gal Podlipnik 2025-06-15 21:44:22 +02:00
parent 3aa4c5b150
commit 63354e85d5
5 changed files with 56 additions and 53 deletions

View File

@ -1,8 +1,9 @@
import { chatAPI } from '@/lib/api'; import { chatAPI } from '@/lib/api';
import { useAuthStore } from '@/stores/authStore'; import { useAuthStore } from '@/stores/authStore';
import { useChatStore } from '@/stores/chatStore'; import { useChatStore } from '@/stores/chatStore';
import { useSocketStore } from '@/stores/socketStore';
import type { ChatRoom, CreateChatRoomRequest } from '@/types'; import type { ChatRoom, CreateChatRoomRequest } from '@/types';
import { useMutation, useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import { import {
Laptop, Laptop,
LogOut, LogOut,
@ -52,8 +53,9 @@ export const ChatSidebar: FC<ChatSidebarProps> = ({
memberUsernames: [], memberUsernames: [],
}); });
const { chatRooms, onlineUsers, setChatRooms, addChatRoom } = useChatStore(); const { chatRooms, onlineUsers, setChatRooms } = useChatStore();
const { user, logout } = useAuthStore(); const { user, logout } = useAuthStore();
const { socket } = useSocketStore();
const navigate = useNavigate(); const navigate = useNavigate();
const { theme, setTheme } = useTheme(); const { theme, setTheme } = useTheme();
@ -69,29 +71,18 @@ export const ChatSidebar: FC<ChatSidebarProps> = ({
}, },
}); });
const createRoomMutation = useMutation({
mutationKey: ['createChatRoom'],
mutationFn: chatAPI.createChatRoom,
onSuccess: (response) => {
if (response.data.success) {
const newRoom = response.data.data;
addChatRoom(newRoom);
setIsCreateDialogOpen(false);
setNewRoomData({ name: '', description: '', memberUsernames: [] });
toast.success('Chat room created successfully');
navigate(`/room/${newRoom.id}`);
}
},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
onError: (error: any) => {
toast.error(error.response?.data?.error ?? 'Failed to create chat room');
},
});
const handleCreateRoom = (e: FormEvent) => { const handleCreateRoom = (e: FormEvent) => {
e.preventDefault(); e.preventDefault();
createRoomMutation.mutate(newRoomData);
if (!socket) {
toast.error('Socket connection is not established');
return;
}
socket.emit('create_chat_room', newRoomData);
setNewRoomData({ name: '', description: '', memberUsernames: [] });
setIsCreateDialogOpen(false);
}; };
const getOnlineMembersCount = (room: ChatRoom) => { const getOnlineMembersCount = (room: ChatRoom) => {
@ -193,12 +184,8 @@ export const ChatSidebar: FC<ChatSidebarProps> = ({
placeholder="user1, user2, user3" placeholder="user1, user2, user3"
/> />
</div> </div>
<Button <Button type="submit" className="w-full">
type="submit" Create Room
className="w-full"
disabled={createRoomMutation.isPending}
>
{createRoomMutation.isPending ? 'Creating...' : 'Create Room'}
</Button> </Button>
</form> </form>
</DialogContent> </DialogContent>

View File

@ -198,11 +198,11 @@ export const MessageCard: FC<{ message: Message }> = ({ message }) => {
'flex items-center gap-1 text-xs px-2 py-1 rounded-full', 'flex items-center gap-1 text-xs px-2 py-1 rounded-full',
hasUserReacted(message.reactions, type) hasUserReacted(message.reactions, type)
? type === 'like' ? type === 'like'
? 'bg-red-100' ? 'bg-red-100 dark:bg-red-900/20'
: type === 'thumbs_up' : type === 'thumbs_up'
? 'bg-blue-100' ? 'bg-blue-100 dark:bg-blue-900/20'
: 'bg-yellow-100' : 'bg-yellow-100 dark:bg-yellow-900/20'
: 'bg-gray-100' : 'bg-gray-100 dark:bg-gray-700'
)} )}
onClick={() => handleReaction(message.id, type)} onClick={() => handleReaction(message.id, type)}
> >
@ -210,8 +210,9 @@ export const MessageCard: FC<{ message: Message }> = ({ message }) => {
<Heart <Heart
className={cn( className={cn(
'h-3 w-3', 'h-3 w-3',
hasUserReacted(message.reactions, type) && hasUserReacted(message.reactions, type)
'fill-red-500 text-red-500' ? 'fill-red-500 text-red-500'
: 'text-gray-600 dark:text-gray-300'
)} )}
/> />
)} )}
@ -219,8 +220,9 @@ export const MessageCard: FC<{ message: Message }> = ({ message }) => {
<ThumbsUp <ThumbsUp
className={cn( className={cn(
'h-3 w-3', 'h-3 w-3',
hasUserReacted(message.reactions, type) && hasUserReacted(message.reactions, type)
'fill-blue-500 text-blue-500' ? 'fill-blue-500 text-blue-500'
: 'text-gray-600 dark:text-gray-300'
)} )}
/> />
)} )}
@ -228,12 +230,13 @@ export const MessageCard: FC<{ message: Message }> = ({ message }) => {
<Smile <Smile
className={cn( className={cn(
'h-3 w-3', 'h-3 w-3',
hasUserReacted(message.reactions, type) && hasUserReacted(message.reactions, type)
'fill-yellow-500 text-yellow-500' ? 'text-yellow-500'
: 'text-gray-600 dark:text-gray-300'
)} )}
/> />
)} )}
<span className="text-gray-600 dark:text-black">{count}</span> <span className="text-gray-600 dark:text-gray-300">{count}</span>
</div> </div>
))} ))}
</div> </div>

View File

@ -1,3 +1,4 @@
import { useAuthStore } from '@/stores/authStore';
import { useChatStore } from '@/stores/chatStore'; import { useChatStore } from '@/stores/chatStore';
import { Settings, Users } from 'lucide-react'; import { Settings, Users } from 'lucide-react';
import { useState, type FC } from 'react'; import { useState, type FC } from 'react';
@ -10,7 +11,7 @@ export const NavBar: FC = () => {
const { chatRooms, onlineUsers } = useChatStore(); const { chatRooms, onlineUsers } = useChatStore();
const { roomId } = useParams<{ roomId: string }>(); const { roomId } = useParams<{ roomId: string }>();
const [isSettingsOpen, setIsSettingsOpen] = useState(false); const [isSettingsOpen, setIsSettingsOpen] = useState(false);
const { user } = useAuthStore();
const currentRoom = chatRooms.find((room) => room.id === roomId); const currentRoom = chatRooms.find((room) => room.id === roomId);
const getOnlineMembersCount = () => { const getOnlineMembersCount = () => {
@ -45,15 +46,18 @@ export const NavBar: FC = () => {
)} )}
</div> </div>
<div> <div>
{currentRoom && ( {currentRoom &&
<Button currentRoom.members.some(
size="sm" (member) => member.userId === user?.id && member.role === 'admin'
variant="ghost" ) && (
onClick={() => setIsSettingsOpen(true)} <Button
> size="sm"
<Settings className="h-4 w-4" /> variant="ghost"
</Button> onClick={() => setIsSettingsOpen(true)}
)} >
<Settings className="h-4 w-4" />
</Button>
)}
</div> </div>
{currentRoom && ( {currentRoom && (

View File

@ -55,7 +55,6 @@ export const chatAPI = {
limit = 50 limit = 50
): Promise<AxiosResponse<ApiResponse>> => ): Promise<AxiosResponse<ApiResponse>> =>
api.get(`/messages/${roomId}?page=${page}&limit=${limit}`), api.get(`/messages/${roomId}?page=${page}&limit=${limit}`),
// Add these new endpoints
updateChatRoom: ( updateChatRoom: (
roomId: string, roomId: string,
data: UpdateChatRoomRequest data: UpdateChatRoomRequest

View File

@ -1,6 +1,6 @@
import { useChatStore } from '@/stores/chatStore'; import { useChatStore } from '@/stores/chatStore';
import { useSocketStore } from '@/stores/socketStore'; import { useSocketStore } from '@/stores/socketStore';
import type { Message, MessageReaction } from '@/types'; import type { ChatRoom, Message, MessageReaction } from '@/types';
import { io, type Socket } from 'socket.io-client'; import { io, type Socket } from 'socket.io-client';
import { toast } from 'sonner'; import { toast } from 'sonner';
@ -116,13 +116,23 @@ class SocketService {
} }
); );
this.socket.on('chat_room_created', (room: ChatRoom) => {
const { chatRooms, addChatRoom } = useChatStore.getState();
if (!chatRooms.some((r) => r.id === room.id)) {
addChatRoom(room);
toast.success('Chat room created successfully', {
id: 'creating-room',
});
}
});
this.socket.on( this.socket.on(
'rate_limit_exceeded', 'rate_limit_exceeded',
(data: { message: string; remainingTime?: number }) => { (data: { message: string; remainingTime?: number }) => {
console.warn('Rate limit exceeded:', data.message); console.warn('Rate limit exceeded:', data.message);
toast.error(`Rate limit exceeded: ${data.message}`, { toast.error(`Rate limit exceeded: ${data.message}`, {
duration: data.remainingTime ? data.remainingTime * 1000 : 5000, duration: data.remainingTime ? data.remainingTime * 1000 : 5000,
position: 'top-right',
style: { style: {
background: '#f8d7da', background: '#f8d7da',
color: '#721c24', color: '#721c24',