Files
Epicnabbo-Catalogus-Updated…/Coolui v3 test/src/components/room/widgets/chat/ChatWidgetView.tsx
T
2026-01-27 14:08:40 +01:00

163 lines
5.1 KiB
TypeScript

import { RoomChatSettings } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useRef } from 'react';
import { ChatBubbleMessage, DoChatsOverlap, GetConfigurationValue } from '../../../../api';
import { useChatWidget } from '../../../../hooks';
import IntervalWebWorker from '../../../../workers/IntervalWebWorker';
import { WorkerBuilder } from '../../../../workers/WorkerBuilder';
import { ChatWidgetMessageView } from './ChatWidgetMessageView';
export const ChatWidgetView: FC<{}> = props =>
{
const { chatMessages = [], setChatMessages = null, chatSettings = null, getScrollSpeed = 6000 } = useChatWidget();
const elementRef = useRef<HTMLDivElement>();
const removeHiddenChats = useCallback(() =>
{
setChatMessages(prevValue =>
{
if(prevValue)
{
const newMessages = prevValue.filter(chat => ((chat.top > (-(chat.height) * 2))));
if(newMessages.length !== prevValue.length) return newMessages;
}
return prevValue;
});
}, [ setChatMessages ]);
const checkOverlappingChats = useCallback((chat: ChatBubbleMessage, moved: number, tempChats: ChatBubbleMessage[]) =>
{
for(let i = (chatMessages.indexOf(chat) - 1); i >= 0; i--)
{
const collides = chatMessages[i];
if(!collides || (chat === collides) || (tempChats.indexOf(collides) >= 0) || (((collides.top + collides.height) - moved) > (chat.top + chat.height))) continue;
if(DoChatsOverlap(chat, collides, -moved, 0))
{
const amount = Math.abs((collides.top + collides.height) - chat.top);
tempChats.push(collides);
collides.top -= amount;
collides.skipMovement = true;
checkOverlappingChats(collides, amount, tempChats);
}
}
}, [ chatMessages ]);
const makeRoom = useCallback((chat: ChatBubbleMessage) =>
{
if(chatSettings.mode === RoomChatSettings.CHAT_MODE_FREE_FLOW)
{
chat.skipMovement = true;
checkOverlappingChats(chat, 0, [ chat ]);
removeHiddenChats();
}
else
{
const lowestPoint = (chat.top + chat.height);
const requiredSpace = chat.height;
const spaceAvailable = (elementRef.current.offsetHeight - lowestPoint);
const amount = (requiredSpace - spaceAvailable);
if(spaceAvailable < requiredSpace)
{
setChatMessages(prevValue =>
{
prevValue.forEach(prevChat =>
{
if(prevChat === chat) return;
prevChat.top -= amount;
});
return prevValue;
});
removeHiddenChats();
}
}
}, [ chatSettings, checkOverlappingChats, removeHiddenChats, setChatMessages ]);
useEffect(() =>
{
const resize = (event: UIEvent = null) =>
{
if(!elementRef || !elementRef.current) return;
const currentHeight = elementRef.current.offsetHeight;
const newHeight = Math.round(document.body.offsetHeight * GetConfigurationValue<number>('chat.viewer.height.percentage'));
elementRef.current.style.height = `${ newHeight }px`;
setChatMessages(prevValue =>
{
if(prevValue)
{
prevValue.forEach(chat => (chat.top -= (currentHeight - newHeight)));
}
return prevValue;
});
};
window.addEventListener('resize', resize);
resize();
return () =>
{
window.removeEventListener('resize', resize);
};
}, [ setChatMessages ]);
useEffect(() =>
{
const moveAllChatsUp = (amount: number) =>
{
setChatMessages(prevValue =>
{
prevValue.forEach(chat =>
{
if(chat.skipMovement)
{
chat.skipMovement = false;
return;
}
chat.top -= amount;
});
return prevValue;
});
removeHiddenChats();
};
const worker = new WorkerBuilder(IntervalWebWorker);
worker.onmessage = () => moveAllChatsUp(15);
worker.postMessage({ action: 'START', content: getScrollSpeed });
return () =>
{
worker.postMessage({ action: 'STOP' });
worker.terminate();
};
}, [ getScrollSpeed, removeHiddenChats, setChatMessages ]);
return (
<div ref={ elementRef } className="absolute flex justify-center items-center w-full top-0 min-h-[1px] z-[var(--chat-zindex)] bg-transparent roundehidden shadow-none pointer-events-none">
{ chatMessages.map(chat => <ChatWidgetMessageView key={ chat.id } bubbleWidth={ chatSettings.weight } chat={ chat } makeRoom={ makeRoom } />) }
</div>
);
};