From 4af23aa5a4bc66e994b43e6c517239f69fd1b7a9 Mon Sep 17 00:00:00 2001 From: obrucheoghene Date: Thu, 20 Nov 2025 02:31:39 +0100 Subject: [PATCH 1/7] feat: implement chat item --- src/components/room/chat/chat-item.tsx | 29 ++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 src/components/room/chat/chat-item.tsx diff --git a/src/components/room/chat/chat-item.tsx b/src/components/room/chat/chat-item.tsx new file mode 100644 index 0000000..3289665 --- /dev/null +++ b/src/components/room/chat/chat-item.tsx @@ -0,0 +1,29 @@ +import { Typography } from '@/components/typography'; +import { convertTimestampTo12HourTime } from '@/lib/utils'; +import type { Chat } from '@/types'; + +const ChatItem = ({ chat }: { chat: Chat }) => { + return ( +
+
+ {chat.sender.name} + + {convertTimestampTo12HourTime(chat.createdAt)} + +
+
+ + {chat.text} + +
+
+ ); +}; + +export default ChatItem; From 23635d277659371c0619a4313c0ccba01242286c Mon Sep 17 00:00:00 2001 From: obrucheoghene Date: Thu, 20 Nov 2025 02:32:07 +0100 Subject: [PATCH 2/7] feat: use chat item in chat container --- src/components/room/chat/chat-container.tsx | 57 ++++++++++++++------- 1 file changed, 39 insertions(+), 18 deletions(-) diff --git a/src/components/room/chat/chat-container.tsx b/src/components/room/chat/chat-container.tsx index 653aabe..a923e3a 100644 --- a/src/components/room/chat/chat-container.tsx +++ b/src/components/room/chat/chat-container.tsx @@ -6,44 +6,65 @@ import { Assets } from '@/assets'; import { Typography } from '@/components/typography'; import { useSignaling } from '@/hooks/use-signaling'; import { cn } from '@/lib/utils'; -import { useModalChatOpen, usePeerMe } from '@/store/conf/hooks'; +import { + useChatActions, + useChats, + useModalChatOpen, + usePeerMe, +} from '@/store/conf/hooks'; import { Actions } from '@/types/actions'; +import ChatItem from './chat-item'; +import type { Chat } from '@/types'; const ChatContainer = () => { const chatOpen = useModalChatOpen(); const { signalingService } = useSignaling(); const peerMe = usePeerMe(); const [message, setMessage] = useState(''); + const chats = useChats(); + const chatActions = useChatActions(); const handleSendChat = async () => { - if (!signalingService) return; + if (!signalingService || !peerMe || !message.length) return; + const chatMessage: Chat = { + id: uuidv4(), + text: message, + sender: peerMe, + createdAt: Date.now(), + }; signalingService.sendMessage({ action: Actions.SendChat, - args: { - id: uuidv4(), - text: message, - sender: peerMe, - createdAt: Date.now(), - }, + args: { ...chatMessage }, }); - console.log(message, 'sent'); + if (message) chatActions.addChat(chatMessage); + setMessage(''); }; return (
{/* content */} -
- Emtpy Chat - Start Conversation - - There are no messages here yet. Start a conversation by sending a - message. - -
+ {!chats.length ? ( +
+ Emtpy Chat + Start Conversation + + There are no messages here yet. Start a conversation by sending a + message. + +
+ ) : ( +
+
+ {chats.map(chat => ( + + ))} +
+
+ )} {/* input */}
From 20665dd8744db0269b04410030acba17d6c2f797 Mon Sep 17 00:00:00 2001 From: obrucheoghene Date: Thu, 20 Nov 2025 02:32:26 +0100 Subject: [PATCH 3/7] feat: handle send chat event --- src/hooks/use-room.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/hooks/use-room.ts b/src/hooks/use-room.ts index 4cb638f..ff996a0 100644 --- a/src/hooks/use-room.ts +++ b/src/hooks/use-room.ts @@ -1,4 +1,5 @@ import { + useChatActions, usePeerActions, usePeerMe, useRoomAccess, @@ -30,6 +31,7 @@ export const useRoom = () => { const peerMe = usePeerMe(); const roomData = useRoomData(); const roomAccess = useRoomAccess(); + const chatActions = useChatActions(); const joinVisitors = useCallback(async () => { if (!signalingService || !roomData) return; @@ -128,9 +130,17 @@ export const useRoom = () => { [Actions.SendChat]: async args => { const data = ValidationSchema.sendChat.parse(args); console.log(data); + chatActions.addChat(data); }, }), - [closeConsumer, createConsumer, pauseConsumer, peerActions, resumeConsumer] + [ + closeConsumer, + createConsumer, + pauseConsumer, + peerActions, + resumeConsumer, + chatActions, + ] ); return { joinVisitors, joinRoom, leaveRoom, actionHandlers }; From f082116fb1891f4e154c5e552029297ee4068732 Mon Sep 17 00:00:00 2001 From: obrucheoghene Date: Thu, 20 Nov 2025 02:32:41 +0100 Subject: [PATCH 4/7] handle time converter --- src/lib/utils.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/lib/utils.ts b/src/lib/utils.ts index a277162..5f3e965 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -234,3 +234,16 @@ export const audioContraints = (deviceId: string) => ({ noiseSuppression: { ideal: true }, }, }); + +export const convertTimestampTo12HourTime = (timestamp: number) => { + const date = new Date(timestamp); + const hour = date.getHours(); + const minute = date.getMinutes(); + const period = hour >= 12 ? 'PM' : 'AM'; + + const formattedHour = hour % 12 === 0 ? 12 : hour % 12; + const paddedHours = formattedHour < 10 ? '0' + formattedHour : formattedHour; + const paddedMinute = minute < 10 ? '0' + minute : minute; + + return paddedHours + ':' + paddedMinute + ' ' + period; +}; From b8953117b99059af1b5635aac0eefb8b93414bd3 Mon Sep 17 00:00:00 2001 From: obrucheoghene Date: Thu, 20 Nov 2025 02:33:02 +0100 Subject: [PATCH 5/7] feat: add chat slice --- src/store/conf/hooks.ts | 12 ++++++++++++ src/store/conf/slices/chat-slice.ts | 11 ++++++----- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/store/conf/hooks.ts b/src/store/conf/hooks.ts index 28bb8e3..1ab0d93 100644 --- a/src/store/conf/hooks.ts +++ b/src/store/conf/hooks.ts @@ -157,3 +157,15 @@ export const useModalActions = () => }), [] ); + +// ============================================================================ +// CHAT SELECTORS +// ============================================================================ +export const useChats = () => useConfStore(state => state.chat.chats); +export const useChatActions = () => + useMemo( + () => ({ + addChat: useConfStore.getState().chat.add, + }), + [] + ); diff --git a/src/store/conf/slices/chat-slice.ts b/src/store/conf/slices/chat-slice.ts index 7f8e43c..73ddee8 100644 --- a/src/store/conf/slices/chat-slice.ts +++ b/src/store/conf/slices/chat-slice.ts @@ -1,9 +1,10 @@ import type { StateCreator } from 'zustand'; import type { ConfStoreState } from '../type'; +import type { Chat } from '@/types'; export interface ChatSlice { - open: boolean; - toggle: () => void; + chats: Chat[]; + add: (chat: Chat) => void; } export const createChatSlice: StateCreator< @@ -12,10 +13,10 @@ export const createChatSlice: StateCreator< [['zustand/immer', ChatSlice]], ChatSlice > = set => ({ - open: false, - toggle: () => + chats: [], + add: chat => set(state => { - state.chat.open = !state.chat.open; + state.chat.chats.push(chat); return state; }), }); From 547781fda2f3aca6f251c0e5943216965c2f3aeb Mon Sep 17 00:00:00 2001 From: obrucheoghene Date: Thu, 20 Nov 2025 16:35:13 +0100 Subject: [PATCH 6/7] chore: change endmeeting to endroom --- src/types/actions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/actions.ts b/src/types/actions.ts index 6f7fab2..bef9f4e 100644 --- a/src/types/actions.ts +++ b/src/types/actions.ts @@ -45,7 +45,7 @@ export enum Actions { AddRole = 'add_role', RemoveRole = 'remove_role', - EndMeeting = 'end_meeting', + EndRoom = 'end_room', Heartbeat = 'heartbeat', HeartbeatAck = 'heartbeat_ack', From 87ef8342cc02bf0a76040b668ed0ec9b1b015152 Mon Sep 17 00:00:00 2001 From: obrucheoghene Date: Thu, 20 Nov 2025 17:05:23 +0100 Subject: [PATCH 7/7] fix: prevent sending empty chat --- src/components/room/chat/chat-container.tsx | 25 ++++++++++++++------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/components/room/chat/chat-container.tsx b/src/components/room/chat/chat-container.tsx index a923e3a..1f280b4 100644 --- a/src/components/room/chat/chat-container.tsx +++ b/src/components/room/chat/chat-container.tsx @@ -1,5 +1,5 @@ import { ChevronRightIcon, SendHorizonal, Smile, Users } from 'lucide-react'; -import { useState } from 'react'; +import { useState, type KeyboardEvent } from 'react'; import { v4 as uuidv4 } from 'uuid'; import { Assets } from '@/assets'; @@ -26,6 +26,7 @@ const ChatContainer = () => { const handleSendChat = async () => { if (!signalingService || !peerMe || !message.length) return; + if (!message.trim()) return; const chatMessage: Chat = { id: uuidv4(), text: message, @@ -36,9 +37,19 @@ const ChatContainer = () => { action: Actions.SendChat, args: { ...chatMessage }, }); - if (message) chatActions.addChat(chatMessage); + chatActions.addChat(chatMessage); setMessage(''); }; + + const handleOnKeyPress = async ( + event: KeyboardEvent + ) => { + if (event.key === 'Enter' && !event.shiftKey) { + event.preventDefault(); + handleSendChat(); + } + }; + return (
{
-
+