mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-16 09:31:20 -04:00
chat, nicknames, user list.
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
/* eslint-disable react-refresh/only-export-components */
|
||||
|
||||
import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useSocket } from './SocketContext.jsx';
|
||||
import { useSession } from './SessionContext.jsx';
|
||||
|
||||
const ChatContext = createContext({
|
||||
messages: [],
|
||||
sendMessage: async () => {},
|
||||
focusChat: () => {},
|
||||
blurChat: () => {},
|
||||
registerInputRef: () => {},
|
||||
onInputFocus: () => {},
|
||||
onInputBlur: () => {},
|
||||
isChatFocused: false,
|
||||
});
|
||||
|
||||
export function ChatProvider({ children }) {
|
||||
const socket = useSocket();
|
||||
const { session } = useSession();
|
||||
const [messages, setMessages] = useState([]);
|
||||
const [isChatFocused, setIsChatFocused] = useState(false);
|
||||
const inputRef = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
function handleMessage(payload = {}) {
|
||||
setMessages((prev) => [...prev.slice(-99), payload]);
|
||||
}
|
||||
socket.on('chat:message', handleMessage);
|
||||
return () => {
|
||||
socket.off('chat:message', handleMessage);
|
||||
};
|
||||
}, [socket]);
|
||||
|
||||
const sendMessage = useCallback(
|
||||
(text) =>
|
||||
new Promise((resolve, reject) => {
|
||||
socket.emit('chat:send', { text }, (resp = {}) => {
|
||||
if (resp.error) {
|
||||
reject(new Error(resp.error));
|
||||
} else {
|
||||
resolve(resp);
|
||||
}
|
||||
});
|
||||
}),
|
||||
[socket],
|
||||
);
|
||||
|
||||
const registerInputRef = useCallback((el) => {
|
||||
inputRef.current = el;
|
||||
}, []);
|
||||
|
||||
const focusChat = useCallback(() => {
|
||||
setIsChatFocused(true);
|
||||
inputRef.current?.focus();
|
||||
}, []);
|
||||
|
||||
const blurChat = useCallback(() => {
|
||||
setIsChatFocused(false);
|
||||
inputRef.current?.blur();
|
||||
}, []);
|
||||
|
||||
const onInputFocus = useCallback(() => setIsChatFocused(true), []);
|
||||
const onInputBlur = useCallback(() => setIsChatFocused(false), []);
|
||||
|
||||
const value = useMemo(
|
||||
() => ({
|
||||
messages,
|
||||
sendMessage,
|
||||
focusChat,
|
||||
blurChat,
|
||||
registerInputRef,
|
||||
onInputFocus,
|
||||
onInputBlur,
|
||||
isChatFocused,
|
||||
selfSocketId: session?.socketId || null,
|
||||
}),
|
||||
[blurChat, focusChat, isChatFocused, messages, onInputBlur, onInputFocus, registerInputRef, sendMessage, session?.socketId],
|
||||
);
|
||||
|
||||
return <ChatContext.Provider value={value}>{children}</ChatContext.Provider>;
|
||||
}
|
||||
|
||||
export function useChat() {
|
||||
const ctx = useContext(ChatContext);
|
||||
if (!ctx) {
|
||||
throw new Error('useChat must be used inside ChatProvider');
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
@@ -14,6 +14,7 @@ const SessionContext = createContext({
|
||||
subscribeAll: async () => {},
|
||||
homeAssistantToggle: async () => {},
|
||||
homeAssistantSetState: async () => {},
|
||||
setNickname: async () => {},
|
||||
});
|
||||
|
||||
function useAckEmitter(socket) {
|
||||
@@ -94,6 +95,7 @@ export function SessionProvider({ children }) {
|
||||
homeAssistantToggle: (entityId) => emitWithAck('homeAssistant:toggle', { entityId }),
|
||||
homeAssistantSetState: (entityId, state) =>
|
||||
emitWithAck('homeAssistant:setState', { entityId, state }),
|
||||
setNickname: (nickname) => emitWithAck('nickname:set', { nickname }),
|
||||
}),
|
||||
[emitWithAck],
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user