5180 fichiers 38.5 Mo 0 téléchargements 287 vues mis à jour il y a 6 heures ui
nitro-v36-with-renderer-v36 / src / hooks / rooms / widgets / useChatInputState.ts
useChatInputState.ts 3.9 Ko Télécharger le fichier
import { RoomEngineObjectEvent, RoomObjectCategory, RoomSessionChatEvent } from '@octane/renderer';
import { useEffect, useRef, useState } from 'react';
import { useOctaneEvent } from '../../events';
import { useObjectSelectedEvent } from '../engine';
import { useRoom } from '../useRoom';

/**
 * State + event subscriptions for the chat-input widget. Pure
 * imperative dispatch (sendChat) lives in useChatInputActions.
 *
 *  - selectedUsername  → tracks the last avatar the user clicked,
 *                        used by `/whisper` shortcuts.
 *  - floodBlocked /    → flood-throttle banner state, driven by the
 *    floodBlockedSeconds  renderer's FLOOD_EVENT plus a 1s tick.
 *  - isTyping /        → typing indicator + 10s idle auto-clear, with
 *    isIdle              an internal `typingStartedSent` ref so the
 *                        outgoing sendChatTypingMessage only fires on
 *                        state edges (start / stop), not every render.
 */
/** The seconds of a flood block the server sent, rounded up; 0 for a message that is not a positive number. */
export const floodBlockSeconds = (message: string): number => {
    const seconds = Number.parseFloat(message);

    return Number.isFinite(seconds) && seconds > 0 ? Math.ceil(seconds) : 0;
};

export const useChatInputState = () => {
    const [selectedUsername, setSelectedUsername] = useState('');
    const [isTyping, setIsTyping] = useState<boolean>(false);
    const [typingStartedSent, setTypingStartedSent] = useState(false);
    const [isIdle, setIsIdle] = useState(false);
    const [floodBlocked, setFloodBlocked] = useState(false);
    const [floodBlockedSeconds, setFloodBlockedSeconds] = useState(0);
    // The countdown itself: it was worked out inside a state updater and read right after, which React does not
    // promise to have run, and a message that was not a number (NaN) ended the block at once.
    const floodRemainingRef = useRef(0);
    const { roomSession = null } = useRoom();

    useOctaneEvent<RoomSessionChatEvent>(RoomSessionChatEvent.FLOOD_EVENT, (event) => {
        const seconds = floodBlockSeconds(event.message);

        if (seconds <= 0) return;

        floodRemainingRef.current = seconds;
        setFloodBlockedSeconds(seconds);
        setFloodBlocked(true);
    });

    useObjectSelectedEvent((event) => {
        if (event.category !== RoomObjectCategory.UNIT) return;

        const userData = roomSession?.userDataManager?.getUserDataByIndex(event.id);

        if (!userData) return;

        setSelectedUsername(userData.name);
    });

    useOctaneEvent<RoomEngineObjectEvent>(RoomEngineObjectEvent.DESELECTED, () => setSelectedUsername(''));

    useEffect(() => {
        if (!floodBlocked) return;

        const interval = setInterval(() => {
            floodRemainingRef.current -= 1;
            setFloodBlockedSeconds(Math.max(0, floodRemainingRef.current));

            if (floodRemainingRef.current <= 0) {
                clearInterval(interval);

                setFloodBlocked(false);
            }
        }, 1000);

        return () => clearInterval(interval);
    }, [floodBlocked]);

    useEffect(() => {
        if (!isIdle) return;

        const timeout = setTimeout(() => {
            setIsIdle(false);
            setIsTyping(false);
        }, 10000);

        return () => clearTimeout(timeout);
    }, [isIdle]);

    useEffect(() => {
        if (!roomSession) return;

        if (isTyping) {
            if (!typingStartedSent) {
                setTypingStartedSent(true);

                roomSession.sendChatTypingMessage(isTyping);
            }
        } else {
            if (typingStartedSent) {
                setTypingStartedSent(false);

                roomSession.sendChatTypingMessage(isTyping);
            }
        }
    }, [roomSession, isTyping, typingStartedSent]);

    return { selectedUsername, floodBlocked, floodBlockedSeconds, setIsTyping, setIsIdle };
};
15Sujets
1Dépôts
20Membres
2En ligne
Profile
Inscrit
Dernière visite
Messages
0
Votes positifs
0
Votes négatifs
0

Nous utilisons des cookies pour assurer le bon fonctionnement du site et améliorer votre expérience. en savoir plus

Autoriser