mirror of
https://github.com/duckietm/Nitro-V3.git
synced 2026-06-19 15:06:20 +00:00
🆙 New: Added a new Chat window, handy for in game / building etc.
This commit is contained in:
@@ -2,4 +2,5 @@ export class LocalStorageKeys
|
|||||||
{
|
{
|
||||||
public static CATALOG_PLACE_MULTIPLE_OBJECTS: string = 'catalogPlaceMultipleObjects';
|
public static CATALOG_PLACE_MULTIPLE_OBJECTS: string = 'catalogPlaceMultipleObjects';
|
||||||
public static CATALOG_SKIP_PURCHASE_CONFIRMATION: string = 'catalogSkipPurchaseConfirmation';
|
public static CATALOG_SKIP_PURCHASE_CONFIRMATION: string = 'catalogSkipPurchaseConfirmation';
|
||||||
|
public static CHAT_WINDOW_ENABLED: string = 'chatWindowEnabled';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,16 @@
|
|||||||
import { RoomChatSettings } from '@nitrots/nitro-renderer';
|
import { RoomChatSettings } from '@nitrots/nitro-renderer';
|
||||||
import { FC, useCallback, useEffect, useRef } from 'react';
|
import { FC, useCallback, useEffect, useRef } from 'react';
|
||||||
import { ChatBubbleMessage, DoChatsOverlap, GetConfigurationValue } from '../../../../api';
|
import { ChatBubbleMessage, DoChatsOverlap, GetConfigurationValue } from '../../../../api';
|
||||||
import { useChatWidget } from '../../../../hooks';
|
import { useChatWidget, useChatWindow } from '../../../../hooks';
|
||||||
import IntervalWebWorker from '../../../../workers/IntervalWebWorker';
|
import IntervalWebWorker from '../../../../workers/IntervalWebWorker';
|
||||||
import { WorkerBuilder } from '../../../../workers/WorkerBuilder';
|
import { WorkerBuilder } from '../../../../workers/WorkerBuilder';
|
||||||
import { ChatWidgetMessageView } from './ChatWidgetMessageView';
|
import { ChatWidgetMessageView } from './ChatWidgetMessageView';
|
||||||
|
import { ChatWidgetWindowView } from './ChatWidgetWindowView';
|
||||||
|
|
||||||
export const ChatWidgetView: FC<{}> = props =>
|
export const ChatWidgetView: FC<{}> = props =>
|
||||||
{
|
{
|
||||||
const { chatMessages = [], setChatMessages = null, chatSettings = null, getScrollSpeed = 6000 } = useChatWidget();
|
const { chatMessages = [], setChatMessages = null, chatSettings = null, getScrollSpeed = 6000 } = useChatWidget();
|
||||||
|
const [ chatWindowEnabled ] = useChatWindow();
|
||||||
const elementRef = useRef<HTMLDivElement>();
|
const elementRef = useRef<HTMLDivElement>();
|
||||||
|
|
||||||
const removeHiddenChats = useCallback(() =>
|
const removeHiddenChats = useCallback(() =>
|
||||||
@@ -156,7 +158,8 @@ export const ChatWidgetView: FC<{}> = props =>
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={ elementRef } className="absolute flex justify-center items-center w-full top-0 min-h-px z-(--chat-zindex) bg-transparent roundehidden shadow-none pointer-events-none">
|
<div ref={ elementRef } className="absolute flex justify-center items-center w-full top-0 min-h-px z-(--chat-zindex) bg-transparent roundehidden shadow-none pointer-events-none">
|
||||||
{ chatMessages.map(chat => <ChatWidgetMessageView key={ chat.id } bubbleWidth={ chatSettings.weight } chat={ chat } makeRoom={ makeRoom } />) }
|
{ !chatWindowEnabled && chatMessages.map(chat => <ChatWidgetMessageView key={ chat.id } bubbleWidth={ chatSettings.weight } chat={ chat } makeRoom={ makeRoom } />) }
|
||||||
|
{ chatWindowEnabled && <ChatWidgetWindowView /> }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,172 @@
|
|||||||
|
import { GetSessionDataManager, RoomObjectType } from '@nitrots/nitro-renderer';
|
||||||
|
import { FC, UIEvent, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
|
import { ChatEntryType } from '../../../../api';
|
||||||
|
import { DraggableWindowPosition, NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../common';
|
||||||
|
import { useChatHistory, useChatWindow } from '../../../../hooks';
|
||||||
|
import { useRoom } from '../../../../hooks/rooms';
|
||||||
|
|
||||||
|
const BOTTOM_SCROLL_THRESHOLD = 20;
|
||||||
|
|
||||||
|
export const ChatWidgetWindowView: FC<{}> = () =>
|
||||||
|
{
|
||||||
|
const contentRef = useRef<HTMLDivElement>(null);
|
||||||
|
const lastScrollTop = useRef(0);
|
||||||
|
const [ isAutoScrollEnabled, setIsAutoScrollEnabled ] = useState(true);
|
||||||
|
const [ hidePets, setHidePets ] = useState(false);
|
||||||
|
const [ hideAvatars, setHideAvatars ] = useState(false);
|
||||||
|
const [ hideBalloons, setHideBalloons ] = useState(false);
|
||||||
|
const [ search, setSearch ] = useState('');
|
||||||
|
const { chatHistory = [], clearChatHistory = null } = useChatHistory();
|
||||||
|
const [ , setChatWindowEnabled ] = useChatWindow();
|
||||||
|
const { roomSession = null } = useRoom();
|
||||||
|
const ownUserId = (GetSessionDataManager()?.userId || -1);
|
||||||
|
|
||||||
|
const roomChatHistory = useMemo(() =>
|
||||||
|
{
|
||||||
|
const normalizedSearch = search.trim().toLowerCase();
|
||||||
|
|
||||||
|
return chatHistory.filter(chat =>
|
||||||
|
{
|
||||||
|
if(chat.type !== ChatEntryType.TYPE_CHAT) return false;
|
||||||
|
if(chat.roomId !== roomSession?.roomId) return false;
|
||||||
|
if(hidePets && chat.entityType === RoomObjectType.PET) return false;
|
||||||
|
|
||||||
|
if(!normalizedSearch.length) return true;
|
||||||
|
|
||||||
|
return (`${ chat.name } ${ chat.message }`.toLowerCase().includes(normalizedSearch));
|
||||||
|
});
|
||||||
|
}, [ chatHistory, roomSession?.roomId, hidePets, search ]);
|
||||||
|
|
||||||
|
const isAtBottom = useCallback((element: HTMLDivElement) =>
|
||||||
|
{
|
||||||
|
const distanceToBottom = (element.scrollHeight - element.clientHeight - element.scrollTop);
|
||||||
|
|
||||||
|
return (distanceToBottom <= BOTTOM_SCROLL_THRESHOLD);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const scrollToLatest = useCallback((smooth: boolean = true) =>
|
||||||
|
{
|
||||||
|
if(!contentRef.current) return;
|
||||||
|
|
||||||
|
const element = contentRef.current;
|
||||||
|
|
||||||
|
element.scrollTo({ top: element.scrollHeight, behavior: smooth ? 'smooth' : 'auto' });
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const onScroll = useCallback((event: UIEvent<HTMLDivElement>) =>
|
||||||
|
{
|
||||||
|
const element = event.currentTarget;
|
||||||
|
const atBottom = isAtBottom(element);
|
||||||
|
const isScrollingUp = (element.scrollTop < lastScrollTop.current);
|
||||||
|
|
||||||
|
lastScrollTop.current = element.scrollTop;
|
||||||
|
|
||||||
|
if(atBottom)
|
||||||
|
{
|
||||||
|
if(!isAutoScrollEnabled) setIsAutoScrollEnabled(true);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isAutoScrollEnabled && isScrollingUp) setIsAutoScrollEnabled(false);
|
||||||
|
}, [ isAtBottom, isAutoScrollEnabled ]);
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
if(!contentRef.current || !isAutoScrollEnabled) return;
|
||||||
|
|
||||||
|
scrollToLatest();
|
||||||
|
}, [ roomChatHistory.length, isAutoScrollEnabled, scrollToLatest ]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<NitroCardView
|
||||||
|
className="w-[460px] h-[240px]"
|
||||||
|
disableDrag={ false }
|
||||||
|
style={ { pointerEvents: 'auto' } }
|
||||||
|
theme="primary-slim"
|
||||||
|
uniqueKey="chat-widget-window"
|
||||||
|
windowPosition={ DraggableWindowPosition.TOP_LEFT }>
|
||||||
|
<NitroCardHeaderView headerText="Chat window" onCloseClick={ () =>
|
||||||
|
{
|
||||||
|
setChatWindowEnabled(false);
|
||||||
|
|
||||||
|
if(clearChatHistory) clearChatHistory();
|
||||||
|
} } />
|
||||||
|
<NitroCardContentView className="bg-[#f2f2f2] relative" overflow="hidden">
|
||||||
|
<div className="flex items-center gap-2 px-2 py-1 border-b border-black/20 bg-white/40 text-black text-[11px]">
|
||||||
|
<label className="flex items-center gap-1 cursor-pointer select-none">
|
||||||
|
<input checked={ hidePets } type="checkbox" onChange={ event => setHidePets(event.target.checked) } />
|
||||||
|
<span>hide pets</span>
|
||||||
|
</label>
|
||||||
|
<label className="flex items-center gap-1 cursor-pointer select-none">
|
||||||
|
<input checked={ hideAvatars } type="checkbox" onChange={ event => setHideAvatars(event.target.checked) } />
|
||||||
|
<span>hide avatars</span>
|
||||||
|
</label>
|
||||||
|
<button className="ml-auto px-1 py-0.5 rounded border border-black/30 bg-white/70 text-[11px] text-black hover:bg-white" onClick={ () => setHideBalloons(value => !value) } type="button">
|
||||||
|
{ hideBalloons ? 'show balloons' : 'hide balloons' }
|
||||||
|
</button>
|
||||||
|
<button className="px-1 py-0.5 rounded border border-black/30 bg-white/70 text-[11px] text-black hover:bg-white" onClick={ () =>
|
||||||
|
{
|
||||||
|
if(clearChatHistory) clearChatHistory();
|
||||||
|
} } type="button">
|
||||||
|
clear history
|
||||||
|
</button>
|
||||||
|
<div>
|
||||||
|
<input
|
||||||
|
className="h-[20px] px-1 rounded border border-black/30 bg-white/70 text-[11px] text-black"
|
||||||
|
placeholder="Search"
|
||||||
|
type="text"
|
||||||
|
value={ search }
|
||||||
|
onChange={ event => setSearch(event.target.value) } />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div ref={ contentRef } className="h-[calc(100%-31px)] overflow-y-auto px-2 py-1 text-black text-[13px] leading-4" onScroll={ onScroll }>
|
||||||
|
{ roomChatHistory.map(chat =>
|
||||||
|
{
|
||||||
|
const isOwnMessage = (chat.webId === ownUserId);
|
||||||
|
const rowClassName = `mb-1 flex items-start gap-1 break-words ${ isOwnMessage ? 'justify-end' : '' }`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div key={ `${ chat.timestamp }-${ chat.id }` } className={ rowClassName }>
|
||||||
|
{ hideBalloons && !hideAvatars && <div className={ `w-[65px] h-[55px] shrink-0 mt-[-18px] rounded-sm bg-no-repeat bg-center scale-70 ${ isOwnMessage ? 'order-2' : '' }` } style={ chat.imageUrl ? { backgroundImage: `url(${ chat.imageUrl })` } : undefined } /> }
|
||||||
|
{ hideBalloons && (
|
||||||
|
<div>
|
||||||
|
<b dangerouslySetInnerHTML={ { __html: `${ chat.name }: ` } } />
|
||||||
|
<span dangerouslySetInnerHTML={ { __html: chat.message } } />
|
||||||
|
</div>
|
||||||
|
) }
|
||||||
|
{ !hideBalloons && (
|
||||||
|
<div className="bubble-container relative inline-flex items-start">
|
||||||
|
{ chat.style === 0 && (
|
||||||
|
<div className="absolute -top-px left-px w-[30px] h-[calc(100%-0.5px)] rounded-[7px] z-1" style={ { backgroundColor: chat.color } } />
|
||||||
|
) }
|
||||||
|
<div className={ `chat-bubble bubble-${ chat.style } type-${ chat.chatType } relative z-1 wrap-break-word text-[14px]` } style={ { maxWidth: '100%' } }>
|
||||||
|
<div className="user-container flex items-center justify-center h-full max-h-[24px] overflow-hidden">
|
||||||
|
{ !hideAvatars && chat.imageUrl && chat.imageUrl.length > 0 && (
|
||||||
|
<div className={ `user-image absolute top-[-15px] w-[45px] h-[65px] bg-no-repeat bg-center ${ isOwnMessage ? 'right-[-9.25px]' : 'left-[-9.25px]' }` } style={ { backgroundImage: `url(${ chat.imageUrl })` } } />
|
||||||
|
) }
|
||||||
|
</div>
|
||||||
|
<div className={ `chat-content py-[5px] px-[6px] leading-none min-h-[25px] ${ !hideAvatars ? (isOwnMessage ? 'mr-[27px]' : 'ml-[27px]') : '' }` }>
|
||||||
|
<b className="username" dangerouslySetInnerHTML={ { __html: `${ chat.name }: ` } } />
|
||||||
|
<span className="message" dangerouslySetInnerHTML={ { __html: `${ chat.message }` } } />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) }
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}) }
|
||||||
|
</div>
|
||||||
|
{ !isAutoScrollEnabled && (
|
||||||
|
<button className="absolute bottom-2 right-2 px-2 py-1 text-white text-[11px] rounded bg-black/45 hover:bg-black/60" onClick={ () =>
|
||||||
|
{
|
||||||
|
setIsAutoScrollEnabled(true);
|
||||||
|
scrollToLatest();
|
||||||
|
} } type="button">
|
||||||
|
Go to latest message
|
||||||
|
</button>
|
||||||
|
) }
|
||||||
|
</NitroCardContentView>
|
||||||
|
</NitroCardView>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
import { FC, UIEvent, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
|
import { ChatEntryType } from '../../../../api';
|
||||||
|
import { DraggableWindowPosition, NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../common';
|
||||||
|
import { useChatHistory } from '../../../../hooks';
|
||||||
|
import { useRoom } from '../../../../hooks/rooms';
|
||||||
|
|
||||||
|
const BOTTOM_SCROLL_THRESHOLD = 20;
|
||||||
|
|
||||||
|
export const ChatWidgetWindowView: FC<{}> = () =>
|
||||||
|
{
|
||||||
|
const contentRef = useRef<HTMLDivElement>(null);
|
||||||
|
const lastScrollTop = useRef(0);
|
||||||
|
const [ isAutoScrollEnabled, setIsAutoScrollEnabled ] = useState(true);
|
||||||
|
const { chatHistory = [] } = useChatHistory();
|
||||||
|
const { roomSession = null } = useRoom();
|
||||||
|
|
||||||
|
const roomChatHistory = useMemo(() => chatHistory.filter(chat => ((chat.type === ChatEntryType.TYPE_CHAT) && (chat.roomId === roomSession?.roomId))), [ chatHistory, roomSession?.roomId ]);
|
||||||
|
|
||||||
|
const isAtBottom = useCallback((element: HTMLDivElement) =>
|
||||||
|
{
|
||||||
|
const distanceToBottom = (element.scrollHeight - element.clientHeight - element.scrollTop);
|
||||||
|
|
||||||
|
return (distanceToBottom <= BOTTOM_SCROLL_THRESHOLD);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const scrollToLatest = useCallback((smooth: boolean = true) =>
|
||||||
|
{
|
||||||
|
if(!contentRef.current) return;
|
||||||
|
|
||||||
|
const element = contentRef.current;
|
||||||
|
|
||||||
|
element.scrollTo({ top: element.scrollHeight, behavior: smooth ? 'smooth' : 'auto' });
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const onScroll = useCallback((event: UIEvent<HTMLDivElement>) =>
|
||||||
|
{
|
||||||
|
const element = event.currentTarget;
|
||||||
|
const atBottom = isAtBottom(element);
|
||||||
|
const isScrollingUp = (element.scrollTop < lastScrollTop.current);
|
||||||
|
|
||||||
|
lastScrollTop.current = element.scrollTop;
|
||||||
|
|
||||||
|
if(atBottom)
|
||||||
|
{
|
||||||
|
if(!isAutoScrollEnabled) setIsAutoScrollEnabled(true);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isAutoScrollEnabled && isScrollingUp) setIsAutoScrollEnabled(false);
|
||||||
|
}, [ isAtBottom, isAutoScrollEnabled ]);
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
if(!contentRef.current || !isAutoScrollEnabled) return;
|
||||||
|
|
||||||
|
scrollToLatest();
|
||||||
|
}, [ roomChatHistory.length, isAutoScrollEnabled, scrollToLatest ]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<NitroCardView
|
||||||
|
className="w-[460px] h-[240px]"
|
||||||
|
disableDrag={ false }
|
||||||
|
style={ { pointerEvents: 'auto' } }
|
||||||
|
theme="primary-slim"
|
||||||
|
uniqueKey="chat-widget-window"
|
||||||
|
windowPosition={ DraggableWindowPosition.TOP_LEFT }>
|
||||||
|
<NitroCardHeaderView headerText="Chat window" />
|
||||||
|
<NitroCardContentView className="bg-[#f2f2f2] relative" overflow="hidden">
|
||||||
|
<div ref={ contentRef } className="h-full overflow-y-auto px-2 py-1 text-black text-[13px] leading-4" onScroll={ onScroll }>
|
||||||
|
{ roomChatHistory.map(chat => (
|
||||||
|
<div key={ `${ chat.timestamp }-${ chat.id }` } className="mb-1 flex items-start gap-1 break-words">
|
||||||
|
<div className="w-[65px] h-[50px] shrink-0 mt-[-8px] rounded-sm bg-no-repeat bg-center scale-70" style={ chat.imageUrl ? { backgroundImage: `url(${ chat.imageUrl })` } : undefined } />
|
||||||
|
<div>
|
||||||
|
<b dangerouslySetInnerHTML={ { __html: `${ chat.name }: ` } } />
|
||||||
|
<span dangerouslySetInnerHTML={ { __html: chat.message } } />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)) }
|
||||||
|
</div>
|
||||||
|
{ !isAutoScrollEnabled && (
|
||||||
|
<button className="absolute bottom-2 right-2 px-2 py-1 text-white text-[11px] rounded bg-black/45 hover:bg-black/60" onClick={ () =>
|
||||||
|
{
|
||||||
|
setIsAutoScrollEnabled(true);
|
||||||
|
scrollToLatest();
|
||||||
|
} } type="button">
|
||||||
|
Go to latest message
|
||||||
|
</button>
|
||||||
|
) }
|
||||||
|
</NitroCardContentView>
|
||||||
|
</NitroCardView>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -3,7 +3,7 @@ import { FC, useEffect, useState } from 'react';
|
|||||||
import { FaVolumeDown, FaVolumeMute, FaVolumeUp } from 'react-icons/fa';
|
import { FaVolumeDown, FaVolumeMute, FaVolumeUp } from 'react-icons/fa';
|
||||||
import { DispatchMainEvent, DispatchUiEvent, LocalizeText, SendMessageComposer } from '../../api';
|
import { DispatchMainEvent, DispatchUiEvent, LocalizeText, SendMessageComposer } from '../../api';
|
||||||
import { NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../common';
|
import { NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../common';
|
||||||
import { useCatalogPlaceMultipleItems, useCatalogSkipPurchaseConfirmation, useMessageEvent } from '../../hooks';
|
import { useCatalogPlaceMultipleItems, useCatalogSkipPurchaseConfirmation, useChatWindow, useMessageEvent } from '../../hooks';
|
||||||
import { classNames } from '../../layout';
|
import { classNames } from '../../layout';
|
||||||
|
|
||||||
export const UserSettingsView: FC<{}> = props =>
|
export const UserSettingsView: FC<{}> = props =>
|
||||||
@@ -12,6 +12,7 @@ export const UserSettingsView: FC<{}> = props =>
|
|||||||
const [ userSettings, setUserSettings ] = useState<NitroSettingsEvent>(null);
|
const [ userSettings, setUserSettings ] = useState<NitroSettingsEvent>(null);
|
||||||
const [ catalogPlaceMultipleObjects, setCatalogPlaceMultipleObjects ] = useCatalogPlaceMultipleItems();
|
const [ catalogPlaceMultipleObjects, setCatalogPlaceMultipleObjects ] = useCatalogPlaceMultipleItems();
|
||||||
const [ catalogSkipPurchaseConfirmation, setCatalogSkipPurchaseConfirmation ] = useCatalogSkipPurchaseConfirmation();
|
const [ catalogSkipPurchaseConfirmation, setCatalogSkipPurchaseConfirmation ] = useCatalogSkipPurchaseConfirmation();
|
||||||
|
const [ chatWindowEnabled, setChatWindowEnabled ] = useChatWindow();
|
||||||
|
|
||||||
const processAction = (type: string, value?: boolean | number | string) =>
|
const processAction = (type: string, value?: boolean | number | string) =>
|
||||||
{
|
{
|
||||||
@@ -151,6 +152,10 @@ export const UserSettingsView: FC<{}> = props =>
|
|||||||
<input checked={ catalogSkipPurchaseConfirmation } className="form-check-input" type="checkbox" onChange={ event => setCatalogSkipPurchaseConfirmation(event.target.checked) } />
|
<input checked={ catalogSkipPurchaseConfirmation } className="form-check-input" type="checkbox" onChange={ event => setCatalogSkipPurchaseConfirmation(event.target.checked) } />
|
||||||
<Text>{ LocalizeText('memenu.settings.other.skip.purchase.confirmation') }</Text>
|
<Text>{ LocalizeText('memenu.settings.other.skip.purchase.confirmation') }</Text>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="flex items-center gap-1">
|
||||||
|
<input checked={ chatWindowEnabled } className="form-check-input" type="checkbox" onChange={ event => setChatWindowEnabled(event.target.checked) } />
|
||||||
|
<Text>Enable chat window</Text>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<Text bold>{ LocalizeText('widget.memenu.settings.volume') }</Text>
|
<Text bold>{ LocalizeText('widget.memenu.settings.volume') }</Text>
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import { ChatEntryType, ChatHistoryCurrentDate, IChatEntry, IRoomHistoryEntry, M
|
|||||||
import { useMessageEvent, useNitroEvent } from '../events';
|
import { useMessageEvent, useNitroEvent } from '../events';
|
||||||
import { useLocalStorage } from '../useLocalStorage';
|
import { useLocalStorage } from '../useLocalStorage';
|
||||||
|
|
||||||
const CHAT_HISTORY_MAX = 1000;
|
|
||||||
const ROOM_HISTORY_MAX = 10;
|
const ROOM_HISTORY_MAX = 10;
|
||||||
const MESSENGER_HISTORY_MAX = 1000;
|
const MESSENGER_HISTORY_MAX = 1000;
|
||||||
|
|
||||||
@@ -29,12 +28,13 @@ const useChatHistoryState = () =>
|
|||||||
|
|
||||||
newValue.push(entry);
|
newValue.push(entry);
|
||||||
|
|
||||||
if(newValue.length > CHAT_HISTORY_MAX) newValue.shift();
|
|
||||||
|
|
||||||
return newValue;
|
return newValue;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const clearChatHistory = () => setChatHistory([]);
|
||||||
|
|
||||||
const addRoomHistoryEntry = (entry: IRoomHistoryEntry) =>
|
const addRoomHistoryEntry = (entry: IRoomHistoryEntry) =>
|
||||||
{
|
{
|
||||||
setRoomHistory(prevValue =>
|
setRoomHistory(prevValue =>
|
||||||
@@ -99,7 +99,7 @@ const useChatHistoryState = () =>
|
|||||||
addMessengerEntry({ id: -1, webId: parser.senderId, entityId: -1, name: '', message: parser.messageText, roomId: -1, timestamp: MessengerHistoryCurrentDate(), type: ChatEntryType.TYPE_IM });
|
addMessengerEntry({ id: -1, webId: parser.senderId, entityId: -1, name: '', message: parser.messageText, roomId: -1, timestamp: MessengerHistoryCurrentDate(), type: ChatEntryType.TYPE_IM });
|
||||||
});
|
});
|
||||||
|
|
||||||
return { addChatEntry, chatHistory, roomHistory, messengerHistory };
|
return { addChatEntry, clearChatHistory, chatHistory, roomHistory, messengerHistory };
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useChatHistory = () => useBetween(useChatHistoryState);
|
export const useChatHistory = () => useBetween(useChatHistoryState);
|
||||||
|
|||||||
@@ -22,3 +22,4 @@ export * from './session';
|
|||||||
export * from './useLocalStorage';
|
export * from './useLocalStorage';
|
||||||
export * from './useSharedVisibility';
|
export * from './useSharedVisibility';
|
||||||
export * from './wired';
|
export * from './wired';
|
||||||
|
export * from './useChatWindow';
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import { useMessageEvent, useNitroEvent } from '../../events';
|
|||||||
import { useRoom } from '../useRoom';
|
import { useRoom } from '../useRoom';
|
||||||
import { useChatHistory } from './../../chat-history';
|
import { useChatHistory } from './../../chat-history';
|
||||||
|
|
||||||
|
const CHAT_MESSAGES_MAX = 250;
|
||||||
|
|
||||||
const useChatWidgetState = () =>
|
const useChatWidgetState = () =>
|
||||||
{
|
{
|
||||||
const [chatMessages, setChatMessages] = useState<ChatBubbleMessage[]>([]);
|
const [chatMessages, setChatMessages] = useState<ChatBubbleMessage[]>([]);
|
||||||
@@ -146,7 +148,14 @@ const useChatWidgetState = () =>
|
|||||||
imageUrl,
|
imageUrl,
|
||||||
color);
|
color);
|
||||||
|
|
||||||
setChatMessages(prevValue => [...prevValue, chatMessage]);
|
setChatMessages(prevValue =>
|
||||||
|
{
|
||||||
|
const newValue = [ ...prevValue, chatMessage ];
|
||||||
|
|
||||||
|
if(newValue.length > CHAT_MESSAGES_MAX) newValue.shift();
|
||||||
|
|
||||||
|
return newValue;
|
||||||
|
});
|
||||||
addChatEntry({ id: -1, webId: userData.webID, entityId: userData.roomIndex, name: username, imageUrl, style: styleId, chatType: chatType, entityType: userData.type, message: formattedText, timestamp: ChatHistoryCurrentDate(), type: ChatEntryType.TYPE_CHAT, roomId: roomSession.roomId, color });
|
addChatEntry({ id: -1, webId: userData.webID, entityId: userData.roomIndex, name: username, imageUrl, style: styleId, chatType: chatType, entityType: userData.type, message: formattedText, timestamp: ChatHistoryCurrentDate(), type: ChatEntryType.TYPE_CHAT, roomId: roomSession.roomId, color });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import { useBetween } from 'use-between';
|
||||||
|
import { LocalStorageKeys } from '../api';
|
||||||
|
import { useLocalStorage } from './useLocalStorage';
|
||||||
|
|
||||||
|
const useChatWindowState = () => useLocalStorage(LocalStorageKeys.CHAT_WINDOW_ENABLED, false);
|
||||||
|
|
||||||
|
export const useChatWindow = () => useBetween(useChatWindowState);
|
||||||
Reference in New Issue
Block a user