From 7926bb7469bd0cbc17d699d1ae003629f7e6f17d Mon Sep 17 00:00:00 2001 From: MyNameIsBatman Date: Thu, 16 Sep 2021 01:37:17 -0300 Subject: [PATCH 01/31] Updates DONT TOUCH IT --- .../handlers/RoomWidgetInfostandHandler.ts | 4 +- src/events/friend-list/index.ts | 2 - .../FriendEnteredRoomEvent.ts | 0 .../FriendListContentEvent.ts | 4 +- .../FriendsEvent.ts} | 4 +- .../FriendsSendFriendRequestEvent.ts} | 6 +- src/events/friends/index.ts | 4 + src/events/index.ts | 2 +- .../friends/FriendListMessageHandler.tsx | 73 ---------- .../friends/FriendListMessageHandler.types.ts | 5 - src/views/friends/FriendsMessageHandler.tsx | 90 ++++++++++++ src/views/friends/FriendsView.scss | 2 +- src/views/friends/FriendsView.tsx | 128 +++++++----------- src/views/friends/common/MessengerChat.ts | 34 +++++ .../friends/common/MessengerChatMessage.ts | 13 ++ .../friends/context/FriendListContext.tsx | 14 -- .../friends/context/FriendListContext.type.ts | 13 -- src/views/friends/context/FriendsContext.tsx | 14 ++ .../friends/context/FriendsContext.type.ts | 13 ++ ...iendListReducer.tsx => FriendsReducer.tsx} | 40 ++++-- .../views/friend-bar/FriendBarView.tsx | 6 +- .../views/friend-item/FriendsListItemView.tsx | 3 +- .../FriendsGroupItemView.tsx | 63 +++++++++ .../FriendsGroupItemView.types.ts | 6 + .../FriendsGroupView.tsx} | 10 +- .../FriendsGroupView.types.ts} | 2 +- .../views/friends-list/FriendsListView.tsx | 43 ++++++ .../friends-list/FriendsListView.types.ts | 9 ++ .../FriendsRequestItemView.tsx | 37 +++++ .../FriendsRequestItemView.types.ts | 6 + .../views/messenger/FriendsMessengerView.tsx | 13 ++ .../FriendsRequestItemView.types.ts | 3 +- .../NavigatorRoomSettingsView.tsx | 6 +- src/views/toolbar/ToolbarView.tsx | 4 +- 34 files changed, 450 insertions(+), 226 deletions(-) delete mode 100644 src/events/friend-list/index.ts rename src/events/{friend-list => friends}/FriendEnteredRoomEvent.ts (100%) rename src/events/{friend-list => friends}/FriendListContentEvent.ts (83%) rename src/events/{friend-list/FriendListEvent.ts => friends/FriendsEvent.ts} (57%) rename src/events/{friend-list/FriendListSendFriendRequestEvent.ts => friends/FriendsSendFriendRequestEvent.ts} (57%) create mode 100644 src/events/friends/index.ts delete mode 100644 src/views/friends/FriendListMessageHandler.tsx delete mode 100644 src/views/friends/FriendListMessageHandler.types.ts create mode 100644 src/views/friends/FriendsMessageHandler.tsx create mode 100644 src/views/friends/common/MessengerChat.ts create mode 100644 src/views/friends/common/MessengerChatMessage.ts delete mode 100644 src/views/friends/context/FriendListContext.tsx delete mode 100644 src/views/friends/context/FriendListContext.type.ts create mode 100644 src/views/friends/context/FriendsContext.tsx create mode 100644 src/views/friends/context/FriendsContext.type.ts rename src/views/friends/reducers/{FriendListReducer.tsx => FriendsReducer.tsx} (77%) create mode 100644 src/views/friends/views/friends-group-item/FriendsGroupItemView.tsx create mode 100644 src/views/friends/views/friends-group-item/FriendsGroupItemView.types.ts rename src/views/friends/views/{list/FriendsListView.tsx => friends-group/FriendsGroupView.tsx} (58%) rename src/views/friends/views/{list/FriendsListView.types.ts => friends-group/FriendsGroupView.types.ts} (82%) create mode 100644 src/views/friends/views/friends-list/FriendsListView.tsx create mode 100644 src/views/friends/views/friends-list/FriendsListView.types.ts create mode 100644 src/views/friends/views/friends-request-item/FriendsRequestItemView.tsx create mode 100644 src/views/friends/views/friends-request-item/FriendsRequestItemView.types.ts create mode 100644 src/views/friends/views/messenger/FriendsMessengerView.tsx diff --git a/src/api/nitro/room/widgets/handlers/RoomWidgetInfostandHandler.ts b/src/api/nitro/room/widgets/handlers/RoomWidgetInfostandHandler.ts index 1ee584ce..e86aba4e 100644 --- a/src/api/nitro/room/widgets/handlers/RoomWidgetInfostandHandler.ts +++ b/src/api/nitro/room/widgets/handlers/RoomWidgetInfostandHandler.ts @@ -1,7 +1,7 @@ import { IFurnitureData, NitroEvent, ObjectDataFactory, PetFigureData, PetRespectComposer, PetSupplementComposer, PetType, RoomControllerLevel, RoomModerationSettings, RoomObjectCategory, RoomObjectOperationType, RoomObjectType, RoomObjectVariable, RoomSessionPetInfoUpdateEvent, RoomSessionUserBadgesEvent, RoomTradingLevelEnum, RoomUnitDropHandItemComposer, RoomUnitGiveHandItemComposer, RoomUnitGiveHandItemPetComposer, RoomUserData, RoomWidgetEnum, RoomWidgetEnumItemExtradataParameter, Vector3d } from '@nitrots/nitro-renderer'; import { GetNitroInstance, GetRoomEngine, GetSessionDataManager, IsOwnerOfFurniture } from '../../../..'; import { InventoryTradeRequestEvent, WiredSelectObjectEvent } from '../../../../../events'; -import { FriendListSendFriendRequestEvent } from '../../../../../events/friend-list/FriendListSendFriendRequestEvent'; +import { FriendsSendFriendRequestEvent } from '../../../../../events/friends/FriendsSendFriendRequestEvent'; import { dispatchUiEvent } from '../../../../../hooks/events'; import { SendMessageHook } from '../../../../../hooks/messages'; import { PetSupplementEnum } from '../../../../../views/room/widgets/avatar-info/common/PetSupplementEnum'; @@ -76,7 +76,7 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler case RoomWidgetRoomObjectMessage.GET_OBJECT_INFO: return this.processObjectInfoMessage((message as RoomWidgetRoomObjectMessage)); case RoomWidgetUserActionMessage.SEND_FRIEND_REQUEST: - dispatchUiEvent(new FriendListSendFriendRequestEvent(userId)); + dispatchUiEvent(new FriendsSendFriendRequestEvent(userId)); break; case RoomWidgetUserActionMessage.RESPECT_USER: GetSessionDataManager().giveRespect(userId); diff --git a/src/events/friend-list/index.ts b/src/events/friend-list/index.ts deleted file mode 100644 index 4789fde9..00000000 --- a/src/events/friend-list/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './FriendEnteredRoomEvent'; -export * from './FriendListEvent'; diff --git a/src/events/friend-list/FriendEnteredRoomEvent.ts b/src/events/friends/FriendEnteredRoomEvent.ts similarity index 100% rename from src/events/friend-list/FriendEnteredRoomEvent.ts rename to src/events/friends/FriendEnteredRoomEvent.ts diff --git a/src/events/friend-list/FriendListContentEvent.ts b/src/events/friends/FriendListContentEvent.ts similarity index 83% rename from src/events/friend-list/FriendListContentEvent.ts rename to src/events/friends/FriendListContentEvent.ts index a7623cbc..80048267 100644 --- a/src/events/friend-list/FriendListContentEvent.ts +++ b/src/events/friends/FriendListContentEvent.ts @@ -1,7 +1,7 @@ import { MessengerFriend } from '../../views/friends/common/MessengerFriend'; -import { FriendListEvent } from './FriendListEvent'; +import { FriendsEvent } from './FriendsEvent'; -export class FriendListContentEvent extends FriendListEvent +export class FriendListContentEvent extends FriendsEvent { public static FRIEND_LIST_CONTENT: string = 'FLSFRE_FRIEND_LIST_CONTENT'; diff --git a/src/events/friend-list/FriendListEvent.ts b/src/events/friends/FriendsEvent.ts similarity index 57% rename from src/events/friend-list/FriendListEvent.ts rename to src/events/friends/FriendsEvent.ts index d450144e..0f8be1d7 100644 --- a/src/events/friend-list/FriendListEvent.ts +++ b/src/events/friends/FriendsEvent.ts @@ -1,8 +1,10 @@ import { NitroEvent } from '@nitrots/nitro-renderer'; -export class FriendListEvent extends NitroEvent +export class FriendsEvent extends NitroEvent { public static SHOW_FRIEND_LIST: string = 'IE_SHOW_FRIEND_LIST'; public static TOGGLE_FRIEND_LIST: string = 'IE_TOGGLE_FRIEND_LIST'; + public static SHOW_FRIEND_MESSENGER: string = 'IE_SHOW_FRIEND_MESSENGER'; + public static TOGGLE_FRIEND_MESSENGER: string = 'IE_TOGGLE_FRIEND_MESSENGER'; public static REQUEST_FRIEND_LIST: string = 'FLSFRE_REQUEST_FRIEND_LIST'; } diff --git a/src/events/friend-list/FriendListSendFriendRequestEvent.ts b/src/events/friends/FriendsSendFriendRequestEvent.ts similarity index 57% rename from src/events/friend-list/FriendListSendFriendRequestEvent.ts rename to src/events/friends/FriendsSendFriendRequestEvent.ts index 02d7c006..9e42661b 100644 --- a/src/events/friend-list/FriendListSendFriendRequestEvent.ts +++ b/src/events/friends/FriendsSendFriendRequestEvent.ts @@ -1,6 +1,6 @@ -import { FriendListEvent } from './FriendListEvent'; +import { FriendsEvent } from './FriendsEvent'; -export class FriendListSendFriendRequestEvent extends FriendListEvent +export class FriendsSendFriendRequestEvent extends FriendsEvent { public static SEND_FRIEND_REQUEST: string = 'FLSFRE_SEND_FRIEND_REQUEST'; @@ -8,7 +8,7 @@ export class FriendListSendFriendRequestEvent extends FriendListEvent constructor(userId: number) { - super(FriendListSendFriendRequestEvent.SEND_FRIEND_REQUEST); + super(FriendsSendFriendRequestEvent.SEND_FRIEND_REQUEST); this._userId = userId; } diff --git a/src/events/friends/index.ts b/src/events/friends/index.ts new file mode 100644 index 00000000..9a4bb3ed --- /dev/null +++ b/src/events/friends/index.ts @@ -0,0 +1,4 @@ +export * from './FriendEnteredRoomEvent'; +export * from './FriendListContentEvent'; +export * from './FriendsEvent'; +export * from './FriendsSendFriendRequestEvent'; diff --git a/src/events/index.ts b/src/events/index.ts index 006285c8..9d4842ca 100644 --- a/src/events/index.ts +++ b/src/events/index.ts @@ -1,7 +1,7 @@ export * from './avatar-editor'; export * from './camera'; export * from './catalog'; -export * from './friend-list'; +export * from './friends'; export * from './inventory'; export * from './navigator'; export * from './notification-center'; diff --git a/src/views/friends/FriendListMessageHandler.tsx b/src/views/friends/FriendListMessageHandler.tsx deleted file mode 100644 index e84e72a5..00000000 --- a/src/views/friends/FriendListMessageHandler.tsx +++ /dev/null @@ -1,73 +0,0 @@ -import { FriendListFragmentEvent, FriendListUpdateEvent, FriendRequestsEvent, GetFriendRequestsComposer, MessengerInitEvent } from '@nitrots/nitro-renderer'; -import { FC, useCallback } from 'react'; -import { CreateMessageHook, SendMessageHook } from '../../hooks/messages/message-event'; -import { MessengerSettings } from './common/MessengerSettings'; -import { useFriendListContext } from './context/FriendListContext'; -import { FriendListMessageHandlerProps } from './FriendListMessageHandler.types'; -import { FriendListActions } from './reducers/FriendListReducer'; - -export const FriendListMessageHandler: FC = props => -{ - const { friendListState = null, dispatchFriendListState = null } = useFriendListContext(); - - const onMessengerInitEvent = useCallback((event: MessengerInitEvent) => - { - const parser = event.getParser(); - - dispatchFriendListState({ - type: FriendListActions.UPDATE_SETTINGS, - payload: { - settings: new MessengerSettings( - parser.userFriendLimit, - parser.normalFriendLimit, - parser.extendedFriendLimit, - parser.categories) - } - }); - - SendMessageHook(new GetFriendRequestsComposer()); - }, [ dispatchFriendListState ]); - - const onFriendListFragmentEvent = useCallback((event: FriendListFragmentEvent) => - { - const parser = event.getParser(); - - dispatchFriendListState({ - type: FriendListActions.PROCESS_FRAGMENT, - payload: { - fragment: parser.fragment - } - }); - }, [ dispatchFriendListState ]); - - const onFriendListUpdateEvent = useCallback((event: FriendListUpdateEvent) => - { - const parser = event.getParser(); - - dispatchFriendListState({ - type: FriendListActions.PROCESS_UPDATE, - payload: { - update: parser - } - }); - }, [ dispatchFriendListState ]); - - const onFriendRequestsEvent = useCallback((event: FriendRequestsEvent) => - { - const parser = event.getParser(); - - dispatchFriendListState({ - type: FriendListActions.PROCESS_REQUESTS, - payload: { - requests: parser.requests - } - }); - }, [ dispatchFriendListState ]); - - CreateMessageHook(MessengerInitEvent, onMessengerInitEvent); - CreateMessageHook(FriendListFragmentEvent, onFriendListFragmentEvent); - CreateMessageHook(FriendListUpdateEvent, onFriendListUpdateEvent); - CreateMessageHook(FriendRequestsEvent, onFriendRequestsEvent); - - return null; -} diff --git a/src/views/friends/FriendListMessageHandler.types.ts b/src/views/friends/FriendListMessageHandler.types.ts deleted file mode 100644 index 2a810612..00000000 --- a/src/views/friends/FriendListMessageHandler.types.ts +++ /dev/null @@ -1,5 +0,0 @@ - -export interface FriendListMessageHandlerProps -{ - -} diff --git a/src/views/friends/FriendsMessageHandler.tsx b/src/views/friends/FriendsMessageHandler.tsx new file mode 100644 index 00000000..579230a5 --- /dev/null +++ b/src/views/friends/FriendsMessageHandler.tsx @@ -0,0 +1,90 @@ +import { FriendListFragmentEvent, FriendListUpdateEvent, FriendRequestsEvent, GetFriendRequestsComposer, MessengerInitEvent, NewConsoleMessageEvent } from '@nitrots/nitro-renderer'; +import { FC, useCallback } from 'react'; +import { CreateMessageHook, SendMessageHook } from '../../hooks/messages/message-event'; +import { MessengerSettings } from './common/MessengerSettings'; +import { useFriendsContext } from './context/FriendsContext'; +import { FriendsActions } from './reducers/FriendsReducer'; + +export const FriendsMessageHandler: FC<{}> = props => +{ + const { friendsState = null, dispatchFriendsState = null } = useFriendsContext(); + const { activeChats = [] } = friendsState; + + const onMessengerInitEvent = useCallback((event: MessengerInitEvent) => + { + const parser = event.getParser(); + + dispatchFriendsState({ + type: FriendsActions.UPDATE_SETTINGS, + payload: { + settings: new MessengerSettings( + parser.userFriendLimit, + parser.normalFriendLimit, + parser.extendedFriendLimit, + parser.categories) + } + }); + + SendMessageHook(new GetFriendRequestsComposer()); + }, [ dispatchFriendsState ]); + + const onFriendsFragmentEvent = useCallback((event: FriendListFragmentEvent) => + { + const parser = event.getParser(); + + dispatchFriendsState({ + type: FriendsActions.PROCESS_FRAGMENT, + payload: { + fragment: parser.fragment + } + }); + }, [ dispatchFriendsState ]); + + const onFriendsUpdateEvent = useCallback((event: FriendListUpdateEvent) => + { + const parser = event.getParser(); + + dispatchFriendsState({ + type: FriendsActions.PROCESS_UPDATE, + payload: { + update: parser + } + }); + }, [ dispatchFriendsState ]); + + const onFriendRequestsEvent = useCallback((event: FriendRequestsEvent) => + { + const parser = event.getParser(); + + dispatchFriendsState({ + type: FriendsActions.PROCESS_REQUESTS, + payload: { + requests: parser.requests + } + }); + }, [ dispatchFriendsState ]); + + const onNewConsoleMessageEvent = useCallback((event: NewConsoleMessageEvent) => + { + const parser = event.getParser(); + + const activeChat = activeChats.find(c => c.friendId === parser.senderId); + + if(activeChat) + { + + } + else + { + + } + }, [ friendsState, dispatchFriendsState ]); + + CreateMessageHook(MessengerInitEvent, onMessengerInitEvent); + CreateMessageHook(FriendListFragmentEvent, onFriendsFragmentEvent); + CreateMessageHook(FriendListUpdateEvent, onFriendsUpdateEvent); + CreateMessageHook(FriendRequestsEvent, onFriendRequestsEvent); + CreateMessageHook(NewConsoleMessageEvent, onNewConsoleMessageEvent); + + return null; +} diff --git a/src/views/friends/FriendsView.scss b/src/views/friends/FriendsView.scss index 1d882087..519d6d1e 100644 --- a/src/views/friends/FriendsView.scss +++ b/src/views/friends/FriendsView.scss @@ -1,4 +1,4 @@ -.nitro-friend-list { +.nitro-friends { width: 250px; } diff --git a/src/views/friends/FriendsView.tsx b/src/views/friends/FriendsView.tsx index 6e2d74eb..8c8e5316 100644 --- a/src/views/friends/FriendsView.tsx +++ b/src/views/friends/FriendsView.tsx @@ -1,54 +1,69 @@ import { MessengerInitComposer, RoomEngineObjectEvent, RoomObjectCategory, RoomObjectUserType } from '@nitrots/nitro-renderer'; import { FC, useCallback, useEffect, useMemo, useReducer, useState } from 'react'; import { createPortal } from 'react-dom'; -import { GetRoomSession, LocalizeText } from '../../api'; -import { FriendEnteredRoomEvent, FriendListEvent } from '../../events'; -import { FriendListContentEvent } from '../../events/friend-list/FriendListContentEvent'; -import { FriendListSendFriendRequestEvent } from '../../events/friend-list/FriendListSendFriendRequestEvent'; +import { GetRoomSession } from '../../api'; +import { FriendEnteredRoomEvent, FriendListContentEvent, FriendsEvent } from '../../events'; +import { FriendsSendFriendRequestEvent } from '../../events/friends/FriendsSendFriendRequestEvent'; import { useRoomEngineEvent } from '../../hooks/events'; import { dispatchUiEvent, useUiEvent } from '../../hooks/events/ui/ui-event'; import { SendMessageHook } from '../../hooks/messages/message-event'; -import { NitroCardAccordionItemView, NitroCardAccordionView, NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../layout'; -import { FriendListContextProvider } from './context/FriendListContext'; -import { FriendListMessageHandler } from './FriendListMessageHandler'; -import { FriendListReducer, initialFriendList } from './reducers/FriendListReducer'; +import { FriendsContextProvider } from './context/FriendsContext'; +import { FriendsMessageHandler } from './FriendsMessageHandler'; +import { FriendsReducer, initialFriends } from './reducers/FriendsReducer'; import { FriendBarView } from './views/friend-bar/FriendBarView'; -import { FriendsListView } from './views/list/FriendsListView'; - -const TABS: string[] = ['friendlist.friends', 'generic.search']; +import { FriendsListView } from './views/friends-list/FriendsListView'; +import { FriendsMessengerView } from './views/messenger/FriendsMessengerView'; export const FriendsView: FC<{}> = props => { - const [ friendListState, dispatchFriendListState ] = useReducer(FriendListReducer, initialFriendList); - const { friends = null, requests = null, settings = null } = friendListState; + const [ friendsState, dispatchFriendsState ] = useReducer(FriendsReducer, initialFriends); + const { friends = [], requests = [], settings = null } = friendsState; - const [ isVisible, setIsVisible ] = useState(false); const [ isReady, setIsReady ] = useState(false); - const [ currentTab, setCurrentTab ] = useState(0); + const [ isListVisible, setIsListVisible ] = useState(false); + const [ isMessengerVisible, setIsMessengerVisible ] = useState(false); - const onFriendListEvent = useCallback((event: FriendListEvent) => + useEffect(() => + { + SendMessageHook(new MessengerInitComposer()); + }, []); + + useEffect(() => + { + if(!settings) return; + + setIsReady(true); + }, [ settings ]); + + const onFriendsEvent = useCallback((event: FriendsEvent) => { switch(event.type) { - case FriendListEvent.SHOW_FRIEND_LIST: - setIsVisible(true); + case FriendsEvent.SHOW_FRIEND_LIST: + setIsListVisible(true); return; - case FriendListEvent.TOGGLE_FRIEND_LIST: - setIsVisible(value => !value); + case FriendsEvent.TOGGLE_FRIEND_LIST: + setIsListVisible(value => !value); return; - case FriendListSendFriendRequestEvent.SEND_FRIEND_REQUEST: - const requestEvent = (event as FriendListSendFriendRequestEvent); + case FriendsEvent.SHOW_FRIEND_MESSENGER: + setIsMessengerVisible(true); return; - case FriendListEvent.REQUEST_FRIEND_LIST: - dispatchUiEvent(new FriendListContentEvent(friendListState.friends)); + case FriendsEvent.TOGGLE_FRIEND_MESSENGER: + setIsMessengerVisible(value => !value); + return; + case FriendsSendFriendRequestEvent.SEND_FRIEND_REQUEST: + const requestEvent = (event as FriendsSendFriendRequestEvent); + return; + case FriendsEvent.REQUEST_FRIEND_LIST: + dispatchUiEvent(new FriendListContentEvent(friendsState.friends)); return; } - }, [friendListState.friends]); + }, [ friendsState.friends ]); - useUiEvent(FriendListEvent.SHOW_FRIEND_LIST, onFriendListEvent); - useUiEvent(FriendListEvent.TOGGLE_FRIEND_LIST, onFriendListEvent); - useUiEvent(FriendListSendFriendRequestEvent.SEND_FRIEND_REQUEST, onFriendListEvent); - useUiEvent(FriendListEvent.REQUEST_FRIEND_LIST, onFriendListEvent); + useUiEvent(FriendsEvent.SHOW_FRIEND_LIST, onFriendsEvent); + useUiEvent(FriendsEvent.TOGGLE_FRIEND_LIST, onFriendsEvent); + useUiEvent(FriendsSendFriendRequestEvent.SEND_FRIEND_REQUEST, onFriendsEvent); + useUiEvent(FriendsEvent.REQUEST_FRIEND_LIST, onFriendsEvent); const onRoomEngineObjectEvent = useCallback((event: RoomEngineObjectEvent) => { @@ -62,7 +77,7 @@ export const FriendsView: FC<{}> = props => if(!userData || (userData.type !== RoomObjectUserType.getTypeNumber(RoomObjectUserType.USER))) return; - const friend = friendListState.friends.find(friend => + const friend = friendsState.friends.find(friend => { return (friend.id === userData.webID); }); @@ -70,67 +85,26 @@ export const FriendsView: FC<{}> = props => if(!friend) return; dispatchUiEvent(new FriendEnteredRoomEvent(userData.roomIndex, RoomObjectCategory.UNIT, userData.webID, userData.name, userData.type)); - }, [ friendListState.friends ]); + }, [ friendsState.friends ]); useRoomEngineEvent(RoomEngineObjectEvent.ADDED, onRoomEngineObjectEvent); - useEffect(() => - { - if(!settings) return; - - setIsReady(true); - }, [ settings ]); - - useEffect(() => - { - SendMessageHook(new MessengerInitComposer()); - }, []); - const onlineFriends = useMemo(() => { - if(!friends) return []; - return friends.filter(f => f.online); }, [ friends ]); const offlineFriends = useMemo(() => { - if(!friends) return []; - return friends.filter(f => !f.online); }, [ friends ]); return ( - - + + { isReady && createPortal(, document.getElementById('toolbar-friend-bar-container')) } - { isVisible && - - setIsVisible(false) } /> - - - { TABS.map((tab, index) => - { - return ( setCurrentTab(index) }> - { LocalizeText(tab) } - ); - }) } - -
- { currentTab === 0 && - - - - - - - { requests.length > 0 && - - } - } -
-
-
} -
+ { isListVisible && setIsListVisible(false) } /> } + { isMessengerVisible && } + ); } diff --git a/src/views/friends/common/MessengerChat.ts b/src/views/friends/common/MessengerChat.ts new file mode 100644 index 00000000..d21982c9 --- /dev/null +++ b/src/views/friends/common/MessengerChat.ts @@ -0,0 +1,34 @@ +import { MessengerChatMessage } from './MessengerChatMessage'; +export class MessengerChat +{ + private _friendId: number; + private _isRead: boolean; + private _messages: MessengerChatMessage[]; + + constructor(friendId: number, isRead: boolean = true) + { + this._friendId = friendId; + this._isRead = isRead; + this._messages = []; + } + + public addMessage(): void + { + this._messages.push(); + } + + public get friendId(): number + { + return this._friendId; + } + + public get isRead(): boolean + { + return this._isRead; + } + + public get messages(): MessengerChatMessage[] + { + return this._messages; + } +} diff --git a/src/views/friends/common/MessengerChatMessage.ts b/src/views/friends/common/MessengerChatMessage.ts new file mode 100644 index 00000000..28b54787 --- /dev/null +++ b/src/views/friends/common/MessengerChatMessage.ts @@ -0,0 +1,13 @@ +export class MessengerChatMessage +{ + private _type: number; + private _senderId: number; + private _message: string; + private _extraData: string; + private _sentAt: number; + + constructor(type: number, senderId: number, message: string, extraData: string, sentAt: number) + { + + } +} diff --git a/src/views/friends/context/FriendListContext.tsx b/src/views/friends/context/FriendListContext.tsx deleted file mode 100644 index 39d23764..00000000 --- a/src/views/friends/context/FriendListContext.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { createContext, FC, useContext } from 'react'; -import { FriendListContextProps, IFriendListContext } from './FriendListContext.type'; - -const FriendListContext = createContext({ - friendListState: null, - dispatchFriendListState: null -}); - -export const FriendListContextProvider: FC = props => -{ - return { props.children } -} - -export const useFriendListContext = () => useContext(FriendListContext); diff --git a/src/views/friends/context/FriendListContext.type.ts b/src/views/friends/context/FriendListContext.type.ts deleted file mode 100644 index 6e74c4cb..00000000 --- a/src/views/friends/context/FriendListContext.type.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Dispatch, ProviderProps } from 'react'; -import { IFriendListAction, IFriendListState } from '../reducers/FriendListReducer'; - -export interface IFriendListContext -{ - friendListState: IFriendListState; - dispatchFriendListState: Dispatch; -} - -export interface FriendListContextProps extends ProviderProps -{ - -} diff --git a/src/views/friends/context/FriendsContext.tsx b/src/views/friends/context/FriendsContext.tsx new file mode 100644 index 00000000..5b551102 --- /dev/null +++ b/src/views/friends/context/FriendsContext.tsx @@ -0,0 +1,14 @@ +import { createContext, FC, useContext } from 'react'; +import { FriendsContextProps, IFriendsContext } from './FriendsContext.type'; + +const FriendsContext = createContext({ + friendsState: null, + dispatchFriendsState: null +}); + +export const FriendsContextProvider: FC = props => +{ + return { props.children } +} + +export const useFriendsContext = () => useContext(FriendsContext); diff --git a/src/views/friends/context/FriendsContext.type.ts b/src/views/friends/context/FriendsContext.type.ts new file mode 100644 index 00000000..a61ef776 --- /dev/null +++ b/src/views/friends/context/FriendsContext.type.ts @@ -0,0 +1,13 @@ +import { Dispatch, ProviderProps } from 'react'; +import { IFriendsAction, IFriendsState } from '../reducers/FriendsReducer'; + +export interface IFriendsContext +{ + friendsState: IFriendsState; + dispatchFriendsState: Dispatch; +} + +export interface FriendsContextProps extends ProviderProps +{ + +} diff --git a/src/views/friends/reducers/FriendListReducer.tsx b/src/views/friends/reducers/FriendsReducer.tsx similarity index 77% rename from src/views/friends/reducers/FriendListReducer.tsx rename to src/views/friends/reducers/FriendsReducer.tsx index 3139d735..1b1ab612 100644 --- a/src/views/friends/reducers/FriendListReducer.tsx +++ b/src/views/friends/reducers/FriendsReducer.tsx @@ -1,5 +1,6 @@ import { FriendListUpdateParser, FriendParser, FriendRequestData } from '@nitrots/nitro-renderer'; import { Reducer } from 'react'; +import { MessengerChat } from '../common/MessengerChat'; import { MessengerFriend } from '../common/MessengerFriend'; import { MessengerRequest } from '../common/MessengerRequest'; import { MessengerSettings } from '../common/MessengerSettings'; @@ -11,14 +12,15 @@ function compareName(a, b) return 0; } -export interface IFriendListState +export interface IFriendsState { settings: MessengerSettings; friends: MessengerFriend[]; requests: MessengerRequest[]; + activeChats: MessengerChat[]; } -export interface IFriendListAction +export interface IFriendsAction { type: string; payload: { @@ -26,34 +28,37 @@ export interface IFriendListAction fragment?: FriendParser[]; update?: FriendListUpdateParser; requests?: FriendRequestData[]; + chats?: MessengerChat[]; } } -export class FriendListActions +export class FriendsActions { - public static RESET_STATE: string = 'FLA_RESET_STATE'; - public static UPDATE_SETTINGS: string = 'FLA_UPDATE_SETTINGS'; - public static PROCESS_FRAGMENT: string = 'FLA_PROCESS_FRAGMENT'; - public static PROCESS_UPDATE: string = 'FLA_PROCESS_UPDATE'; - public static PROCESS_REQUESTS: string = 'FLA_PROCESS_REQUESTS'; + public static RESET_STATE: string = 'FA_RESET_STATE'; + public static UPDATE_SETTINGS: string = 'FA_UPDATE_SETTINGS'; + public static PROCESS_FRAGMENT: string = 'FA_PROCESS_FRAGMENT'; + public static PROCESS_UPDATE: string = 'FA_PROCESS_UPDATE'; + public static PROCESS_REQUESTS: string = 'FA_PROCESS_REQUESTS'; + public static SET_ACTIVE_CHATS: string = 'FA_SET_ACTIVE_CHATS'; } -export const initialFriendList: IFriendListState = { +export const initialFriends: IFriendsState = { settings: null, friends: [], - requests: [] + requests: [], + activeChats: [] } -export const FriendListReducer: Reducer = (state, action) => +export const FriendsReducer: Reducer = (state, action) => { switch(action.type) { - case FriendListActions.UPDATE_SETTINGS: { + case FriendsActions.UPDATE_SETTINGS: { const settings = (action.payload.settings || state.settings || null); return { ...state, settings }; } - case FriendListActions.PROCESS_FRAGMENT: { + case FriendsActions.PROCESS_FRAGMENT: { const fragment = (action.payload.fragment || null); let friends = [ ...state.friends ]; @@ -85,7 +90,7 @@ export const FriendListReducer: Reducer = ( return { ...state, friends }; } - case FriendListActions.PROCESS_UPDATE: { + case FriendsActions.PROCESS_UPDATE: { const update = (action.payload.update || null); let friends = [ ...state.friends ]; @@ -118,7 +123,7 @@ export const FriendListReducer: Reducer = ( return { ...state, friends }; } - case FriendListActions.PROCESS_REQUESTS: { + case FriendsActions.PROCESS_REQUESTS: { const newRequests = (action.payload.requests || null); let requests = [ ...state.requests ]; @@ -133,6 +138,11 @@ export const FriendListReducer: Reducer = ( return { ...state, requests }; } + case FriendsActions.SET_ACTIVE_CHATS: { + const activeChats = (action.payload.chats || []); + + return { ...state, activeChats }; + } default: return state; } diff --git a/src/views/friends/views/friend-bar/FriendBarView.tsx b/src/views/friends/views/friend-bar/FriendBarView.tsx index 3931c4f4..dd7c698b 100644 --- a/src/views/friends/views/friend-bar/FriendBarView.tsx +++ b/src/views/friends/views/friend-bar/FriendBarView.tsx @@ -1,12 +1,12 @@ import { FC, useMemo, useState } from 'react'; -import { useFriendListContext } from '../../context/FriendListContext'; +import { useFriendsContext } from '../../context/FriendsContext'; import { FriendBarItemView } from '../friend-bar-item/FriendBarItemView'; import { FriendBarViewProps } from './FriendBarView.types'; export const FriendBarView: FC = props => { - const { friendListState = null } = useFriendListContext(); - const { friends = null } = friendListState; + const { friendsState = null } = useFriendsContext(); + const { friends = null } = friendsState; const [ indexOffset, setIndexOffset ] = useState(0); const [ maxDisplayCount, setMaxDisplayCount ] = useState(3); diff --git a/src/views/friends/views/friend-item/FriendsListItemView.tsx b/src/views/friends/views/friend-item/FriendsListItemView.tsx index bac0415d..3b398814 100644 --- a/src/views/friends/views/friend-item/FriendsListItemView.tsx +++ b/src/views/friends/views/friend-item/FriendsListItemView.tsx @@ -1,4 +1,5 @@ -import { FollowFriendMessageComposer, SetRelationshipStatusComposer } from '@nitrots/nitro-renderer'; +import { SetRelationshipStatusComposer } from '@nitrots/nitro-renderer'; +import { FollowFriendMessageComposer } from '@nitrots/nitro-renderer/src/nitro/communication/messages/outgoing/friendlist/FollowFriendMessageComposer'; import { FC, useCallback, useState } from 'react'; import { LocalizeText } from '../../../../api'; import { SendMessageHook } from '../../../../hooks'; diff --git a/src/views/friends/views/friends-group-item/FriendsGroupItemView.tsx b/src/views/friends/views/friends-group-item/FriendsGroupItemView.tsx new file mode 100644 index 00000000..bd9203f1 --- /dev/null +++ b/src/views/friends/views/friends-group-item/FriendsGroupItemView.tsx @@ -0,0 +1,63 @@ +import { FollowFriendMessageComposer, SetRelationshipStatusComposer } from '@nitrots/nitro-renderer'; +import { FC, useCallback, useState } from 'react'; +import { LocalizeText } from '../../../../api'; +import { SendMessageHook } from '../../../../hooks'; +import { UserProfileIconView } from '../../../shared/user-profile-icon/UserProfileIconView'; +import { MessengerFriend } from '../../common/MessengerFriend'; +import { FriendsGroupItemViewProps } from './FriendsGroupItemView.types'; + +export const FriendsGroupItemView: FC = props => +{ + const { friend = null } = props; + + const [ isExpanded, setIsExpanded ] = useState(false); + + const followFriend = useCallback(() => + { + if(!friend) return; + + SendMessageHook(new FollowFriendMessageComposer(friend.id)); + }, [ friend ]); + + const getCurrentRelationshipName = useCallback(() => + { + if(!friend) return 'none'; + + switch(friend.relationshipStatus) + { + case MessengerFriend.RELATIONSHIP_HEART: return 'heart'; + case MessengerFriend.RELATIONSHIP_SMILE: return 'smile'; + case MessengerFriend.RELATIONSHIP_BOBBA: return 'bobba'; + default: return 'none'; + } + }, [ friend ]); + + const updateRelationship = useCallback((type: number) => + { + if(type !== friend.relationshipStatus) SendMessageHook(new SetRelationshipStatusComposer(friend.id, type)); + + setIsExpanded(false); + }, [ friend ]); + + if(!friend) return null; + + return ( +
+ +
{ friend.name }
+
+ { !isExpanded && <> + { friend.followingAllowed && } + { friend.online && } + setIsExpanded(true) } title={ LocalizeText('infostand.link.relationship') } /> + } + { isExpanded && <> + updateRelationship(MessengerFriend.RELATIONSHIP_HEART) } /> + updateRelationship(MessengerFriend.RELATIONSHIP_SMILE) } /> + updateRelationship(MessengerFriend.RELATIONSHIP_BOBBA) } /> + updateRelationship(MessengerFriend.RELATIONSHIP_NONE) } /> + } +
+
+ ); +} diff --git a/src/views/friends/views/friends-group-item/FriendsGroupItemView.types.ts b/src/views/friends/views/friends-group-item/FriendsGroupItemView.types.ts new file mode 100644 index 00000000..345532b1 --- /dev/null +++ b/src/views/friends/views/friends-group-item/FriendsGroupItemView.types.ts @@ -0,0 +1,6 @@ +import { MessengerFriend } from '../../common/MessengerFriend'; + +export interface FriendsGroupItemViewProps +{ + friend: MessengerFriend; +} diff --git a/src/views/friends/views/list/FriendsListView.tsx b/src/views/friends/views/friends-group/FriendsGroupView.tsx similarity index 58% rename from src/views/friends/views/list/FriendsListView.tsx rename to src/views/friends/views/friends-group/FriendsGroupView.tsx index 86ed2707..c5eb989b 100644 --- a/src/views/friends/views/list/FriendsListView.tsx +++ b/src/views/friends/views/friends-group/FriendsGroupView.tsx @@ -1,11 +1,11 @@ import React, { FC } from 'react'; import { MessengerFriend } from '../../common/MessengerFriend'; import { MessengerRequest } from '../../common/MessengerRequest'; -import { FriendsListItemView } from '../friend-item/FriendsListItemView'; -import { FriendsRequestItemView } from '../request-item/FriendsRequestItemView'; -import { FriendsListViewProps } from './FriendsListView.types'; +import { FriendsGroupItemView } from '../friends-group-item/FriendsGroupItemView'; +import { FriendsRequestItemView } from '../friends-request-item/FriendsRequestItemView'; +import { FriendsGroupViewProps } from './FriendsGroupView.types'; -export const FriendsListView: FC = props => +export const FriendsGroupView: FC = props => { const { list = null } = props; @@ -15,7 +15,7 @@ export const FriendsListView: FC = props => { list.map((item, index) => { if(item instanceof MessengerFriend) - return + return else if(item instanceof MessengerRequest) return else diff --git a/src/views/friends/views/list/FriendsListView.types.ts b/src/views/friends/views/friends-group/FriendsGroupView.types.ts similarity index 82% rename from src/views/friends/views/list/FriendsListView.types.ts rename to src/views/friends/views/friends-group/FriendsGroupView.types.ts index 8a4c4bc9..48bc5ee6 100644 --- a/src/views/friends/views/list/FriendsListView.types.ts +++ b/src/views/friends/views/friends-group/FriendsGroupView.types.ts @@ -1,7 +1,7 @@ import { MessengerFriend } from '../../common/MessengerFriend'; import { MessengerRequest } from '../../common/MessengerRequest'; -export interface FriendsListViewProps +export interface FriendsGroupViewProps { list: MessengerFriend[] | MessengerRequest[]; } diff --git a/src/views/friends/views/friends-list/FriendsListView.tsx b/src/views/friends/views/friends-list/FriendsListView.tsx new file mode 100644 index 00000000..fd796044 --- /dev/null +++ b/src/views/friends/views/friends-list/FriendsListView.tsx @@ -0,0 +1,43 @@ +import { FC, useState } from 'react'; +import { LocalizeText } from '../../../../api'; +import { NitroCardAccordionItemView, NitroCardAccordionView, NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../../../layout'; +import { FriendsGroupView } from '../friends-group/FriendsGroupView'; +import { FriendsListViewProps } from './FriendsListView.types'; + +const TABS: string[] = ['friendlist.friends', 'generic.search']; + +export const FriendsListView: FC = props => +{ + const { onlineFriends = [], offlineFriends = [], friendRequests = [], onCloseClick = null } = props; + + const [ currentTab, setCurrentTab ] = useState(0); + + return ( + + + + + { TABS.map((tab, index) => + { + return ( setCurrentTab(index) }> + { LocalizeText(tab) } + ); + }) } + +
+ { currentTab === 0 && + + + + + + + { friendRequests.length > 0 && + + } + } +
+
+
+ ); +}; diff --git a/src/views/friends/views/friends-list/FriendsListView.types.ts b/src/views/friends/views/friends-list/FriendsListView.types.ts new file mode 100644 index 00000000..01bfcc84 --- /dev/null +++ b/src/views/friends/views/friends-list/FriendsListView.types.ts @@ -0,0 +1,9 @@ +import { MessengerFriend } from './../../common/MessengerFriend'; +import { MessengerRequest } from './../../common/MessengerRequest'; +export interface FriendsListViewProps +{ + onCloseClick: () => void; + onlineFriends: MessengerFriend[]; + offlineFriends: MessengerFriend[]; + friendRequests: MessengerRequest[]; +} diff --git a/src/views/friends/views/friends-request-item/FriendsRequestItemView.tsx b/src/views/friends/views/friends-request-item/FriendsRequestItemView.tsx new file mode 100644 index 00000000..f25c42f9 --- /dev/null +++ b/src/views/friends/views/friends-request-item/FriendsRequestItemView.tsx @@ -0,0 +1,37 @@ +import { AcceptFriendMessageComposer, DeclineFriendMessageComposer } from '@nitrots/nitro-renderer'; +import { FC, useCallback } from 'react'; +import { SendMessageHook } from '../../../../hooks/messages/message-event'; +import { UserProfileIconView } from '../../../shared/user-profile-icon/UserProfileIconView'; +import { FriendsRequestItemViewProps } from './FriendsRequestItemView.types'; + +export const FriendsRequestItemView: FC = props => +{ + const { request = null } = props; + + const accept = useCallback(() => + { + if(!request) return; + + SendMessageHook(new AcceptFriendMessageComposer(request.id)); + }, [ request ]); + + const decline = useCallback(() => + { + if(!request) return; + + SendMessageHook(new DeclineFriendMessageComposer(false, request.id)); + }, [ request ]); + + if(!request) return null; + + return ( +
+ +
{ request.name }
+
+ + +
+
+ ); +}; diff --git a/src/views/friends/views/friends-request-item/FriendsRequestItemView.types.ts b/src/views/friends/views/friends-request-item/FriendsRequestItemView.types.ts new file mode 100644 index 00000000..4f5c38d5 --- /dev/null +++ b/src/views/friends/views/friends-request-item/FriendsRequestItemView.types.ts @@ -0,0 +1,6 @@ +import { MessengerRequest } from '../../common/MessengerRequest'; + +export interface FriendsRequestItemViewProps +{ + request: MessengerRequest; +} diff --git a/src/views/friends/views/messenger/FriendsMessengerView.tsx b/src/views/friends/views/messenger/FriendsMessengerView.tsx new file mode 100644 index 00000000..38a3c07b --- /dev/null +++ b/src/views/friends/views/messenger/FriendsMessengerView.tsx @@ -0,0 +1,13 @@ +import { FC } from 'react'; +import { LocalizeText } from '../../../../api'; +import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout'; + +export const FriendsMessengerView: FC<{}> = props => +{ + return ( + {} } /> + + + + ); +}; diff --git a/src/views/friends/views/request-item/FriendsRequestItemView.types.ts b/src/views/friends/views/request-item/FriendsRequestItemView.types.ts index 4f5c38d5..bc01f938 100644 --- a/src/views/friends/views/request-item/FriendsRequestItemView.types.ts +++ b/src/views/friends/views/request-item/FriendsRequestItemView.types.ts @@ -1,5 +1,4 @@ -import { MessengerRequest } from '../../common/MessengerRequest'; - +import { MessengerRequest } from './../../common/MessengerRequest'; export interface FriendsRequestItemViewProps { request: MessengerRequest; diff --git a/src/views/navigator/views/room-settings/NavigatorRoomSettingsView.tsx b/src/views/navigator/views/room-settings/NavigatorRoomSettingsView.tsx index 385a0a4f..8fe49ce2 100644 --- a/src/views/navigator/views/room-settings/NavigatorRoomSettingsView.tsx +++ b/src/views/navigator/views/room-settings/NavigatorRoomSettingsView.tsx @@ -1,8 +1,8 @@ import { RoomBannedUsersComposer, RoomBannedUsersEvent, RoomSettingsEvent, RoomUsersWithRightsComposer, RoomUsersWithRightsEvent, SaveRoomSettingsComposer } from '@nitrots/nitro-renderer'; import { FC, useCallback, useEffect, useState } from 'react'; import { LocalizeText } from '../../../../api'; -import { FriendListEvent } from '../../../../events'; -import { FriendListContentEvent } from '../../../../events/friend-list/FriendListContentEvent'; +import { FriendsEvent } from '../../../../events'; +import { FriendListContentEvent } from '../../../../events/friends/FriendListContentEvent'; import { dispatchUiEvent, useUiEvent } from '../../../../hooks'; import { CreateMessageHook, SendMessageHook } from '../../../../hooks/messages'; import { NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../../../layout'; @@ -87,7 +87,7 @@ export const NavigatorRoomSettingsView: FC<{}> = props => useEffect(() => { - if(roomSettingsData) dispatchUiEvent(new FriendListEvent(FriendListEvent.REQUEST_FRIEND_LIST)); + if(roomSettingsData) dispatchUiEvent(new FriendsEvent(FriendsEvent.REQUEST_FRIEND_LIST)); }, [roomSettingsData]) const save = useCallback((data: RoomSettingsData) => diff --git a/src/views/toolbar/ToolbarView.tsx b/src/views/toolbar/ToolbarView.tsx index 74b22062..3ab96937 100644 --- a/src/views/toolbar/ToolbarView.tsx +++ b/src/views/toolbar/ToolbarView.tsx @@ -1,7 +1,7 @@ import { Dispose, DropBounce, EaseOut, FigureUpdateEvent, JumpBy, Motions, NitroToolbarAnimateIconEvent, Queue, UserInfoDataParser, UserInfoEvent, UserProfileComposer, Wait } from '@nitrots/nitro-renderer'; import { FC, useCallback, useState } from 'react'; import { GetRoomSession, GetRoomSessionManager, GetSessionDataManager, GoToDesktop } from '../../api'; -import { AvatarEditorEvent, CatalogEvent, FriendListEvent, InventoryEvent, NavigatorEvent, RoomWidgetCameraEvent } from '../../events'; +import { AvatarEditorEvent, CatalogEvent, FriendsEvent, InventoryEvent, NavigatorEvent, RoomWidgetCameraEvent } from '../../events'; import { AchievementsUIEvent } from '../../events/achievements'; import { UnseenItemTrackerUpdateEvent } from '../../events/inventory/UnseenItemTrackerUpdateEvent'; import { ModToolsEvent } from '../../events/mod-tools/ModToolsEvent'; @@ -107,7 +107,7 @@ export const ToolbarView: FC = props => dispatchUiEvent(new CatalogEvent(CatalogEvent.TOGGLE_CATALOG)); return; case ToolbarViewItems.FRIEND_LIST_ITEM: - dispatchUiEvent(new CatalogEvent(FriendListEvent.TOGGLE_FRIEND_LIST)); + dispatchUiEvent(new CatalogEvent(FriendsEvent.TOGGLE_FRIEND_LIST)); return; case ToolbarViewItems.CAMERA_ITEM: dispatchUiEvent(new RoomWidgetCameraEvent(RoomWidgetCameraEvent.TOGGLE_CAMERA)); From 34ad458f87b4651dc0329f9c0cb9e9ac069d2f59 Mon Sep 17 00:00:00 2001 From: Bill Date: Fri, 17 Sep 2021 02:39:58 -0400 Subject: [PATCH 02/31] Rename CatalogGiftView --- src/views/catalog/CatalogView.tsx | 4 ++-- src/views/catalog/views/CatalogViews.scss | 2 +- .../gift/{CatalogPageGiftView.scss => CatalogGiftView.scss} | 0 .../gift/{CatalogPageGiftView.tsx => CatalogGiftView.tsx} | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename src/views/catalog/views/gift/{CatalogPageGiftView.scss => CatalogGiftView.scss} (100%) rename src/views/catalog/views/gift/{CatalogPageGiftView.tsx => CatalogGiftView.tsx} (99%) diff --git a/src/views/catalog/CatalogView.tsx b/src/views/catalog/CatalogView.tsx index d49b167e..d69eb842 100644 --- a/src/views/catalog/CatalogView.tsx +++ b/src/views/catalog/CatalogView.tsx @@ -10,7 +10,7 @@ import { CatalogMode, CatalogViewProps } from './CatalogView.types'; import { BuildCatalogPageTree } from './common/CatalogUtilities'; import { CatalogContextProvider } from './context/CatalogContext'; import { CatalogReducer, initialCatalog } from './reducers/CatalogReducer'; -import { CatalogPageGiftView } from './views/gift/CatalogPageGiftView'; +import { CatalogGiftView } from './views/gift/CatalogGiftView'; import { ACTIVE_PAGES, CatalogNavigationView } from './views/navigation/CatalogNavigationView'; import { CatalogPageView } from './views/page/CatalogPageView'; @@ -214,7 +214,7 @@ export const CatalogView: FC = props => } - + ); } diff --git a/src/views/catalog/views/CatalogViews.scss b/src/views/catalog/views/CatalogViews.scss index d5d8464b..0a5f6295 100644 --- a/src/views/catalog/views/CatalogViews.scss +++ b/src/views/catalog/views/CatalogViews.scss @@ -2,4 +2,4 @@ @import './navigation/CatalogNavigationView'; @import './page/CatalogPageView'; @import './search/CatalogSearchView'; -@import './gift/CatalogPageGiftView'; +@import './gift/CatalogGiftView'; diff --git a/src/views/catalog/views/gift/CatalogPageGiftView.scss b/src/views/catalog/views/gift/CatalogGiftView.scss similarity index 100% rename from src/views/catalog/views/gift/CatalogPageGiftView.scss rename to src/views/catalog/views/gift/CatalogGiftView.scss diff --git a/src/views/catalog/views/gift/CatalogPageGiftView.tsx b/src/views/catalog/views/gift/CatalogGiftView.tsx similarity index 99% rename from src/views/catalog/views/gift/CatalogPageGiftView.tsx rename to src/views/catalog/views/gift/CatalogGiftView.tsx index 1d7a1bf1..d466d5b6 100644 --- a/src/views/catalog/views/gift/CatalogPageGiftView.tsx +++ b/src/views/catalog/views/gift/CatalogGiftView.tsx @@ -10,7 +10,7 @@ import { CurrencyIcon } from '../../../shared/currency-icon/CurrencyIcon'; import { FurniImageView } from '../../../shared/furni-image/FurniImageView'; import { useCatalogContext } from '../../context/CatalogContext'; -export const CatalogPageGiftView: FC<{}> = props => +export const CatalogGiftView: FC<{}> = props => { const { catalogState = null } = useCatalogContext(); const { giftConfiguration = null } = catalogState; From 7ee1a6898780d6e09767a0e87adacf6cffdb4928 Mon Sep 17 00:00:00 2001 From: Bill Date: Fri, 17 Sep 2021 02:40:11 -0400 Subject: [PATCH 03/31] Fix dimmer again --- .../furniture/dimmer/FurnitureDimmerView.tsx | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/views/room/widgets/furniture/dimmer/FurnitureDimmerView.tsx b/src/views/room/widgets/furniture/dimmer/FurnitureDimmerView.tsx index f65f2664..d1f88b64 100644 --- a/src/views/room/widgets/furniture/dimmer/FurnitureDimmerView.tsx +++ b/src/views/room/widgets/furniture/dimmer/FurnitureDimmerView.tsx @@ -55,16 +55,8 @@ export const FurnitureDimmerView: FC<{}> = props => BatchUpdates(() => { - let prevDimmerState = 0; - - setDimmerState(prevValue => - { - setLastDimmerState(prevValue); - - return widgetEvent.state; - }); - - setLastDimmerState(prevDimmerState); + setLastDimmerState(dimmerState); + setDimmerState(widgetEvent.state); setSelectedPresetId(widgetEvent.presetId); setEffectId(widgetEvent.effectId); setSelectedEffectId(widgetEvent.effectId); @@ -73,10 +65,11 @@ export const FurnitureDimmerView: FC<{}> = props => setBrightness(widgetEvent.brightness); setSelectedBrightness(widgetEvent.brightness); }); + return; } } - }, []); + }, [ dimmerState ]); CreateEventDispatcherHook(RoomWidgetUpdateDimmerEvent.PRESETS, eventDispatcher, onNitroEvent); CreateEventDispatcherHook(RoomWidgetUpdateDimmerEvent.HIDE, eventDispatcher, onNitroEvent); @@ -144,6 +137,8 @@ export const FurnitureDimmerView: FC<{}> = props => { if((dimmerState === 0) && (lastDimmerState === 0)) return; + console.log('ye') + widgetHandler.processWidgetMessage(new RoomWidgetDimmerPreviewMessage(selectedColor, selectedBrightness, (selectedEffectId === 2))); }, [ widgetHandler, dimmerState, lastDimmerState, selectedColor, selectedBrightness, selectedEffectId ]); From 4a55aff19cafd0030bdeaa83810ecb9093eb6d3d Mon Sep 17 00:00:00 2001 From: Bill Date: Fri, 17 Sep 2021 02:40:37 -0400 Subject: [PATCH 04/31] Remove console log --- .../page/layout/badge-display/CatalogLayoutBadgeDisplayView.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/views/catalog/views/page/layout/badge-display/CatalogLayoutBadgeDisplayView.tsx b/src/views/catalog/views/page/layout/badge-display/CatalogLayoutBadgeDisplayView.tsx index b36ce01b..4cb90755 100644 --- a/src/views/catalog/views/page/layout/badge-display/CatalogLayoutBadgeDisplayView.tsx +++ b/src/views/catalog/views/page/layout/badge-display/CatalogLayoutBadgeDisplayView.tsx @@ -63,8 +63,6 @@ export const CatalogLayoutBadgeDisplayView: FC Date: Fri, 17 Sep 2021 02:40:54 -0400 Subject: [PATCH 05/31] Fix chat input width resetting --- src/views/room/widgets/chat-input/ChatInputView.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/views/room/widgets/chat-input/ChatInputView.tsx b/src/views/room/widgets/chat-input/ChatInputView.tsx index c1ac2a3b..534dd93c 100644 --- a/src/views/room/widgets/chat-input/ChatInputView.tsx +++ b/src/views/room/widgets/chat-input/ChatInputView.tsx @@ -260,11 +260,18 @@ export const ChatInputView: FC<{}> = props => } }, [ onKeyDownEvent ]); + useEffect(() => + { + if(!inputRef.current) return; + + inputRef.current.parentElement.dataset.value = chatValue; + }, [ chatValue ]); + return ( createPortal(
- { event.target.parentElement.dataset.value = event.target.value; updateChatInput(event.target.value) } } onMouseDown={ event => setInputFocus() } /> + updateChatInput(event.target.value) } onMouseDown={ event => setInputFocus() } />
, document.getElementById('toolbar-chat-input-container')) From b5850c1995494ce5872a1ee07d027ccd02deb9a3 Mon Sep 17 00:00:00 2001 From: MyNameIsBatman Date: Fri, 17 Sep 2021 08:15:53 -0300 Subject: [PATCH 06/31] Updates --- src/api/friends/OpenMessengerChat.ts | 7 ++ src/api/friends/index.ts | 1 + src/api/index.ts | 1 + src/views/friends/FriendsView.tsx | 9 +-- src/views/friends/common/MessengerChat.ts | 4 +- .../friends/common/MessengerChatMessage.ts | 35 ++++++++- .../views/friend-item/FriendsListItemView.tsx | 13 +++- .../views/messenger/FriendsMessengerView.tsx | 75 ++++++++++++++++++- 8 files changed, 127 insertions(+), 18 deletions(-) create mode 100644 src/api/friends/OpenMessengerChat.ts create mode 100644 src/api/friends/index.ts diff --git a/src/api/friends/OpenMessengerChat.ts b/src/api/friends/OpenMessengerChat.ts new file mode 100644 index 00000000..e5c685cd --- /dev/null +++ b/src/api/friends/OpenMessengerChat.ts @@ -0,0 +1,7 @@ +import { CreateLinkEvent } from '..'; + +export function OpenMessengerChat(friendId: number): void +{ + console.log(`friends/messenger/${friendId}`); + CreateLinkEvent(`friends/messenger/${friendId}`); +} diff --git a/src/api/friends/index.ts b/src/api/friends/index.ts new file mode 100644 index 00000000..ffb458ee --- /dev/null +++ b/src/api/friends/index.ts @@ -0,0 +1 @@ +export * from './OpenMessengerChat'; diff --git a/src/api/index.ts b/src/api/index.ts index 773325c3..0b87703a 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -1,4 +1,5 @@ export * from './core'; +export * from './friends'; export * from './groups'; export * from './navigator'; export * from './nitro'; diff --git a/src/views/friends/FriendsView.tsx b/src/views/friends/FriendsView.tsx index 8c8e5316..3e593a88 100644 --- a/src/views/friends/FriendsView.tsx +++ b/src/views/friends/FriendsView.tsx @@ -21,7 +21,6 @@ export const FriendsView: FC<{}> = props => const [ isReady, setIsReady ] = useState(false); const [ isListVisible, setIsListVisible ] = useState(false); - const [ isMessengerVisible, setIsMessengerVisible ] = useState(false); useEffect(() => { @@ -45,12 +44,6 @@ export const FriendsView: FC<{}> = props => case FriendsEvent.TOGGLE_FRIEND_LIST: setIsListVisible(value => !value); return; - case FriendsEvent.SHOW_FRIEND_MESSENGER: - setIsMessengerVisible(true); - return; - case FriendsEvent.TOGGLE_FRIEND_MESSENGER: - setIsMessengerVisible(value => !value); - return; case FriendsSendFriendRequestEvent.SEND_FRIEND_REQUEST: const requestEvent = (event as FriendsSendFriendRequestEvent); return; @@ -104,7 +97,7 @@ export const FriendsView: FC<{}> = props => { isReady && createPortal(, document.getElementById('toolbar-friend-bar-container')) } { isListVisible && setIsListVisible(false) } /> } - { isMessengerVisible && } + ); } diff --git a/src/views/friends/common/MessengerChat.ts b/src/views/friends/common/MessengerChat.ts index d21982c9..963a941b 100644 --- a/src/views/friends/common/MessengerChat.ts +++ b/src/views/friends/common/MessengerChat.ts @@ -12,9 +12,9 @@ export class MessengerChat this._messages = []; } - public addMessage(): void + public addMessage(type: number, senderId: number, message: string, sentAt: number, extraData?: string): void { - this._messages.push(); + this._messages.push(new MessengerChatMessage(type, senderId, message, sentAt, extraData)); } public get friendId(): number diff --git a/src/views/friends/common/MessengerChatMessage.ts b/src/views/friends/common/MessengerChatMessage.ts index 28b54787..0b410216 100644 --- a/src/views/friends/common/MessengerChatMessage.ts +++ b/src/views/friends/common/MessengerChatMessage.ts @@ -3,11 +3,40 @@ export class MessengerChatMessage private _type: number; private _senderId: number; private _message: string; - private _extraData: string; private _sentAt: number; + private _extraData: string; - constructor(type: number, senderId: number, message: string, extraData: string, sentAt: number) + constructor(type: number, senderId: number, message: string, sentAt: number, extraData?: string) { - + this._type = type; + this._senderId = senderId; + this._message = message; + this._sentAt = sentAt; + this._extraData = extraData; + } + + public get type(): number + { + return this._type; + } + + public get senderId(): number + { + return this._senderId; + } + + public get message(): string + { + return this._message; + } + + public get sentAt(): number + { + return this._sentAt; + } + + public get extraData(): string + { + return this._extraData; } } diff --git a/src/views/friends/views/friend-item/FriendsListItemView.tsx b/src/views/friends/views/friend-item/FriendsListItemView.tsx index 3b398814..2edafd90 100644 --- a/src/views/friends/views/friend-item/FriendsListItemView.tsx +++ b/src/views/friends/views/friend-item/FriendsListItemView.tsx @@ -1,7 +1,7 @@ import { SetRelationshipStatusComposer } from '@nitrots/nitro-renderer'; import { FollowFriendMessageComposer } from '@nitrots/nitro-renderer/src/nitro/communication/messages/outgoing/friendlist/FollowFriendMessageComposer'; import { FC, useCallback, useState } from 'react'; -import { LocalizeText } from '../../../../api'; +import { LocalizeText, OpenMessengerChat } from '../../../../api'; import { SendMessageHook } from '../../../../hooks'; import { UserProfileIconView } from '../../../shared/user-profile-icon/UserProfileIconView'; import { MessengerFriend } from '../../common/MessengerFriend'; @@ -20,6 +20,13 @@ export const FriendsListItemView: FC = props => SendMessageHook(new FollowFriendMessageComposer(friend.id)); }, [ friend ]); + const openMessengerChat = useCallback(() => + { + if(!friend) return; + + OpenMessengerChat(friend.id); + }, [ friend ]); + const getCurrentRelationshipName = useCallback(() => { if(!friend) return 'none'; @@ -48,8 +55,8 @@ export const FriendsListItemView: FC = props =>
{ friend.name }
{ !isExpanded && <> - { friend.followingAllowed && } - { friend.online && } + { friend.followingAllowed && } + { friend.online && } setIsExpanded(true) } title={ LocalizeText('infostand.link.relationship') } /> } { isExpanded && <> diff --git a/src/views/friends/views/messenger/FriendsMessengerView.tsx b/src/views/friends/views/messenger/FriendsMessengerView.tsx index 38a3c07b..b64ed9d2 100644 --- a/src/views/friends/views/messenger/FriendsMessengerView.tsx +++ b/src/views/friends/views/messenger/FriendsMessengerView.tsx @@ -1,9 +1,80 @@ -import { FC } from 'react'; -import { LocalizeText } from '../../../../api'; +import { ILinkEventTracker, NitroEvent } from '@nitrots/nitro-renderer'; +import { FC, useCallback, useEffect, useState } from 'react'; +import { AddEventLinkTracker, LocalizeText, RemoveLinkEventTracker } from '../../../../api'; +import { FriendsEvent } from '../../../../events/friends/FriendsEvent'; +import { useUiEvent } from '../../../../hooks'; import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout'; +import { MessengerChat } from '../../common/MessengerChat'; +import { useFriendsContext } from '../../context/FriendsContext'; +import { FriendsActions } from '../../reducers/FriendsReducer'; export const FriendsMessengerView: FC<{}> = props => { + const { friendsState = null, dispatchFriendsState = null } = useFriendsContext(); + const { activeChats = [] } = friendsState; + + const [ isVisible, setIsVisible ] = useState(false); + const [ activeChatIndex, setActiveChatIndex ] = useState(0); + + const onNitroEvent = useCallback((event: NitroEvent) => + { + switch(event.type) + { + case FriendsEvent.SHOW_FRIEND_MESSENGER: + setIsVisible(true); + return; + case FriendsEvent.TOGGLE_FRIEND_MESSENGER: + setIsVisible(value => !value); + return; + } + }, []); + + useUiEvent(FriendsEvent.SHOW_FRIEND_MESSENGER, onNitroEvent); + useUiEvent(FriendsEvent.TOGGLE_FRIEND_MESSENGER, onNitroEvent); + + const linkReceived = useCallback((url: string) => + { + const parts = url.split('/'); + console.log(parts); + if(parts.length < 3) return; + + const friendId = parseInt(parts[2]); + console.log(friendId); + let existingChatIndex = activeChats.findIndex(c => c.friendId === friendId); + + if(existingChatIndex === -1) + { + const clonedActiveChats = Array.from(activeChats); + clonedActiveChats.push(new MessengerChat(friendId, true)); + + dispatchFriendsState({ + type: FriendsActions.SET_ACTIVE_CHATS, + payload: { + chats: clonedActiveChats + } + }); + + existingChatIndex = clonedActiveChats.length - 1; + } + + setActiveChatIndex(existingChatIndex); + setIsVisible(true); + }, [ activeChats, dispatchFriendsState ]); + + useEffect(() => + { + const linkTracker: ILinkEventTracker = { + linkReceived, + eventUrlPrefix: 'friends/messenger/' + }; + + AddEventLinkTracker(linkTracker); + + return () => RemoveLinkEventTracker(linkTracker); + }, [ linkReceived ]); + + if(!isVisible) return null; + return ( {} } /> From c7a5170c2208dc439c88868e09674ac1249943ed Mon Sep 17 00:00:00 2001 From: Layne Date: Sat, 18 Sep 2021 01:27:31 -0400 Subject: [PATCH 07/31] new header ig --- .../card/content/NitroCardContentView.scss | 6 ----- .../card/header/NitroCardHeaderView.scss | 25 ++++++++++++------- .../card/header/NitroCardHeaderView.tsx | 4 +-- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/layout/card/content/NitroCardContentView.scss b/src/layout/card/content/NitroCardContentView.scss index c681fd34..9ffd6fe9 100644 --- a/src/layout/card/content/NitroCardContentView.scss +++ b/src/layout/card/content/NitroCardContentView.scss @@ -2,15 +2,9 @@ padding-top: $container-padding-x; padding-bottom: $container-padding-x; overflow: auto; - - &.simple { - padding-left: ($container-padding-x + 25px); - padding-right: ($container-padding-x + 25px); - } } @include media-breakpoint-down(lg) { - .content-area { height: 100% !important; min-height: auto !important; diff --git a/src/layout/card/header/NitroCardHeaderView.scss b/src/layout/card/header/NitroCardHeaderView.scss index b3142be8..b81b748e 100644 --- a/src/layout/card/header/NitroCardHeaderView.scss +++ b/src/layout/card/header/NitroCardHeaderView.scss @@ -2,7 +2,6 @@ min-height: 33px; max-height: 33px; white-space: nowrap; - overflow: hidden; .header-text { margin: 0 35px; @@ -10,19 +9,22 @@ &.simple-header { min-height: 28px; - max-height: 28px; + + .header-close { + font-size: 12px; + } } .bg-tertiary-split { position: relative; - border: 2px solid darken($quaternary, 4); - box-shadow: 0 0 0 2px $white; + border-bottom: 2px solid darken($quaternary, 5); + box-shadow: 0 2px white; width: 100%; - margin: 0 25px; + margin: 0; &:before { position: absolute; - content: ' '; + content: " "; top: 0; left: 0; width: 100%; @@ -36,15 +38,20 @@ border-radius: $border-radius; box-shadow: 0 0 0 1.5px $white; border: 2px solid #921911; - background: repeating-linear-gradient(rgba(245,80,65,1), rgba(245,80,65,1) 50%, rgba(194,48,39,1) 50%, rgba(194,48,39,1) 100%); + background: repeating-linear-gradient( + rgba(245, 80, 65, 1), + rgba(245, 80, 65, 1) 50%, + rgba(194, 48, 39, 1) 50%, + rgba(194, 48, 39, 1) 100% + ); cursor: pointer; line-height: 1; padding: 1px 3px; - + &:hover { filter: brightness(1.2); } - + &:active { filter: brightness(0.8); } diff --git a/src/layout/card/header/NitroCardHeaderView.tsx b/src/layout/card/header/NitroCardHeaderView.tsx index 3be15c6d..b964fe46 100644 --- a/src/layout/card/header/NitroCardHeaderView.tsx +++ b/src/layout/card/header/NitroCardHeaderView.tsx @@ -18,8 +18,8 @@ export const NitroCardHeaderView: FC = props => return (
-
-
{ headerText }
+
+
{ headerText }
From 7a6fe87aedd54715462945fdccf16b66a41e2bce Mon Sep 17 00:00:00 2001 From: MyNameIsBatman Date: Sat, 18 Sep 2021 03:04:50 -0300 Subject: [PATCH 08/31] Messenger Chat --- src/layout/card/NitroCardView.scss | 4 + src/layout/card/NitroCardView.tsx | 2 +- src/views/friends/FriendsMessageHandler.tsx | 20 +-- src/views/friends/FriendsView.scss | 1 + src/views/friends/FriendsView.tsx | 2 +- src/views/friends/common/MessengerChat.ts | 21 ++- .../friends/common/MessengerChatMessage.ts | 4 + .../common/MessengerChatMessageGroup.ts | 28 ++++ src/views/friends/reducers/FriendsReducer.tsx | 22 +++ .../friend-bar-item/FriendBarItemView.tsx | 11 +- .../views/friend-bar/FriendBarView.tsx | 10 +- .../views/friend-bar/FriendBarView.types.ts | 3 +- .../views/friend-item/FriendsListItemView.tsx | 71 --------- .../friend-item/FriendsListItemView.types.ts | 6 - .../FriendsGroupItemView.tsx | 11 +- .../views/messenger/FriendsMessengerView.scss | 71 +++++++++ .../views/messenger/FriendsMessengerView.tsx | 141 ++++++++++++++++-- 17 files changed, 309 insertions(+), 119 deletions(-) create mode 100644 src/views/friends/common/MessengerChatMessageGroup.ts delete mode 100644 src/views/friends/views/friend-item/FriendsListItemView.tsx delete mode 100644 src/views/friends/views/friend-item/FriendsListItemView.types.ts create mode 100644 src/views/friends/views/messenger/FriendsMessengerView.scss diff --git a/src/layout/card/NitroCardView.scss b/src/layout/card/NitroCardView.scss index 44285071..cd7bfebf 100644 --- a/src/layout/card/NitroCardView.scss +++ b/src/layout/card/NitroCardView.scss @@ -19,6 +19,10 @@ $nitro-card-tabs-height: 33px; height: 100%; pointer-events: none; + .theme-primary { + border: $border-width solid $border-color; + } + @include media-breakpoint-down(lg) { .draggable-window { diff --git a/src/layout/card/NitroCardView.tsx b/src/layout/card/NitroCardView.tsx index aaf4178a..f44ee67f 100644 --- a/src/layout/card/NitroCardView.tsx +++ b/src/layout/card/NitroCardView.tsx @@ -11,7 +11,7 @@ export const NitroCardView: FC = props =>
-
+
{ children }
diff --git a/src/views/friends/FriendsMessageHandler.tsx b/src/views/friends/FriendsMessageHandler.tsx index 579230a5..e1e055f2 100644 --- a/src/views/friends/FriendsMessageHandler.tsx +++ b/src/views/friends/FriendsMessageHandler.tsx @@ -1,6 +1,8 @@ import { FriendListFragmentEvent, FriendListUpdateEvent, FriendRequestsEvent, GetFriendRequestsComposer, MessengerInitEvent, NewConsoleMessageEvent } from '@nitrots/nitro-renderer'; import { FC, useCallback } from 'react'; +import { GetSessionDataManager } from '../../api'; import { CreateMessageHook, SendMessageHook } from '../../hooks/messages/message-event'; +import { MessengerChatMessage } from './common/MessengerChatMessage'; import { MessengerSettings } from './common/MessengerSettings'; import { useFriendsContext } from './context/FriendsContext'; import { FriendsActions } from './reducers/FriendsReducer'; @@ -68,17 +70,17 @@ export const FriendsMessageHandler: FC<{}> = props => { const parser = event.getParser(); - const activeChat = activeChats.find(c => c.friendId === parser.senderId); + let userId = parser.senderId; - if(activeChat) - { + if(userId === GetSessionDataManager().userId) userId = 0; - } - else - { - - } - }, [ friendsState, dispatchFriendsState ]); + dispatchFriendsState({ + type: FriendsActions.ADD_CHAT_MESSAGE, + payload: { + chatMessage: new MessengerChatMessage(MessengerChatMessage.MESSAGE, userId, parser.messageText, parser.secondsSinceSent, parser.extraData) + } + }); + }, [ dispatchFriendsState ]); CreateMessageHook(MessengerInitEvent, onMessengerInitEvent); CreateMessageHook(FriendListFragmentEvent, onFriendsFragmentEvent); diff --git a/src/views/friends/FriendsView.scss b/src/views/friends/FriendsView.scss index 519d6d1e..3d55929f 100644 --- a/src/views/friends/FriendsView.scss +++ b/src/views/friends/FriendsView.scss @@ -3,3 +3,4 @@ } @import './views/friend-bar/FriendBarView'; +@import './views/messenger/FriendsMessengerView'; diff --git a/src/views/friends/FriendsView.tsx b/src/views/friends/FriendsView.tsx index 3e593a88..0c9415f7 100644 --- a/src/views/friends/FriendsView.tsx +++ b/src/views/friends/FriendsView.tsx @@ -95,7 +95,7 @@ export const FriendsView: FC<{}> = props => return ( - { isReady && createPortal(, document.getElementById('toolbar-friend-bar-container')) } + { isReady && createPortal(, document.getElementById('toolbar-friend-bar-container')) } { isListVisible && setIsListVisible(false) } /> } diff --git a/src/views/friends/common/MessengerChat.ts b/src/views/friends/common/MessengerChat.ts index 963a941b..2369a7c9 100644 --- a/src/views/friends/common/MessengerChat.ts +++ b/src/views/friends/common/MessengerChat.ts @@ -1,20 +1,24 @@ import { MessengerChatMessage } from './MessengerChatMessage'; +import { MessengerChatMessageGroup } from './MessengerChatMessageGroup'; export class MessengerChat { private _friendId: number; private _isRead: boolean; - private _messages: MessengerChatMessage[]; + private _messageGroups: MessengerChatMessageGroup[]; constructor(friendId: number, isRead: boolean = true) { this._friendId = friendId; this._isRead = isRead; - this._messages = []; + this._messageGroups = []; } - public addMessage(type: number, senderId: number, message: string, sentAt: number, extraData?: string): void + public addMessage(message: MessengerChatMessage): void { - this._messages.push(new MessengerChatMessage(type, senderId, message, sentAt, extraData)); + if(!this.lastMessageGroup || this.lastMessageGroup.userId !== message.senderId) this._messageGroups.push(new MessengerChatMessageGroup(message.senderId)); + + this.lastMessageGroup.addMessage(message); + this._isRead = false; } public get friendId(): number @@ -27,8 +31,13 @@ export class MessengerChat return this._isRead; } - public get messages(): MessengerChatMessage[] + public get messageGroups(): MessengerChatMessageGroup[] { - return this._messages; + return this._messageGroups; + } + + public get lastMessageGroup(): MessengerChatMessageGroup + { + return this._messageGroups[this._messageGroups.length - 1]; } } diff --git a/src/views/friends/common/MessengerChatMessage.ts b/src/views/friends/common/MessengerChatMessage.ts index 0b410216..5ded0a7d 100644 --- a/src/views/friends/common/MessengerChatMessage.ts +++ b/src/views/friends/common/MessengerChatMessage.ts @@ -1,5 +1,9 @@ export class MessengerChatMessage { + public static MESSAGE: number = 0; + public static ROOM_INVITE: number = 1; + public static SYSTEM_NOTIFICATION: number = 2; + private _type: number; private _senderId: number; private _message: string; diff --git a/src/views/friends/common/MessengerChatMessageGroup.ts b/src/views/friends/common/MessengerChatMessageGroup.ts new file mode 100644 index 00000000..0bb27fe3 --- /dev/null +++ b/src/views/friends/common/MessengerChatMessageGroup.ts @@ -0,0 +1,28 @@ +import { MessengerChatMessage } from './MessengerChatMessage'; + +export class MessengerChatMessageGroup +{ + private _userId: number; + private _messages: MessengerChatMessage[]; + + constructor(userId: number) + { + this._userId = userId; + this._messages = []; + } + + public addMessage(message: MessengerChatMessage): void + { + this._messages.push(message); + } + + public get userId(): number + { + return this._userId; + } + + public get messages(): MessengerChatMessage[] + { + return this._messages; + } +} diff --git a/src/views/friends/reducers/FriendsReducer.tsx b/src/views/friends/reducers/FriendsReducer.tsx index 1b1ab612..f66ce6fd 100644 --- a/src/views/friends/reducers/FriendsReducer.tsx +++ b/src/views/friends/reducers/FriendsReducer.tsx @@ -1,6 +1,7 @@ import { FriendListUpdateParser, FriendParser, FriendRequestData } from '@nitrots/nitro-renderer'; import { Reducer } from 'react'; import { MessengerChat } from '../common/MessengerChat'; +import { MessengerChatMessage } from '../common/MessengerChatMessage'; import { MessengerFriend } from '../common/MessengerFriend'; import { MessengerRequest } from '../common/MessengerRequest'; import { MessengerSettings } from '../common/MessengerSettings'; @@ -29,6 +30,8 @@ export interface IFriendsAction update?: FriendListUpdateParser; requests?: FriendRequestData[]; chats?: MessengerChat[]; + chatMessage?: MessengerChatMessage; + numberValue?: number; } } @@ -40,6 +43,7 @@ export class FriendsActions public static PROCESS_UPDATE: string = 'FA_PROCESS_UPDATE'; public static PROCESS_REQUESTS: string = 'FA_PROCESS_REQUESTS'; public static SET_ACTIVE_CHATS: string = 'FA_SET_ACTIVE_CHATS'; + public static ADD_CHAT_MESSAGE: string = 'FA_ADD_CHAT_MESSAGE'; } export const initialFriends: IFriendsState = { @@ -143,6 +147,24 @@ export const FriendsReducer: Reducer = (state, ac return { ...state, activeChats }; } + case FriendsActions.ADD_CHAT_MESSAGE: { + const message = action.payload.chatMessage; + const toFriendId = action.payload.numberValue; + + const activeChats = Array.from(state.activeChats); + + let activeChatIndex = activeChats.findIndex(c => c.friendId === toFriendId ? toFriendId : message.senderId); + + if(activeChatIndex === -1) + { + activeChats.push(new MessengerChat(message.senderId, false)); + activeChatIndex = activeChats.length - 1; + } + + activeChats[activeChatIndex].addMessage(message); + + return { ...state, activeChats }; + } default: return state; } diff --git a/src/views/friends/views/friend-bar-item/FriendBarItemView.tsx b/src/views/friends/views/friend-bar-item/FriendBarItemView.tsx index b845f530..40873386 100644 --- a/src/views/friends/views/friend-bar-item/FriendBarItemView.tsx +++ b/src/views/friends/views/friend-bar-item/FriendBarItemView.tsx @@ -1,6 +1,6 @@ import { FollowFriendMessageComposer, MouseEventType, UserProfileComposer } from '@nitrots/nitro-renderer'; import { FC, useCallback, useEffect, useRef, useState } from 'react'; -import { LocalizeText } from '../../../../api'; +import { LocalizeText, OpenMessengerChat } from '../../../../api'; import { SendMessageHook } from '../../../../hooks/messages'; import { AvatarImageView } from '../../../shared/avatar-image/AvatarImageView'; import { FriendBarItemViewProps } from './FriendBarItemView.types'; @@ -16,6 +16,13 @@ export const FriendBarItemView: FC = props => SendMessageHook(new FollowFriendMessageComposer(friend.id)); }, [ friend ]); + const openMessengerChat = useCallback(() => + { + if(!friend) return; + + OpenMessengerChat(friend.id); + }, [ friend ]); + const openProfile = useCallback(() => { SendMessageHook(new UserProfileComposer(friend.id)); @@ -59,7 +66,7 @@ export const FriendBarItemView: FC = props =>
{ friend.name }
{ isVisible &&
- + { friend.followingAllowed && }
} diff --git a/src/views/friends/views/friend-bar/FriendBarView.tsx b/src/views/friends/views/friend-bar/FriendBarView.tsx index dd7c698b..a0347c94 100644 --- a/src/views/friends/views/friend-bar/FriendBarView.tsx +++ b/src/views/friends/views/friend-bar/FriendBarView.tsx @@ -1,20 +1,14 @@ import { FC, useMemo, useState } from 'react'; -import { useFriendsContext } from '../../context/FriendsContext'; import { FriendBarItemView } from '../friend-bar-item/FriendBarItemView'; import { FriendBarViewProps } from './FriendBarView.types'; export const FriendBarView: FC = props => { - const { friendsState = null } = useFriendsContext(); - const { friends = null } = friendsState; + const { onlineFriends = null } = props; + const [ indexOffset, setIndexOffset ] = useState(0); const [ maxDisplayCount, setMaxDisplayCount ] = useState(3); - const onlineFriends = useMemo(() => - { - return friends.filter(friend => friend.online); - }, [ friends ]); - const canDecreaseIndex = useMemo(() => { if(indexOffset === 0) return false; diff --git a/src/views/friends/views/friend-bar/FriendBarView.types.ts b/src/views/friends/views/friend-bar/FriendBarView.types.ts index f47af57f..61a040ce 100644 --- a/src/views/friends/views/friend-bar/FriendBarView.types.ts +++ b/src/views/friends/views/friend-bar/FriendBarView.types.ts @@ -1,4 +1,5 @@ +import { MessengerFriend } from './../../common/MessengerFriend'; export interface FriendBarViewProps { - + onlineFriends: MessengerFriend[]; } diff --git a/src/views/friends/views/friend-item/FriendsListItemView.tsx b/src/views/friends/views/friend-item/FriendsListItemView.tsx deleted file mode 100644 index 2edafd90..00000000 --- a/src/views/friends/views/friend-item/FriendsListItemView.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import { SetRelationshipStatusComposer } from '@nitrots/nitro-renderer'; -import { FollowFriendMessageComposer } from '@nitrots/nitro-renderer/src/nitro/communication/messages/outgoing/friendlist/FollowFriendMessageComposer'; -import { FC, useCallback, useState } from 'react'; -import { LocalizeText, OpenMessengerChat } from '../../../../api'; -import { SendMessageHook } from '../../../../hooks'; -import { UserProfileIconView } from '../../../shared/user-profile-icon/UserProfileIconView'; -import { MessengerFriend } from '../../common/MessengerFriend'; -import { FriendsListItemViewProps } from './FriendsListItemView.types'; - -export const FriendsListItemView: FC = props => -{ - const { friend = null } = props; - - const [ isExpanded, setIsExpanded ] = useState(false); - - const followFriend = useCallback(() => - { - if(!friend) return; - - SendMessageHook(new FollowFriendMessageComposer(friend.id)); - }, [ friend ]); - - const openMessengerChat = useCallback(() => - { - if(!friend) return; - - OpenMessengerChat(friend.id); - }, [ friend ]); - - const getCurrentRelationshipName = useCallback(() => - { - if(!friend) return 'none'; - - switch(friend.relationshipStatus) - { - case MessengerFriend.RELATIONSHIP_HEART: return 'heart'; - case MessengerFriend.RELATIONSHIP_SMILE: return 'smile'; - case MessengerFriend.RELATIONSHIP_BOBBA: return 'bobba'; - default: return 'none'; - } - }, [ friend ]); - - const updateRelationship = useCallback((type: number) => - { - if(type !== friend.relationshipStatus) SendMessageHook(new SetRelationshipStatusComposer(friend.id, type)); - - setIsExpanded(false); - }, [ friend ]); - - if(!friend) return null; - - return ( -
- -
{ friend.name }
-
- { !isExpanded && <> - { friend.followingAllowed && } - { friend.online && } - setIsExpanded(true) } title={ LocalizeText('infostand.link.relationship') } /> - } - { isExpanded && <> - updateRelationship(MessengerFriend.RELATIONSHIP_HEART) } /> - updateRelationship(MessengerFriend.RELATIONSHIP_SMILE) } /> - updateRelationship(MessengerFriend.RELATIONSHIP_BOBBA) } /> - updateRelationship(MessengerFriend.RELATIONSHIP_NONE) } /> - } -
-
- ); -} diff --git a/src/views/friends/views/friend-item/FriendsListItemView.types.ts b/src/views/friends/views/friend-item/FriendsListItemView.types.ts deleted file mode 100644 index df44d3b5..00000000 --- a/src/views/friends/views/friend-item/FriendsListItemView.types.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { MessengerFriend } from '../../common/MessengerFriend'; - -export interface FriendsListItemViewProps -{ - friend: MessengerFriend; -} diff --git a/src/views/friends/views/friends-group-item/FriendsGroupItemView.tsx b/src/views/friends/views/friends-group-item/FriendsGroupItemView.tsx index bd9203f1..60b2066a 100644 --- a/src/views/friends/views/friends-group-item/FriendsGroupItemView.tsx +++ b/src/views/friends/views/friends-group-item/FriendsGroupItemView.tsx @@ -1,6 +1,6 @@ import { FollowFriendMessageComposer, SetRelationshipStatusComposer } from '@nitrots/nitro-renderer'; import { FC, useCallback, useState } from 'react'; -import { LocalizeText } from '../../../../api'; +import { LocalizeText, OpenMessengerChat } from '../../../../api'; import { SendMessageHook } from '../../../../hooks'; import { UserProfileIconView } from '../../../shared/user-profile-icon/UserProfileIconView'; import { MessengerFriend } from '../../common/MessengerFriend'; @@ -19,6 +19,13 @@ export const FriendsGroupItemView: FC = props => SendMessageHook(new FollowFriendMessageComposer(friend.id)); }, [ friend ]); + const openMessengerChat = useCallback(() => + { + if(!friend) return; + + OpenMessengerChat(friend.id); + }, [ friend ]); + const getCurrentRelationshipName = useCallback(() => { if(!friend) return 'none'; @@ -48,7 +55,7 @@ export const FriendsGroupItemView: FC = props =>
{ !isExpanded && <> { friend.followingAllowed && } - { friend.online && } + { friend.online && } setIsExpanded(true) } title={ LocalizeText('infostand.link.relationship') } /> } { isExpanded && <> diff --git a/src/views/friends/views/messenger/FriendsMessengerView.scss b/src/views/friends/views/messenger/FriendsMessengerView.scss new file mode 100644 index 00000000..429f64cf --- /dev/null +++ b/src/views/friends/views/messenger/FriendsMessengerView.scss @@ -0,0 +1,71 @@ +.nitro-friends-messenger { + width: 300px; + + .friend-head { + position: relative; + width: 40px; + height: 40px; + overflow: hidden; + + .avatar-image { + position: absolute; + margin-left: -27px; + margin-top: -27px; + } + } + + .chat-title { + margin-top: -21px; + } + + .chat-messages { + height: 200px; + min-height: 200px; + overflow-y: auto; + + .message-avatar { + position: relative; + overflow: hidden; + width: 50px; + height: 50px; + + .avatar-image { + position: absolute; + margin-left: -22px; + margin-top: -25px; + } + } + + .messages-group-left { + position: relative; + + &:before { + position: absolute; + content: ' '; + width: 0; + height: 0; + border-right: 8px solid rgba(var(--bs-light-rgb), var(--bs-bg-opacity)) !important; + border-top: 8px solid transparent; + border-bottom: 8px solid transparent; + top: 10px; + left: -8px; + } + } + + .messages-group-right { + position: relative; + + &:before { + position: absolute; + content: ' '; + width: 0; + height: 0; + border-left: 8px solid rgba(var(--bs-light-rgb), var(--bs-bg-opacity)) !important; + border-top: 8px solid transparent; + border-bottom: 8px solid transparent; + top: 10px; + right: -8px; + } + } + } +} diff --git a/src/views/friends/views/messenger/FriendsMessengerView.tsx b/src/views/friends/views/messenger/FriendsMessengerView.tsx index b64ed9d2..c3679025 100644 --- a/src/views/friends/views/messenger/FriendsMessengerView.tsx +++ b/src/views/friends/views/messenger/FriendsMessengerView.tsx @@ -1,20 +1,25 @@ -import { ILinkEventTracker, NitroEvent } from '@nitrots/nitro-renderer'; -import { FC, useCallback, useEffect, useState } from 'react'; -import { AddEventLinkTracker, LocalizeText, RemoveLinkEventTracker } from '../../../../api'; +import { FollowFriendMessageComposer, ILinkEventTracker, NitroEvent, SendMessageComposer, UserProfileComposer } from '@nitrots/nitro-renderer'; +import { FC, KeyboardEvent, useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import { AddEventLinkTracker, GetSessionDataManager, LocalizeText, RemoveLinkEventTracker } from '../../../../api'; import { FriendsEvent } from '../../../../events/friends/FriendsEvent'; -import { useUiEvent } from '../../../../hooks'; +import { SendMessageHook, useUiEvent } from '../../../../hooks'; import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout'; +import { AvatarImageView } from '../../../shared/avatar-image/AvatarImageView'; import { MessengerChat } from '../../common/MessengerChat'; +import { MessengerChatMessage } from '../../common/MessengerChatMessage'; import { useFriendsContext } from '../../context/FriendsContext'; import { FriendsActions } from '../../reducers/FriendsReducer'; export const FriendsMessengerView: FC<{}> = props => { const { friendsState = null, dispatchFriendsState = null } = useFriendsContext(); - const { activeChats = [] } = friendsState; + const { activeChats = [], friends = [] } = friendsState; const [ isVisible, setIsVisible ] = useState(false); - const [ activeChatIndex, setActiveChatIndex ] = useState(0); + const [ selectedChatIndex, setSelectedChatIndex ] = useState(0); + const [ message, setMessage ] = useState(''); + + const messagesBox = useRef(); const onNitroEvent = useCallback((event: NitroEvent) => { @@ -35,11 +40,11 @@ export const FriendsMessengerView: FC<{}> = props => const linkReceived = useCallback((url: string) => { const parts = url.split('/'); - console.log(parts); + if(parts.length < 3) return; const friendId = parseInt(parts[2]); - console.log(friendId); + let existingChatIndex = activeChats.findIndex(c => c.friendId === friendId); if(existingChatIndex === -1) @@ -57,10 +62,35 @@ export const FriendsMessengerView: FC<{}> = props => existingChatIndex = clonedActiveChats.length - 1; } - setActiveChatIndex(existingChatIndex); + setSelectedChatIndex(existingChatIndex); setIsVisible(true); }, [ activeChats, dispatchFriendsState ]); + const getFriendFigure = useCallback((id: number) => + { + const friend = friends.find(f => f.id === id); + + if(!friend) return null; + + return friend.figure; + }, [ friends ]); + + const selectedChat = useMemo(() => + { + return activeChats[selectedChatIndex]; + }, [ activeChats, selectedChatIndex ]); + + const selectedChatFriend = useMemo(() => + { + if(!selectedChat) return null; + + const friend = friends.find(f => f.id === selectedChat.friendId); + + if(!friend) return null; + + return friend; + }, [ friends, selectedChat ]); + useEffect(() => { const linkTracker: ILinkEventTracker = { @@ -73,12 +103,99 @@ export const FriendsMessengerView: FC<{}> = props => return () => RemoveLinkEventTracker(linkTracker); }, [ linkReceived ]); + useEffect(() => + { + if(!messagesBox || !messagesBox.current) return; + + messagesBox.current.scrollTop = messagesBox.current.scrollHeight; + + }, [ selectedChat ]); + + const followFriend = useCallback(() => + { + SendMessageHook(new FollowFriendMessageComposer(selectedChatFriend.id)); + }, [ selectedChatFriend ]); + + const openProfile = useCallback(() => + { + SendMessageHook(new UserProfileComposer(selectedChatFriend.id)); + }, [ selectedChatFriend ]); + + const sendMessage = useCallback(() => + { + if(message.length === 0) return; + + SendMessageHook(new SendMessageComposer(selectedChat.friendId, message)); + + dispatchFriendsState({ + type: FriendsActions.ADD_CHAT_MESSAGE, + payload: { + chatMessage: new MessengerChatMessage(MessengerChatMessage.MESSAGE, 0, message, (new Date().getMilliseconds())), + numberValue: selectedChat.friendId + } + }); + setMessage(''); + }, [ selectedChat, message, dispatchFriendsState ]); + + const onKeyDown = useCallback((event: KeyboardEvent) => + { + if(event.key !== 'Enter') return; + + sendMessage(); + }, [ sendMessage ]); + if(!isVisible) return null; return ( - {} } /> - - + setIsVisible(false) } /> + +
+ { activeChats && activeChats.map((chat, index) => + { + return
setSelectedChatIndex(index) }> + +
; + }) } +
+
+ { selectedChat && selectedChatFriend && <> +
{ LocalizeText('messenger.window.separator', ['FRIEND_NAME'], [ selectedChatFriend.name ]) }
+
+
+ + +
+ + +
+
+ { selectedChat.messageGroups.map((group, groupIndex) => + { + return
+ { group.userId !== 0 &&
+ +
} +
+ { group.messages.map((message, messageIndex) => + { + return
{ message.message }
+ }) } +
+ { group.userId === 0 &&
+ +
} +
; + }) } +
+
+ setMessage(e.target.value) } onKeyDown={ onKeyDown } /> + +
+ }
); }; From 0ade1ee7cb4bee83e69b91d41324244d72a25b79 Mon Sep 17 00:00:00 2001 From: MyNameIsBatman Date: Sat, 18 Sep 2021 03:05:47 -0300 Subject: [PATCH 09/31] Remove Console Log --- src/api/friends/OpenMessengerChat.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/api/friends/OpenMessengerChat.ts b/src/api/friends/OpenMessengerChat.ts index e5c685cd..08520b1b 100644 --- a/src/api/friends/OpenMessengerChat.ts +++ b/src/api/friends/OpenMessengerChat.ts @@ -2,6 +2,5 @@ import { CreateLinkEvent } from '..'; export function OpenMessengerChat(friendId: number): void { - console.log(`friends/messenger/${friendId}`); CreateLinkEvent(`friends/messenger/${friendId}`); } From a54be45a4ff279e7fe148237f3b1c59a9eb40c9e Mon Sep 17 00:00:00 2001 From: MyNameIsBatman Date: Sat, 18 Sep 2021 04:09:49 -0300 Subject: [PATCH 10/31] Updates --- .../friendlist/icons/icon_new_message.png | Bin 0 -> 177 bytes .../images/friendlist/icons/icon_warning.png | Bin 0 -> 225 bytes src/assets/styles/icons.scss | 12 ++++ src/views/friends/FriendsMessageHandler.tsx | 3 +- src/views/friends/common/MessengerChat.ts | 16 +++-- .../friends/common/MessengerChatMessage.ts | 3 +- .../common/MessengerChatMessageGroup.ts | 9 ++- src/views/friends/reducers/FriendsReducer.tsx | 24 ++++++- .../views/messenger/FriendsMessengerView.scss | 9 ++- .../views/messenger/FriendsMessengerView.tsx | 61 +++++++++++++----- 10 files changed, 110 insertions(+), 27 deletions(-) create mode 100644 src/assets/images/friendlist/icons/icon_new_message.png create mode 100644 src/assets/images/friendlist/icons/icon_warning.png diff --git a/src/assets/images/friendlist/icons/icon_new_message.png b/src/assets/images/friendlist/icons/icon_new_message.png new file mode 100644 index 0000000000000000000000000000000000000000..f7a31fa00dc9ba26150a1722162be85e55cfaa45 GIT binary patch literal 177 zcmeAS@N?(olHy`uVBq!ia0vp^d_XL~!3HGNrubO_sR~aQ#}Es_vlAS-8Vqzopr090#4fdBvi literal 0 HcmV?d00001 diff --git a/src/assets/images/friendlist/icons/icon_warning.png b/src/assets/images/friendlist/icons/icon_warning.png new file mode 100644 index 0000000000000000000000000000000000000000..3a3ffcf9efa03104936b6823bd7435cff4b4a610 GIT binary patch literal 225 zcmeAS@N?(olHy`uVBq!ia0vp^;y^6Q!3HGPJ}O-eq&N#aB8wRq_zr_GLB zeq{8kw;XW)eZ?&6#hu4Hmp!{Cm!HhG?puX)X7n1Ls;kD~hxUIs<=V=BrCNP;;4|i) Xl&z_ce_Xf+bRL7JtDnm{r-UW|QKMd} literal 0 HcmV?d00001 diff --git a/src/assets/styles/icons.scss b/src/assets/styles/icons.scss index a5108a7c..3d8f14ab 100644 --- a/src/assets/styles/icons.scss +++ b/src/assets/styles/icons.scss @@ -693,6 +693,18 @@ height: 16px; } + &.icon-friendlist-warning { + background: url('../images/friendlist/icons/icon_warning.png'); + width: 23px; + height: 21px; + } + + &.icon-friendlist-new-message { + background: url('../images/friendlist/icons/icon_new_message.png'); + width: 14px; + height: 16px; + } + &.spin { animation: rotating 1s linear infinite; } diff --git a/src/views/friends/FriendsMessageHandler.tsx b/src/views/friends/FriendsMessageHandler.tsx index e1e055f2..479fc961 100644 --- a/src/views/friends/FriendsMessageHandler.tsx +++ b/src/views/friends/FriendsMessageHandler.tsx @@ -77,7 +77,8 @@ export const FriendsMessageHandler: FC<{}> = props => dispatchFriendsState({ type: FriendsActions.ADD_CHAT_MESSAGE, payload: { - chatMessage: new MessengerChatMessage(MessengerChatMessage.MESSAGE, userId, parser.messageText, parser.secondsSinceSent, parser.extraData) + chatMessage: new MessengerChatMessage(MessengerChatMessage.MESSAGE, userId, parser.messageText, parser.secondsSinceSent, parser.extraData), + boolValue: true } }); }, [ dispatchFriendsState ]); diff --git a/src/views/friends/common/MessengerChat.ts b/src/views/friends/common/MessengerChat.ts index 2369a7c9..4b49d0ae 100644 --- a/src/views/friends/common/MessengerChat.ts +++ b/src/views/friends/common/MessengerChat.ts @@ -6,19 +6,25 @@ export class MessengerChat private _isRead: boolean; private _messageGroups: MessengerChatMessageGroup[]; - constructor(friendId: number, isRead: boolean = true) + constructor(friendId: number) { this._friendId = friendId; - this._isRead = isRead; + this._isRead = true; this._messageGroups = []; } - public addMessage(message: MessengerChatMessage): void + public addMessage(message: MessengerChatMessage, setAsNotRead: boolean = true, isSystem: boolean = false): void { - if(!this.lastMessageGroup || this.lastMessageGroup.userId !== message.senderId) this._messageGroups.push(new MessengerChatMessageGroup(message.senderId)); + if(!this.lastMessageGroup || this.lastMessageGroup.userId !== message.senderId || isSystem || this.lastMessageGroup.isSystem) this._messageGroups.push(new MessengerChatMessageGroup(message.senderId, isSystem)); this.lastMessageGroup.addMessage(message); - this._isRead = false; + + if(setAsNotRead) this._isRead = false; + } + + public read(): void + { + this._isRead = true; } public get friendId(): number diff --git a/src/views/friends/common/MessengerChatMessage.ts b/src/views/friends/common/MessengerChatMessage.ts index 5ded0a7d..6a0aced7 100644 --- a/src/views/friends/common/MessengerChatMessage.ts +++ b/src/views/friends/common/MessengerChatMessage.ts @@ -2,7 +2,8 @@ export class MessengerChatMessage { public static MESSAGE: number = 0; public static ROOM_INVITE: number = 1; - public static SYSTEM_NOTIFICATION: number = 2; + public static SECURITY_ALERT: number = 2; + public static STATUS_ALERT: number = 3; private _type: number; private _senderId: number; diff --git a/src/views/friends/common/MessengerChatMessageGroup.ts b/src/views/friends/common/MessengerChatMessageGroup.ts index 0bb27fe3..0fad7be8 100644 --- a/src/views/friends/common/MessengerChatMessageGroup.ts +++ b/src/views/friends/common/MessengerChatMessageGroup.ts @@ -4,11 +4,13 @@ export class MessengerChatMessageGroup { private _userId: number; private _messages: MessengerChatMessage[]; + private _isSystem: boolean; - constructor(userId: number) + constructor(userId: number, isSystem: boolean) { this._userId = userId; this._messages = []; + this._isSystem = isSystem; } public addMessage(message: MessengerChatMessage): void @@ -25,4 +27,9 @@ export class MessengerChatMessageGroup { return this._messages; } + + public get isSystem(): boolean + { + return this._isSystem; + } } diff --git a/src/views/friends/reducers/FriendsReducer.tsx b/src/views/friends/reducers/FriendsReducer.tsx index f66ce6fd..82f2e734 100644 --- a/src/views/friends/reducers/FriendsReducer.tsx +++ b/src/views/friends/reducers/FriendsReducer.tsx @@ -19,6 +19,7 @@ export interface IFriendsState friends: MessengerFriend[]; requests: MessengerRequest[]; activeChats: MessengerChat[]; + firstChatEverOpen: boolean; } export interface IFriendsAction @@ -32,6 +33,7 @@ export interface IFriendsAction chats?: MessengerChat[]; chatMessage?: MessengerChatMessage; numberValue?: number; + boolValue?: boolean; } } @@ -43,6 +45,7 @@ export class FriendsActions public static PROCESS_UPDATE: string = 'FA_PROCESS_UPDATE'; public static PROCESS_REQUESTS: string = 'FA_PROCESS_REQUESTS'; public static SET_ACTIVE_CHATS: string = 'FA_SET_ACTIVE_CHATS'; + public static SET_CHAT_READ: string = 'FA_SET_CHAT_READ'; public static ADD_CHAT_MESSAGE: string = 'FA_ADD_CHAT_MESSAGE'; } @@ -50,7 +53,8 @@ export const initialFriends: IFriendsState = { settings: null, friends: [], requests: [], - activeChats: [] + activeChats: [], + firstChatEverOpen: false } export const FriendsReducer: Reducer = (state, action) => @@ -145,11 +149,25 @@ export const FriendsReducer: Reducer = (state, ac case FriendsActions.SET_ACTIVE_CHATS: { const activeChats = (action.payload.chats || []); + if(!state.firstChatEverOpen && activeChats.length > 0) activeChats[0].addMessage(new MessengerChatMessage(MessengerChatMessage.SECURITY_ALERT, 0, null, 0), false, true); + + return { ...state, activeChats, firstChatEverOpen: true }; + } + case FriendsActions.SET_CHAT_READ: { + const friendId = action.payload.numberValue; + + const activeChats = Array.from(state.activeChats); + + let activeChatIndex = activeChats.findIndex(c => c.friendId === friendId); + + if(activeChatIndex > -1) activeChats[activeChatIndex].read(); + return { ...state, activeChats }; } case FriendsActions.ADD_CHAT_MESSAGE: { const message = action.payload.chatMessage; const toFriendId = action.payload.numberValue; + const setAsNotRead = action.payload.boolValue; const activeChats = Array.from(state.activeChats); @@ -157,11 +175,11 @@ export const FriendsReducer: Reducer = (state, ac if(activeChatIndex === -1) { - activeChats.push(new MessengerChat(message.senderId, false)); + activeChats.push(new MessengerChat(message.senderId)); activeChatIndex = activeChats.length - 1; } - activeChats[activeChatIndex].addMessage(message); + activeChats[activeChatIndex].addMessage(message, setAsNotRead); return { ...state, activeChats }; } diff --git a/src/views/friends/views/messenger/FriendsMessengerView.scss b/src/views/friends/views/messenger/FriendsMessengerView.scss index 429f64cf..bbfdb0aa 100644 --- a/src/views/friends/views/messenger/FriendsMessengerView.scss +++ b/src/views/friends/views/messenger/FriendsMessengerView.scss @@ -1,5 +1,5 @@ .nitro-friends-messenger { - width: 300px; + width: 280px; .friend-head { position: relative; @@ -7,6 +7,13 @@ height: 40px; overflow: hidden; + .icon { + position: absolute; + top: 1px; + right: 1px; + z-index: 10; + } + .avatar-image { position: absolute; margin-left: -27px; diff --git a/src/views/friends/views/messenger/FriendsMessengerView.tsx b/src/views/friends/views/messenger/FriendsMessengerView.tsx index c3679025..882b435f 100644 --- a/src/views/friends/views/messenger/FriendsMessengerView.tsx +++ b/src/views/friends/views/messenger/FriendsMessengerView.tsx @@ -50,7 +50,7 @@ export const FriendsMessengerView: FC<{}> = props => if(existingChatIndex === -1) { const clonedActiveChats = Array.from(activeChats); - clonedActiveChats.push(new MessengerChat(friendId, true)); + clonedActiveChats.push(new MessengerChat(friendId)); dispatchFriendsState({ type: FriendsActions.SET_ACTIVE_CHATS, @@ -75,8 +75,24 @@ export const FriendsMessengerView: FC<{}> = props => return friend.figure; }, [ friends ]); - const selectedChat = useMemo(() => + const selectChat = useCallback((index: number) => { + const chat = activeChats[index]; + + if(!chat) return; + + dispatchFriendsState({ + type: FriendsActions.SET_CHAT_READ, + payload: { + numberValue: chat.friendId + } + }); + + setSelectedChatIndex(index); + }, [ activeChats, dispatchFriendsState ]); + + const selectedChat = useMemo(() => + { return activeChats[selectedChatIndex]; }, [ activeChats, selectedChatIndex ]); @@ -131,7 +147,8 @@ export const FriendsMessengerView: FC<{}> = props => type: FriendsActions.ADD_CHAT_MESSAGE, payload: { chatMessage: new MessengerChatMessage(MessengerChatMessage.MESSAGE, 0, message, (new Date().getMilliseconds())), - numberValue: selectedChat.friendId + numberValue: selectedChat.friendId, + boolValue: false } }); setMessage(''); @@ -152,7 +169,8 @@ export const FriendsMessengerView: FC<{}> = props =>
{ activeChats && activeChats.map((chat, index) => { - return
setSelectedChatIndex(index) }> + return
selectChat(index) }> + { !chat.isRead && }
; }) } @@ -176,18 +194,31 @@ export const FriendsMessengerView: FC<{}> = props => { selectedChat.messageGroups.map((group, groupIndex) => { return
- { group.userId !== 0 &&
- -
} -
+ { group.isSystem && <> { group.messages.map((message, messageIndex) => - { - return
{ message.message }
- }) } -
- { group.userId === 0 &&
- -
} + { + return
+ { message.type === MessengerChatMessage.SECURITY_ALERT &&
+ +
{ LocalizeText('messenger.moderationinfo') }
+
} +
+ }) } + } + { !group.isSystem && <> + { group.userId !== 0 &&
+ +
} +
+ { group.messages.map((message, messageIndex) => + { + return
{ message.message }
+ }) } +
+ { group.userId === 0 &&
+ +
} + }
; }) }
From 83df995ce3f005cf11a4e956afb81decceb22005 Mon Sep 17 00:00:00 2001 From: Bill Date: Sat, 18 Sep 2021 04:31:08 -0400 Subject: [PATCH 11/31] Update alerts --- src/App.tsx | 1 + ...rtUIEvent.ts => NotificationAlertEvent.ts} | 23 +-- .../NotificationBubbleEvent.ts | 2 +- .../NotificationCenterAddNotificationEvent.ts | 19 --- src/events/notification-center/index.ts | 4 +- src/layout/Layout.scss | 1 + src/layout/index.ts | 1 + .../NotificationAlertView.scss | 8 ++ .../NotificationAlertView.tsx | 17 +++ .../NotificationAlertView.types.ts | 7 + src/layout/notification-alert/index.ts | 2 + src/views/help/HelpMessageHandler.tsx | 27 ++++ src/views/help/HelpView.tsx | 11 ++ src/views/help/common/GetCloseReasonKey.ts | 8 ++ src/views/main/MainView.tsx | 2 + .../NotificationCenterMessageHandler.tsx | 133 ++++++++++++++---- .../NotificationCenterView.scss | 9 -- .../NotificationCenterView.tsx | 60 ++++---- .../common/BroadcastMessageNotification.ts | 4 - .../common/DialogMessageNotification.ts | 24 ---- .../common/HotelWillShutdownNotification.ts | 17 --- .../common/MOTDNotification.ts | 19 --- .../common/ModeratorMessageNotification.ts | 17 --- .../common/Notification.ts | 49 ------- .../common/NotificationAlertItem.ts | 62 ++++++++ .../common/NotificationAlertType.ts | 7 + ...ationItem.ts => NotificationBubbleItem.ts} | 10 +- ...ationType.ts => NotificationBubbleType.ts} | 2 +- .../common/NotificationUtilities.ts | 97 ++++++++----- .../common/ProductImageUtility.ts | 59 ++++++++ .../context/NotificationCenterContext.tsx | 14 -- .../NotificationCenterContext.types.ts | 13 -- .../reducers/NotificationCenterReducer.tsx | 77 ---------- .../NotificationCenterAlertBase.tsx | 19 --- .../NotificationCenterAlertBase.types.ts | 5 - .../views/alert-layouts/GetAlertLayout.tsx | 19 +++ .../NotificationAlertLayoutView.types.ts | 7 + .../default/NotificationDefaultAlertView.tsx | 35 +++++ .../NotificationDefaultAlertView.types.ts | 7 + .../event/NotificationEventAlertView.tsx | 33 +++++ .../event/NotificationEventAlertView.types.ts | 7 + ...NotificationCenterBroadcastMessageView.tsx | 30 ---- ...icationCenterBroadcastMessageView.types.ts | 7 - .../views/bubble-layouts/GetBubbleLayout.tsx | 8 +- .../NotificationBubbleLayoutView.types.ts | 4 +- .../HotelWillShutdownView.tsx | 28 ---- .../HotelWillShutdownView.types.ts | 7 - .../ModeratorMessageView.tsx | 33 ----- .../ModeratorMessageView.types.ts | 7 - .../views/motd/NotificationCenterMotdView.tsx | 10 -- .../motd/NotificationCenterMotdView.types.ts | 7 - .../tray-item/NotificationTrayItemView.tsx | 22 --- .../NotificationTrayItemView.types.ts | 7 - 53 files changed, 555 insertions(+), 553 deletions(-) rename src/events/notification-center/{SimpleAlertUIEvent.ts => NotificationAlertEvent.ts} (52%) delete mode 100644 src/events/notification-center/NotificationCenterAddNotificationEvent.ts create mode 100644 src/layout/notification-alert/NotificationAlertView.scss create mode 100644 src/layout/notification-alert/NotificationAlertView.tsx create mode 100644 src/layout/notification-alert/NotificationAlertView.types.ts create mode 100644 src/layout/notification-alert/index.ts create mode 100644 src/views/help/HelpMessageHandler.tsx create mode 100644 src/views/help/HelpView.tsx create mode 100644 src/views/help/common/GetCloseReasonKey.ts delete mode 100644 src/views/notification-center/common/BroadcastMessageNotification.ts delete mode 100644 src/views/notification-center/common/DialogMessageNotification.ts delete mode 100644 src/views/notification-center/common/HotelWillShutdownNotification.ts delete mode 100644 src/views/notification-center/common/MOTDNotification.ts delete mode 100644 src/views/notification-center/common/ModeratorMessageNotification.ts delete mode 100644 src/views/notification-center/common/Notification.ts create mode 100644 src/views/notification-center/common/NotificationAlertItem.ts create mode 100644 src/views/notification-center/common/NotificationAlertType.ts rename src/views/notification-center/common/{NotificationItem.ts => NotificationBubbleItem.ts} (75%) rename src/views/notification-center/common/{NotificationType.ts => NotificationBubbleType.ts} (95%) create mode 100644 src/views/notification-center/common/ProductImageUtility.ts delete mode 100644 src/views/notification-center/context/NotificationCenterContext.tsx delete mode 100644 src/views/notification-center/context/NotificationCenterContext.types.ts delete mode 100644 src/views/notification-center/reducers/NotificationCenterReducer.tsx delete mode 100644 src/views/notification-center/views/alert-base/NotificationCenterAlertBase.tsx delete mode 100644 src/views/notification-center/views/alert-base/NotificationCenterAlertBase.types.ts create mode 100644 src/views/notification-center/views/alert-layouts/GetAlertLayout.tsx create mode 100644 src/views/notification-center/views/alert-layouts/NotificationAlertLayoutView.types.ts create mode 100644 src/views/notification-center/views/alert-layouts/default/NotificationDefaultAlertView.tsx create mode 100644 src/views/notification-center/views/alert-layouts/default/NotificationDefaultAlertView.types.ts create mode 100644 src/views/notification-center/views/alert-layouts/event/NotificationEventAlertView.tsx create mode 100644 src/views/notification-center/views/alert-layouts/event/NotificationEventAlertView.types.ts delete mode 100644 src/views/notification-center/views/broadcast-message/NotificationCenterBroadcastMessageView.tsx delete mode 100644 src/views/notification-center/views/broadcast-message/NotificationCenterBroadcastMessageView.types.ts delete mode 100644 src/views/notification-center/views/hotel-will-shutdown/HotelWillShutdownView.tsx delete mode 100644 src/views/notification-center/views/hotel-will-shutdown/HotelWillShutdownView.types.ts delete mode 100644 src/views/notification-center/views/moderator-message/ModeratorMessageView.tsx delete mode 100644 src/views/notification-center/views/moderator-message/ModeratorMessageView.types.ts delete mode 100644 src/views/notification-center/views/motd/NotificationCenterMotdView.tsx delete mode 100644 src/views/notification-center/views/motd/NotificationCenterMotdView.types.ts delete mode 100644 src/views/notification-center/views/tray-item/NotificationTrayItemView.tsx delete mode 100644 src/views/notification-center/views/tray-item/NotificationTrayItemView.types.ts diff --git a/src/App.tsx b/src/App.tsx index ae6999e5..439fbc5d 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -126,6 +126,7 @@ export const App: FC<{}> = props => return (
+
{ (!isReady || isError) && } diff --git a/src/events/notification-center/SimpleAlertUIEvent.ts b/src/events/notification-center/NotificationAlertEvent.ts similarity index 52% rename from src/events/notification-center/SimpleAlertUIEvent.ts rename to src/events/notification-center/NotificationAlertEvent.ts index d869d0b7..4f64acc9 100644 --- a/src/events/notification-center/SimpleAlertUIEvent.ts +++ b/src/events/notification-center/NotificationAlertEvent.ts @@ -1,29 +1,36 @@ import { NitroEvent } from '@nitrots/nitro-renderer'; -export class SimpleAlertUIEvent extends NitroEvent +export class NotificationAlertEvent extends NitroEvent { - public static ALERT: string = 'SAUE_ALERT'; + public static ALERT: string = 'NAE_ALERT'; - private _message: string; + private _messages: string[]; + private _alertType: string; private _clickUrl: string; private _clickUrlText: string; private _title: string; private _imageUrl: string; - constructor(message: string, clickUrl: string = null, clickUrlText: string = null, title: string = null, imageUrl: string = null) + constructor(messages: string[], alertType: string = null, clickUrl: string = null, clickUrlText: string = null, title: string = null, imageUrl: string = null) { - super(SimpleAlertUIEvent.ALERT); + super(NotificationAlertEvent.ALERT); - this._message = message; + this._messages = messages; + this._alertType = alertType; this._clickUrl = clickUrl; this._clickUrlText = clickUrlText; this._title = title; this._imageUrl = imageUrl; } - public get message(): string + public get messages(): string[] { - return this._message; + return this._messages; + } + + public get alertType(): string + { + return this._alertType; } public get clickUrl(): string diff --git a/src/events/notification-center/NotificationBubbleEvent.ts b/src/events/notification-center/NotificationBubbleEvent.ts index 11a343a2..55383655 100644 --- a/src/events/notification-center/NotificationBubbleEvent.ts +++ b/src/events/notification-center/NotificationBubbleEvent.ts @@ -2,7 +2,7 @@ import { NitroEvent } from '@nitrots/nitro-renderer'; export class NotificationBubbleEvent extends NitroEvent { - public static NEW_BUBBLE: string = 'NNBE_NEW_BUBBLE'; + public static NEW_BUBBLE: string = 'NBE_NEW_BUBBLE'; private _message: string; private _notificationType: string; diff --git a/src/events/notification-center/NotificationCenterAddNotificationEvent.ts b/src/events/notification-center/NotificationCenterAddNotificationEvent.ts deleted file mode 100644 index 200fda47..00000000 --- a/src/events/notification-center/NotificationCenterAddNotificationEvent.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { NitroNotification } from '../../views/notification-center/common/Notification'; -import { NotificationCenterEvent } from './NotificationCenterEvent'; - -export class NotificationCenterAddNotificationEvent extends NotificationCenterEvent -{ - private _notification: NitroNotification; - - constructor(notification: NitroNotification) - { - super(NotificationCenterEvent.ADD_NOTIFICATION); - - this._notification = notification; - } - - public get notification(): NitroNotification - { - return this._notification; - } -} diff --git a/src/events/notification-center/index.ts b/src/events/notification-center/index.ts index 2951cdfb..cac7d708 100644 --- a/src/events/notification-center/index.ts +++ b/src/events/notification-center/index.ts @@ -1,4 +1,4 @@ -export * from './NotificationCenterAddNotificationEvent'; +export * from './NotificationAlertEvent'; +export * from './NotificationBubbleEvent'; export * from './NotificationCenterAlertEvent'; export * from './NotificationCenterEvent'; -export * from './SimpleAlertUIEvent'; diff --git a/src/layout/Layout.scss b/src/layout/Layout.scss index 3b613a5f..9e435e47 100644 --- a/src/layout/Layout.scss +++ b/src/layout/Layout.scss @@ -27,6 +27,7 @@ @import './loading-habbos/LoadingHabbosView'; @import './loading-spinner/LoadingSpinnerView'; @import './mini-camera/NitroLayoutMiniCameraView'; +@import './notification-alert/NotificationAlertView'; @import './notification-bubble/NotificationBubbleView'; @import './trophy/NitroLayoutTrophyView'; @import './gift-card/NitroLayoutGiftCardView'; diff --git a/src/layout/index.ts b/src/layout/index.ts index f02a74e0..81e87964 100644 --- a/src/layout/index.ts +++ b/src/layout/index.ts @@ -3,6 +3,7 @@ export * from './draggable-window'; export * from './gift-card'; export * from './loading-spinner'; export * from './mini-camera'; +export * from './notification-alert'; export * from './notification-bubble'; export * from './transitions'; export * from './trophy'; diff --git a/src/layout/notification-alert/NotificationAlertView.scss b/src/layout/notification-alert/NotificationAlertView.scss new file mode 100644 index 00000000..d6dbe418 --- /dev/null +++ b/src/layout/notification-alert/NotificationAlertView.scss @@ -0,0 +1,8 @@ +.nitro-alert { + width: 350px; + + .content-area { + min-height: 125px; + max-height: 300px; + } +} diff --git a/src/layout/notification-alert/NotificationAlertView.tsx b/src/layout/notification-alert/NotificationAlertView.tsx new file mode 100644 index 00000000..f5281398 --- /dev/null +++ b/src/layout/notification-alert/NotificationAlertView.tsx @@ -0,0 +1,17 @@ +import { FC } from 'react'; +import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../card'; +import { NotificationAlertViewProps } from './NotificationAlertView.types'; + +export const NotificationAlertView: FC = props => +{ + const { title = '', close = null, className = '', children = null, ...rest } = props; + + return ( + + + + { children } + + + ); +} diff --git a/src/layout/notification-alert/NotificationAlertView.types.ts b/src/layout/notification-alert/NotificationAlertView.types.ts new file mode 100644 index 00000000..9d1817e5 --- /dev/null +++ b/src/layout/notification-alert/NotificationAlertView.types.ts @@ -0,0 +1,7 @@ +import { DetailsHTMLAttributes } from 'react'; + +export interface NotificationAlertViewProps extends DetailsHTMLAttributes +{ + title: string; + close: () => void; +} diff --git a/src/layout/notification-alert/index.ts b/src/layout/notification-alert/index.ts new file mode 100644 index 00000000..91f80b3d --- /dev/null +++ b/src/layout/notification-alert/index.ts @@ -0,0 +1,2 @@ +export * from './NotificationAlertView'; +export * from './NotificationAlertView.types'; diff --git a/src/views/help/HelpMessageHandler.tsx b/src/views/help/HelpMessageHandler.tsx new file mode 100644 index 00000000..f71634b7 --- /dev/null +++ b/src/views/help/HelpMessageHandler.tsx @@ -0,0 +1,27 @@ +import { CallForHelpResultMessageEvent, FurnitureListItemParser, PetData } from '@nitrots/nitro-renderer'; +import { FC, useCallback } from 'react'; +import { LocalizeText } from '../../api'; +import { CreateMessageHook } from '../../hooks/messages/message-event'; +import { NotificationAlertType } from '../notification-center/common/NotificationAlertType'; +import { NotificationUtilities } from '../notification-center/common/NotificationUtilities'; +import { GetCloseReasonKey } from './common/GetCloseReasonKey'; +let furniMsgFragments: Map[] = null; +let petMsgFragments: Map[] = null; + +export const HelpMessageHandler: FC<{}> = props => +{ + const onCallForHelpResultMessageEvent = useCallback((event: CallForHelpResultMessageEvent) => + { + const parser = event.getParser(); + + let message = parser.messageText; + + if(!message || !message.length) message = LocalizeText('help.cfh.closed.' + GetCloseReasonKey(parser.resultType)) + + NotificationUtilities.simpleAlert(message, NotificationAlertType.MODERATION, null, null, LocalizeText('mod.alert.title')); + }, []); + + CreateMessageHook(CallForHelpResultMessageEvent, onCallForHelpResultMessageEvent); + + return null; +} diff --git a/src/views/help/HelpView.tsx b/src/views/help/HelpView.tsx new file mode 100644 index 00000000..4917c713 --- /dev/null +++ b/src/views/help/HelpView.tsx @@ -0,0 +1,11 @@ +import { FC } from 'react'; +import { HelpMessageHandler } from './HelpMessageHandler'; + +export const HelpView: FC<{}> = props => +{ + return ( + <> + + + ); +} diff --git a/src/views/help/common/GetCloseReasonKey.ts b/src/views/help/common/GetCloseReasonKey.ts new file mode 100644 index 00000000..520d14fd --- /dev/null +++ b/src/views/help/common/GetCloseReasonKey.ts @@ -0,0 +1,8 @@ +export const GetCloseReasonKey = (code: number) => +{ + if(code === 1) return 'useless'; + + if(code === 2) return 'abusive'; + + return 'resolved'; +} diff --git a/src/views/main/MainView.tsx b/src/views/main/MainView.tsx index 68269e58..49e28a61 100644 --- a/src/views/main/MainView.tsx +++ b/src/views/main/MainView.tsx @@ -9,6 +9,7 @@ import { CameraWidgetView } from '../camera/CameraWidgetView'; import { CatalogView } from '../catalog/CatalogView'; import { FriendsView } from '../friends/FriendsView'; import { GroupsView } from '../groups/GroupsView'; +import { HelpView } from '../help/HelpView'; import { HotelView } from '../hotel-view/HotelView'; import { InventoryView } from '../inventory/InventoryView'; import { ModToolsView } from '../mod-tools/ModToolsView'; @@ -69,6 +70,7 @@ export const MainView: FC = props => +
); } diff --git a/src/views/notification-center/NotificationCenterMessageHandler.tsx b/src/views/notification-center/NotificationCenterMessageHandler.tsx index de974b13..9afc098d 100644 --- a/src/views/notification-center/NotificationCenterMessageHandler.tsx +++ b/src/views/notification-center/NotificationCenterMessageHandler.tsx @@ -1,20 +1,14 @@ -import { AchievementNotificationMessageEvent, ActivityPointNotificationMessageEvent, ClubGiftNotificationEvent, HabboBroadcastMessageEvent, HotelClosesAndWillOpenAtEvent, HotelWillShutdownEvent, ModeratorMessageEvent, MOTDNotificationEvent, NotificationDialogMessageEvent, PetAddedToInventoryEvent, RespectReceivedEvent, RoomEnterEvent, Vector3d } from '@nitrots/nitro-renderer'; +import { AchievementNotificationMessageEvent, ActivityPointNotificationMessageEvent, ClubGiftNotificationEvent, ClubGiftSelectedEvent, HabboBroadcastMessageEvent, HotelClosedAndOpensEvent, HotelClosesAndWillOpenAtEvent, HotelWillCloseInMinutesEvent, InfoFeedEnableMessageEvent, MaintenanceStatusMessageEvent, ModeratorCautionEvent, ModeratorMessageEvent, MOTDNotificationEvent, NotificationDialogMessageEvent, PetLevelNotificationEvent, PetReceivedMessageEvent, RespectReceivedEvent, RoomEnterEvent, UserBannedMessageEvent, Vector3d } from '@nitrots/nitro-renderer'; import { FC, useCallback } from 'react'; -import { GetRoomEngine, GetSessionDataManager, LocalizeBadgeName, LocalizeText } from '../../api'; -import { NotificationCenterAlertEvent } from '../../events'; -import { dispatchUiEvent } from '../../hooks/events'; +import { GetConfiguration, GetRoomEngine, GetSessionDataManager, LocalizeBadgeName, LocalizeText } from '../../api'; import { CreateMessageHook } from '../../hooks/messages'; -import { HotelWillShutdownNotification } from './common/HotelWillShutdownNotification'; -import { NotificationType } from './common/NotificationType'; +import { NotificationBubbleType } from './common/NotificationBubbleType'; import { NotificationUtilities } from './common/NotificationUtilities'; -import { useNotificationCenterContext } from './context/NotificationCenterContext'; +import { ProductImageUtility } from './common/ProductImageUtility'; import { INotificationCenterMessageHandlerProps } from './NotificationCenterMessageHandler.types'; -import { NotificationCenterActions } from './reducers/NotificationCenterReducer'; export const NotificationCenterMessageHandler: FC = props => { - const { dispatchNotificationCenterState = null } = useNotificationCenterContext(); - const onRespectReceivedEvent = useCallback((event: RespectReceivedEvent) => { const parser = event.getParser(); @@ -24,8 +18,8 @@ export const NotificationCenterMessageHandler: FC('currency.asset.icon.url', '').replace('%type%', parser.type.toString()); + break; + } + + NotificationUtilities.showSingleBubble(LocalizeText('notifications.text.loyalty.received', [ 'amount' ], [ parser.amountChanged.toString() ]), NotificationBubbleType.INFO, imageUrl); }, []); CreateMessageHook(ActivityPointNotificationMessageEvent, onActivityPointNotificationMessageEvent); + const onUserBannedMessageEvent = useCallback((event: UserBannedMessageEvent) => + { + const parser = event.getParser(); + + NotificationUtilities.handleUserBannedMessage(parser.message); + }, []); + + CreateMessageHook(UserBannedMessageEvent, onUserBannedMessageEvent); + const onHotelClosesAndWillOpenAtEvent = useCallback((event: HotelClosesAndWillOpenAtEvent) => { const parser = event.getParser(); @@ -89,7 +103,7 @@ export const NotificationCenterMessageHandler: FC + const onPetReceivedMessageEvent = useCallback((event: PetReceivedMessageEvent) => { const parser = event.getParser(); @@ -101,10 +115,10 @@ export const NotificationCenterMessageHandler: FC { @@ -119,24 +133,67 @@ export const NotificationCenterMessageHandler: FC + const onPetLevelNotificationEvent = useCallback((event: PetLevelNotificationEvent) => { const parser = event.getParser(); - dispatchNotificationCenterState({ - type: NotificationCenterActions.ADD_NOTIFICATION, - payload: { - notification: new HotelWillShutdownNotification(parser.minutes) - } - }); - }, [ dispatchNotificationCenterState ]); + let imageUrl: string = null; - CreateMessageHook(HotelWillShutdownEvent, onHotelWillShutdownEvent); + const imageResult = GetRoomEngine().getRoomObjectPetImage(parser.figureData.typeId, parser.figureData.paletteId, parseInt(parser.figureData.color, 16), new Vector3d(45 * 3), 64, null, true); + + if(imageResult) imageUrl = imageResult.getImage().src; + + NotificationUtilities.showSingleBubble(LocalizeText('notifications.text.petlevel', [ 'pet_name', 'level' ], [ parser.petName, parser.level.toString() ]), NotificationBubbleType.PETLEVEL, imageUrl); + }, []); + + CreateMessageHook(PetLevelNotificationEvent, onPetLevelNotificationEvent); + + const onInfoFeedEnableMessageEvent = useCallback((event: InfoFeedEnableMessageEvent) => + { + const parser = event.getParser(); + + NotificationUtilities.BUBBLES_DISABLED = !(parser.enabled); + }, []); + + CreateMessageHook(InfoFeedEnableMessageEvent, onInfoFeedEnableMessageEvent); + + const onClubGiftSelectedEvent = useCallback((event: ClubGiftSelectedEvent) => + { + const parser = event.getParser(); + + if(!parser.products || !parser.products.length) return; + + const productData = parser.products[0]; + + if(!productData) return; + + NotificationUtilities.showSingleBubble(LocalizeText('notifications.text.club_gift.selected'), NotificationBubbleType.INFO, ProductImageUtility.getProductImageUrl(productData.productType, productData.furniClassId, productData.extraParam)) + }, []); + + CreateMessageHook(ClubGiftSelectedEvent, onClubGiftSelectedEvent); + + const onMaintenanceStatusMessageEvent = useCallback((event: MaintenanceStatusMessageEvent) => + { + const parser = event.getParser(); + + NotificationUtilities.handleHotelMaintenanceMessage(parser.minutesUntilMaintenance, parser.duration); + }, []); + + CreateMessageHook(MaintenanceStatusMessageEvent, onMaintenanceStatusMessageEvent); + + const onModeratorCautionEvent = useCallback((event: ModeratorCautionEvent) => + { + const parser = event.getParser(); + + NotificationUtilities.handleModeratorCaution(parser.message, parser.url); + }, []); + + CreateMessageHook(ModeratorCautionEvent, onModeratorCautionEvent); const onNotificationDialogMessageEvent = useCallback((event: NotificationDialogMessageEvent) => { @@ -147,5 +204,23 @@ export const NotificationCenterMessageHandler: FC + { + const parser = event.getParser(); + + NotificationUtilities.handleHotelClosingMessage(parser.openMinute); + }, []); + + CreateMessageHook(HotelWillCloseInMinutesEvent, onHotelWillCloseInMinutesEvent); + + const onHotelClosedAndOpensEvent = useCallback((event: HotelClosedAndOpensEvent) => + { + const parser = event.getParser(); + + NotificationUtilities.handleLoginFailedHotelClosedMessage(parser.openHour, parser.openMinute); + }, []); + + CreateMessageHook(HotelClosedAndOpensEvent, onHotelClosedAndOpensEvent); + return null; } diff --git a/src/views/notification-center/NotificationCenterView.scss b/src/views/notification-center/NotificationCenterView.scss index 78a94d63..671ea3e7 100644 --- a/src/views/notification-center/NotificationCenterView.scss +++ b/src/views/notification-center/NotificationCenterView.scss @@ -1,12 +1,3 @@ -.nitro-alert { - width: 350px; - - .content-area { - min-height: 125px; - max-height: 300px; - } -} - .nitro-notification-center-container { position: absolute; top: 0; diff --git a/src/views/notification-center/NotificationCenterView.tsx b/src/views/notification-center/NotificationCenterView.tsx index ace8d3e4..0367b604 100644 --- a/src/views/notification-center/NotificationCenterView.tsx +++ b/src/views/notification-center/NotificationCenterView.tsx @@ -1,40 +1,42 @@ import { FC, ReactNode, useCallback, useMemo, useState } from 'react'; -import { NotificationCenterAlertEvent } from '../../events'; +import { createPortal } from 'react-dom'; +import { NotificationAlertEvent } from '../../events'; import { NotificationBubbleEvent } from '../../events/notification-center/NotificationBubbleEvent'; import { useUiEvent } from '../../hooks/events'; -import { NotificationItem } from './common/NotificationItem'; -import { NotificationType } from './common/NotificationType'; +import { NotificationAlertItem } from './common/NotificationAlertItem'; +import { NotificationBubbleItem } from './common/NotificationBubbleItem'; +import { NotificationBubbleType } from './common/NotificationBubbleType'; import { NotificationCenterMessageHandler } from './NotificationCenterMessageHandler'; import { NotificationCenterViewProps } from './NotificationCenterView.types'; -import { NotificationCenterBroadcastMessageView } from './views/broadcast-message/NotificationCenterBroadcastMessageView'; +import { GetAlertLayout } from './views/alert-layouts/GetAlertLayout'; import { GetBubbleLayout } from './views/bubble-layouts/GetBubbleLayout'; export const NotificationCenterView: FC = props => { - const [ alerts, setAlerts ] = useState([]); - const [ bubbleAlerts, setBubbleAlerts ] = useState([]); + const [ alerts, setAlerts ] = useState([]); + const [ bubbleAlerts, setBubbleAlerts ] = useState([]); - const onNotificationCenterAlertEvent = useCallback((event: NotificationCenterAlertEvent) => + const onNotificationAlertEvent = useCallback((event: NotificationAlertEvent) => { - setAlerts(prevValue => - { - return [ ...prevValue, event ]; - }); + console.log(event); + const alertItem = new NotificationAlertItem(event.messages, event.alertType, event.clickUrl, event.clickUrlText, event.title, event.imageUrl); + + setAlerts(prevValue => [ alertItem, ...prevValue ]); }, []); - useUiEvent(NotificationCenterAlertEvent.HOTEL_ALERT, onNotificationCenterAlertEvent); + useUiEvent(NotificationAlertEvent.ALERT, onNotificationAlertEvent); const onNotificationBubbleEvent = useCallback((event: NotificationBubbleEvent) => { console.log(event); - const notificationItem = new NotificationItem(event.message, event.notificationType, event.imageUrl, event.linkUrl); + const notificationItem = new NotificationBubbleItem(event.message, event.notificationType, event.imageUrl, event.linkUrl); setBubbleAlerts(prevValue => [ notificationItem, ...prevValue ]); }, []); useUiEvent(NotificationBubbleEvent.NEW_BUBBLE, onNotificationBubbleEvent); - const closeAlert = useCallback((alert: NotificationCenterAlertEvent) => + const closeAlert = useCallback((alert: NotificationAlertItem) => { setAlerts(prevValue => { @@ -47,7 +49,7 @@ export const NotificationCenterView: FC = props => }); }, []); - const closeBubbleAlert = useCallback((item: NotificationItem) => + const closeBubbleAlert = useCallback((item: NotificationBubbleItem) => { setBubbleAlerts(prevValue => { @@ -60,6 +62,22 @@ export const NotificationCenterView: FC = props => }) }, []); + const getAlerts = useMemo(() => + { + if(!alerts || !alerts.length) return null; + + const elements: ReactNode[] = []; + + for(const alert of alerts) + { + const element = GetAlertLayout(alert, () => closeAlert(alert)); + + elements.push(element); + } + + return elements; + }, [ alerts, closeAlert ]); + const getBubbleAlerts = useMemo(() => { if(!bubbleAlerts || !bubbleAlerts.length) return null; @@ -70,7 +88,7 @@ export const NotificationCenterView: FC = props => { const element = GetBubbleLayout(alert, () => closeBubbleAlert(alert)); - if(alert.notificationType === NotificationType.CLUBGIFT) + if(alert.notificationType === NotificationBubbleType.CLUBGIFT) { elements.unshift(element); @@ -89,15 +107,7 @@ export const NotificationCenterView: FC = props =>
{ getBubbleAlerts }
- { (alerts.length > 0) && alerts.map((alert, index) => - { - switch(alert.type) - { - case NotificationCenterAlertEvent.HOTEL_ALERT: - default: - return closeAlert(alert) } />; - } - })} + { createPortal(getAlerts, document.getElementById('nitro-alerts-container')) } ); } diff --git a/src/views/notification-center/common/BroadcastMessageNotification.ts b/src/views/notification-center/common/BroadcastMessageNotification.ts deleted file mode 100644 index ddf0fa0d..00000000 --- a/src/views/notification-center/common/BroadcastMessageNotification.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { NitroNotification } from './Notification'; - -export class BroadcastMessageNotification extends NitroNotification -{} diff --git a/src/views/notification-center/common/DialogMessageNotification.ts b/src/views/notification-center/common/DialogMessageNotification.ts deleted file mode 100644 index a3201658..00000000 --- a/src/views/notification-center/common/DialogMessageNotification.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { NitroNotification } from './Notification'; - -export class DialogMessageNotification extends NitroNotification -{ - private _type: string; - private _parameters: Map; - - constructor(type: string, parameters: Map) - { - super(); - this._type = type; - this._parameters = parameters; - } - - public get type(): string - { - return this._type; - } - - public get parameters(): Map - { - return this._parameters; - } -} diff --git a/src/views/notification-center/common/HotelWillShutdownNotification.ts b/src/views/notification-center/common/HotelWillShutdownNotification.ts deleted file mode 100644 index 9f30c1ae..00000000 --- a/src/views/notification-center/common/HotelWillShutdownNotification.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { NitroNotification } from './Notification'; - -export class HotelWillShutdownNotification extends NitroNotification -{ - private _minutes: number; - - constructor(minutes: number) - { - super(); - this._minutes = minutes; - } - - public get minutes(): number - { - return this._minutes; - } -} diff --git a/src/views/notification-center/common/MOTDNotification.ts b/src/views/notification-center/common/MOTDNotification.ts deleted file mode 100644 index f543507d..00000000 --- a/src/views/notification-center/common/MOTDNotification.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { NitroNotification } from './Notification'; - -export class MOTDNotification extends NitroNotification -{ - private _messages: string[]; - - constructor(messages: string[]) - { - super(); - this._messages = []; - - for(const message of messages) this._messages.push(message.replace(/\r\n|\r|\n/g, '
')); - } - - public get messages(): string[] - { - return this._messages; - } -} diff --git a/src/views/notification-center/common/ModeratorMessageNotification.ts b/src/views/notification-center/common/ModeratorMessageNotification.ts deleted file mode 100644 index ed324b11..00000000 --- a/src/views/notification-center/common/ModeratorMessageNotification.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { NitroNotification } from './Notification'; - -export class ModeratorMessageNotification extends NitroNotification -{ - private _link: string; - - constructor(message: string, link: string) - { - super(message); - this._link = link; - } - - public get link(): string - { - return this._link; - } -} diff --git a/src/views/notification-center/common/Notification.ts b/src/views/notification-center/common/Notification.ts deleted file mode 100644 index 2f170cce..00000000 --- a/src/views/notification-center/common/Notification.ts +++ /dev/null @@ -1,49 +0,0 @@ -export class NitroNotification -{ - public static CURRENT_ID: number = 0; - - private _id: number; - private _title: string; - private _message: string; - private _dismissed: boolean = false; - private _timestamp: number; - - constructor(message: string = null, title: string = null) - { - this._id = ++NitroNotification.CURRENT_ID; - this._title = title; - this._timestamp = Date.now(); - - if(message) this._message = message.replace(/\r\n|\r|\n/g, '
'); - } - - public dismiss(): void - { - this._dismissed = true; - } - - public get id(): number - { - return this._id; - } - - public get title(): string - { - return this._title; - } - - public get message(): string - { - return this._message; - } - - public get dismissed(): boolean - { - return this._dismissed; - } - - public get timestamp(): number - { - return this._timestamp; - } -} diff --git a/src/views/notification-center/common/NotificationAlertItem.ts b/src/views/notification-center/common/NotificationAlertItem.ts new file mode 100644 index 00000000..b3432276 --- /dev/null +++ b/src/views/notification-center/common/NotificationAlertItem.ts @@ -0,0 +1,62 @@ +import { NotificationBubbleType } from './NotificationBubbleType'; + +export class NotificationAlertItem +{ + private static ITEM_ID: number = -1; + + private _id: number; + private _messages: string[]; + private _alertType: string; + private _clickUrl: string; + private _clickUrlText: string; + private _title: string; + private _imageUrl: string; + + constructor(messages: string[], alertType: string = NotificationBubbleType.INFO, clickUrl: string = null, clickUrlText: string = null, title: string = null, imageUrl: string = null) + { + NotificationAlertItem.ITEM_ID += 1; + + this._id = NotificationAlertItem.ITEM_ID; + this._messages = messages; + this._alertType = alertType; + this._clickUrl = clickUrl; + this._clickUrlText = clickUrlText; + this._title = title; + this._imageUrl = imageUrl; + } + + public get id(): number + { + return this._id; + } + + public get messages(): string[] + { + return this._messages; + } + + public get alertType(): string + { + return this._alertType; + } + + public get clickUrl(): string + { + return this._clickUrl; + } + + public get clickUrlText(): string + { + return this._clickUrlText; + } + + public get title(): string + { + return this._title; + } + + public get imageUrl(): string + { + return this._imageUrl; + } +} diff --git a/src/views/notification-center/common/NotificationAlertType.ts b/src/views/notification-center/common/NotificationAlertType.ts new file mode 100644 index 00000000..9a4b192b --- /dev/null +++ b/src/views/notification-center/common/NotificationAlertType.ts @@ -0,0 +1,7 @@ +export class NotificationAlertType +{ + public static DEFAULT: string = 'default'; + public static MOTD: string = 'motd'; + public static MODERATION: string = 'moderation'; + public static EVENT: string = 'event'; +} diff --git a/src/views/notification-center/common/NotificationItem.ts b/src/views/notification-center/common/NotificationBubbleItem.ts similarity index 75% rename from src/views/notification-center/common/NotificationItem.ts rename to src/views/notification-center/common/NotificationBubbleItem.ts index 9387db74..fe90dab7 100644 --- a/src/views/notification-center/common/NotificationItem.ts +++ b/src/views/notification-center/common/NotificationBubbleItem.ts @@ -1,6 +1,6 @@ -import { NotificationType } from './NotificationType'; +import { NotificationBubbleType } from './NotificationBubbleType'; -export class NotificationItem +export class NotificationBubbleItem { private static ITEM_ID: number = -1; @@ -10,11 +10,11 @@ export class NotificationItem private _iconUrl: string; private _linkUrl: string; - constructor(message: string, notificationType: string = NotificationType.INFO, iconUrl: string = null, linkUrl: string = null) + constructor(message: string, notificationType: string = NotificationBubbleType.INFO, iconUrl: string = null, linkUrl: string = null) { - NotificationItem.ITEM_ID += 1; + NotificationBubbleItem.ITEM_ID += 1; - this._id = NotificationItem.ITEM_ID; + this._id = NotificationBubbleItem.ITEM_ID; this._message = message; this._notificationType = notificationType; this._iconUrl = iconUrl; diff --git a/src/views/notification-center/common/NotificationType.ts b/src/views/notification-center/common/NotificationBubbleType.ts similarity index 95% rename from src/views/notification-center/common/NotificationType.ts rename to src/views/notification-center/common/NotificationBubbleType.ts index dff016d8..cce38f5b 100644 --- a/src/views/notification-center/common/NotificationType.ts +++ b/src/views/notification-center/common/NotificationBubbleType.ts @@ -1,4 +1,4 @@ -export class NotificationType +export class NotificationBubbleType { public static FRIENDOFFLINE: string = 'friendoffline'; public static FRIENDONLINE: string = 'friendonline'; diff --git a/src/views/notification-center/common/NotificationUtilities.ts b/src/views/notification-center/common/NotificationUtilities.ts index a80247b4..c4dd1bd9 100644 --- a/src/views/notification-center/common/NotificationUtilities.ts +++ b/src/views/notification-center/common/NotificationUtilities.ts @@ -1,10 +1,11 @@ import { HabboWebTools, RoomEnterEffect } from '@nitrots/nitro-renderer'; import { CreateLinkEvent, GetConfiguration, GetNitroInstance, LocalizeText } from '../../../api'; -import { SimpleAlertUIEvent } from '../../../events'; +import { NotificationAlertEvent } from '../../../events'; import { NotificationBubbleEvent } from '../../../events/notification-center/NotificationBubbleEvent'; import { dispatchUiEvent } from '../../../hooks'; import { CatalogPageName } from '../../catalog/common/CatalogPageName'; -import { NotificationType } from './NotificationType'; +import { NotificationAlertType } from './NotificationAlertType'; +import { NotificationBubbleType } from './NotificationBubbleType'; export class NotificationUtilities { @@ -12,6 +13,8 @@ export class NotificationUtilities private static MODERATION_DISCLAIMER_DELAY_MS: number = 5000; private static MODERATION_DISCLAIMER_TIMEOUT: ReturnType = null; + public static BUBBLES_DISABLED: boolean = false; + private static cleanText(text: string): string { return text.replace(/\\r/g, '\r') @@ -68,62 +71,92 @@ export class NotificationUtilities const configuration = this.getNotificationConfig(('notification.' + type)); - if(configuration) - { - for(const key in configuration) options.set(key, configuration[key]); - } + if(configuration) for(const key in configuration) options.set(key, configuration[key]); console.log(options); + const title = this.getNotificationPart(options, type, 'title', true); + const message = this.getNotificationPart(options, type, 'message', true).replace(/\\r/g, '\r'); + const linkTitle = this.getNotificationPart(options, type, 'linkTitle', false); + const linkUrl = this.getNotificationPart(options, type, 'linkUrl', false); + const image = this.getNotificationImageUrl(options, type); + if(options.get('display') === 'BUBBLE') { - const message = this.getNotificationPart(options, type, 'message', true); - const linkUrl = this.getNotificationPart(options, type, 'linkUrl', false); - const isEventLink = (linkUrl && linkUrl.substr(0, 6) === 'event'); - const image = this.getNotificationImageUrl(options, type); - - dispatchUiEvent(new NotificationBubbleEvent(LocalizeText(message), NotificationType.INFO, LocalizeText(image), (isEventLink ? linkUrl.substr(6) : linkUrl))); + this.showSingleBubble(LocalizeText(message), NotificationBubbleType.INFO, LocalizeText(image), linkUrl); } else { - + this.simpleAlert(message, NotificationAlertType.EVENT, linkUrl, linkTitle, title, image); } } public static showSingleBubble(message: string, type: string, imageUrl: string = null, internalLink: string = null): void { + if(this.BUBBLES_DISABLED) return; + dispatchUiEvent(new NotificationBubbleEvent(message, type, imageUrl, internalLink)); } - public static simpleAlert(message: string, clickUrl: string = null, clickUrlText: string = null, title: string = null, imageUrl: string = null): void - { - if(!title || !title.length) title = LocalizeText('notifications.broadcast.title'); - - dispatchUiEvent(new SimpleAlertUIEvent(message, clickUrl, clickUrlText, title, imageUrl)); - } - - public static alert(title: string, message: string): void - { - dispatchUiEvent(new SimpleAlertUIEvent(message, null, null, title, null)); - } - public static showClubGiftNotification(numGifts: number): void { if(numGifts <= 0) return; - dispatchUiEvent(new NotificationBubbleEvent(numGifts.toString(), NotificationType.CLUBGIFT, null, 'catalog/open/' + CatalogPageName.CLUB_GIFTS)); + this.showSingleBubble(numGifts.toString(), NotificationBubbleType.CLUBGIFT, null, ('catalog/open/' + CatalogPageName.CLUB_GIFTS)); } - public static showModeratorMessage(message: string, url: string = null): void + public static handleMOTD(messages: string[]): void { - this.simpleAlert(this.cleanText(message), url, LocalizeText('mod.alert.link'), LocalizeText('mod.alert.title')); + messages = messages.map(message => this.cleanText(message)); + + dispatchUiEvent(new NotificationAlertEvent(messages, NotificationAlertType.MOTD, null, null, LocalizeText('notifications.motd.title'))); + } + + public static simpleAlert(message: string, type: string, clickUrl: string = null, clickUrlText: string = null, title: string = null, imageUrl: string = null): void + { + if(!title || !title.length) title = LocalizeText('notifications.broadcast.title'); + + dispatchUiEvent(new NotificationAlertEvent([ this.cleanText(message) ], type, clickUrl, clickUrlText, title, imageUrl)); + } + + public static showModeratorMessage(message: string, url: string = null, showHabboWay: boolean = true): void + { + this.simpleAlert(message, NotificationAlertType.MODERATION, url, LocalizeText('mod.alert.link'), LocalizeText('mod.alert.title')); + } + + public static handleModeratorCaution(message: string, url: string = null): void + { + this.showModeratorMessage(message, url); + } + + public static handleModeratorMessage(message: string, url: string = null): void + { + this.showModeratorMessage(message, url, false); + } + + public static handleUserBannedMessage(message: string): void + { + this.showModeratorMessage(message); } public static handleHotelClosedMessage(open: number, minute: number, thrownOut: boolean): void { - const text: string = LocalizeText(('opening.hours.' + (thrownOut ? 'disconnected' : 'closed')), [ 'h', 'm'], [ this.getTimeZeroPadded(open), this.getTimeZeroPadded(minute) ]);; + this.simpleAlert( LocalizeText(('opening.hours.' + (thrownOut ? 'disconnected' : 'closed')), [ 'h', 'm'], [ this.getTimeZeroPadded(open), this.getTimeZeroPadded(minute) ]), NotificationAlertType.DEFAULT, null, null, LocalizeText('opening.hours.title')); + } - this.alert(LocalizeText('opening.hours.title'), text); + public static handleHotelMaintenanceMessage(minutesUntilMaintenance: number, duration: number): void + { + this.simpleAlert(LocalizeText('maintenance.shutdown', [ 'm', 'd' ], [ minutesUntilMaintenance.toString(), duration.toString() ]), NotificationAlertType.DEFAULT, null, null, LocalizeText('opening.hours.title')); + } + + public static handleHotelClosingMessage(minutes: number): void + { + this.simpleAlert(LocalizeText('opening.hours.shutdown', [ 'm' ], [ minutes.toString() ]), NotificationAlertType.DEFAULT, null, null, LocalizeText('opening.hours.title')); + } + + public static handleLoginFailedHotelClosedMessage(openHour: number, openMinutes: number): void + { + this.simpleAlert(LocalizeText('opening.hours.disconnected', [ 'h', 'm' ], [ openHour.toString(), openMinutes.toString() ]), NotificationAlertType.DEFAULT, null, null, LocalizeText('opening.hours.title')); } public static openUrl(url: string): void @@ -134,7 +167,7 @@ export class NotificationUtilities } else { - CreateLinkEvent(url); + CreateLinkEvent(url.substring(6)); } } @@ -153,7 +186,7 @@ export class NotificationUtilities { if(this.MODERATION_DISCLAIMER_SHOWN) return; - this.showSingleBubble(LocalizeText('mod.chatdisclaimer'), NotificationType.INFO); + this.showSingleBubble(LocalizeText('mod.chatdisclaimer'), NotificationBubbleType.INFO); this.MODERATION_DISCLAIMER_SHOWN = true; } diff --git a/src/views/notification-center/common/ProductImageUtility.ts b/src/views/notification-center/common/ProductImageUtility.ts new file mode 100644 index 00000000..9078754c --- /dev/null +++ b/src/views/notification-center/common/ProductImageUtility.ts @@ -0,0 +1,59 @@ +import { CatalogPageMessageProductData } from '@nitrots/nitro-renderer'; +import { GetRoomEngine } from '../../../api'; +import { FurniCategory } from '../../catalog/common/FurniCategory'; + +export class ProductImageUtility +{ + public static getProductImageUrl(productType: string, furniClassId: number, extraParam: string): string + { + let imageUrl: string = null; + + switch(productType) + { + case CatalogPageMessageProductData.S: + imageUrl = GetRoomEngine().getFurnitureFloorIconUrl(furniClassId); + break; + case CatalogPageMessageProductData.I: + const productCategory = this.getProductCategory(CatalogPageMessageProductData.I, furniClassId); + + if(productCategory === 1) + { + imageUrl = GetRoomEngine().getFurnitureWallIconUrl(furniClassId, extraParam); + } + else + { + switch(productCategory) + { + case FurniCategory.WALL_PAPER: + break; + case FurniCategory.LANDSCAPE: + break; + case FurniCategory.FLOOR: + break; + } + } + break; + case CatalogPageMessageProductData.E: + // fx_icon_furniClassId_png + break; + } + + return imageUrl; + } + + private static getProductCategory(productType: string, furniClassId: number): number + { + if(productType === CatalogPageMessageProductData.S) return 1; + + if(productType === CatalogPageMessageProductData.I) + { + if(furniClassId === 3001) return FurniCategory.WALL_PAPER; + + if(furniClassId === 3002) return FurniCategory.FLOOR; + + if(furniClassId === 4057) return FurniCategory.LANDSCAPE; + } + + return 1; + } +} diff --git a/src/views/notification-center/context/NotificationCenterContext.tsx b/src/views/notification-center/context/NotificationCenterContext.tsx deleted file mode 100644 index 036cd97b..00000000 --- a/src/views/notification-center/context/NotificationCenterContext.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { createContext, FC, useContext } from 'react'; -import { INotificationCenterContext, NotificationCenterContextProps } from './NotificationCenterContext.types'; - -const NotificationCenterContext = createContext({ - notificationCenterState: null, - dispatchNotificationCenterState: null -}); - -export const NotificationCenterContextProvider: FC = props => -{ - return { props.children } -} - -export const useNotificationCenterContext = () => useContext(NotificationCenterContext); diff --git a/src/views/notification-center/context/NotificationCenterContext.types.ts b/src/views/notification-center/context/NotificationCenterContext.types.ts deleted file mode 100644 index 8e5358f4..00000000 --- a/src/views/notification-center/context/NotificationCenterContext.types.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Dispatch, ProviderProps } from 'react'; -import { INotificationCenterAction, INotificationCenterState } from '../reducers/NotificationCenterReducer'; - -export interface INotificationCenterContext -{ - notificationCenterState: INotificationCenterState; - dispatchNotificationCenterState: Dispatch; -} - -export interface NotificationCenterContextProps extends ProviderProps -{ - -} diff --git a/src/views/notification-center/reducers/NotificationCenterReducer.tsx b/src/views/notification-center/reducers/NotificationCenterReducer.tsx deleted file mode 100644 index 8d861033..00000000 --- a/src/views/notification-center/reducers/NotificationCenterReducer.tsx +++ /dev/null @@ -1,77 +0,0 @@ -import { Reducer } from 'react'; -import { NitroNotification } from '../common/Notification'; - -export interface INotificationCenterState -{ - notifications: NitroNotification[]; -} - -export interface INotificationCenterAction -{ - type: string; - payload: { - id?: number; - notification?: NitroNotification; - }; -} - -export class NotificationCenterActions -{ - public static ADD_NOTIFICATION: string = 'NCA_ADD_NOTIFICATION'; - public static REMOVE_NOTIFICATION: string = 'NCA_REMOVE_NOTIFICATION'; - public static DISMISS_NOTIFICATION: string = 'NCA_DISMISS_NOTIFICATION'; -} - -export const initialNotificationCenter: INotificationCenterState = { - notifications: [] -} - -export const NotificationCenterReducer: Reducer = (state, action) => -{ - switch(action.type) - { - case NotificationCenterActions.ADD_NOTIFICATION: { - const notification = (action.payload.notification || null); - - if(!notification) return state; - - const notifications = [ ...state.notifications, notification ]; - - return { ...state, notifications }; - } - case NotificationCenterActions.REMOVE_NOTIFICATION: { - const id = (action.payload.id || null); - - if(!id) return state; - - if(!state.notifications) return state; - - const notifications = Array.from(state.notifications); - const notificationIndex = notifications.findIndex(notification => notification.id === id); - - if(notificationIndex === -1) return state; - - notifications.splice(notificationIndex, 1); - - return { ...state, notifications }; - } - case NotificationCenterActions.DISMISS_NOTIFICATION: { - const id = (action.payload.id || null); - - if(!id) return state; - - if(!state.notifications) return state; - - const notifications = Array.from(state.notifications); - const notificationIndex = notifications.findIndex(notification => notification.id === id); - - if(notificationIndex === -1) return state; - - notifications[notificationIndex].dismiss(); - - return { ...state, notifications }; - } - default: - return state; - } -} diff --git a/src/views/notification-center/views/alert-base/NotificationCenterAlertBase.tsx b/src/views/notification-center/views/alert-base/NotificationCenterAlertBase.tsx deleted file mode 100644 index e071e39b..00000000 --- a/src/views/notification-center/views/alert-base/NotificationCenterAlertBase.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { FC } from 'react'; -import { LocalizeText } from '../../../../api'; -import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout'; -import { NotificationCenterAlertBaseProps } from './NotificationCenterAlertBase.types'; - - -export const NotificationCenterAlertBase: FC = props => -{ - const { headerText = LocalizeText('mod.alert.title'), onClose = null, children = null } = props; - - return ( - - - - { children } - - - ); -} diff --git a/src/views/notification-center/views/alert-base/NotificationCenterAlertBase.types.ts b/src/views/notification-center/views/alert-base/NotificationCenterAlertBase.types.ts deleted file mode 100644 index e7c08d27..00000000 --- a/src/views/notification-center/views/alert-base/NotificationCenterAlertBase.types.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface NotificationCenterAlertBaseProps -{ - headerText?: string; - onClose: () => void; -} diff --git a/src/views/notification-center/views/alert-layouts/GetAlertLayout.tsx b/src/views/notification-center/views/alert-layouts/GetAlertLayout.tsx new file mode 100644 index 00000000..fb774c6e --- /dev/null +++ b/src/views/notification-center/views/alert-layouts/GetAlertLayout.tsx @@ -0,0 +1,19 @@ +import { NotificationAlertItem } from '../../common/NotificationAlertItem'; +import { NotificationAlertType } from '../../common/NotificationAlertType'; +import { NotificationDefaultAlertView } from './default/NotificationDefaultAlertView'; +import { NotificationEventAlertView } from './event/NotificationEventAlertView'; + +export const GetAlertLayout = (item: NotificationAlertItem, close: () => void) => +{ + if(!item) return null; + + const props = { key: item.id, item, close }; + + switch(item.alertType) + { + case NotificationAlertType.EVENT: + return + default: + return + } +} diff --git a/src/views/notification-center/views/alert-layouts/NotificationAlertLayoutView.types.ts b/src/views/notification-center/views/alert-layouts/NotificationAlertLayoutView.types.ts new file mode 100644 index 00000000..57c77873 --- /dev/null +++ b/src/views/notification-center/views/alert-layouts/NotificationAlertLayoutView.types.ts @@ -0,0 +1,7 @@ +import { NotificationAlertItem } from '../../common/NotificationAlertItem'; + +export interface NotificationAlertLayoutViewProps +{ + item: NotificationAlertItem; + close: () => void; +} diff --git a/src/views/notification-center/views/alert-layouts/default/NotificationDefaultAlertView.tsx b/src/views/notification-center/views/alert-layouts/default/NotificationDefaultAlertView.tsx new file mode 100644 index 00000000..5b567410 --- /dev/null +++ b/src/views/notification-center/views/alert-layouts/default/NotificationDefaultAlertView.tsx @@ -0,0 +1,35 @@ +import { FC, useCallback } from 'react'; +import { LocalizeText } from '../../../../../api'; +import { NotificationAlertView } from '../../../../../layout'; +import { NotificationUtilities } from '../../../common/NotificationUtilities'; +import { NotificationDefaultAlertViewProps } from './NotificationDefaultAlertView.types'; + +export const NotificationDefaultAlertView: FC = props => +{ + const { item = null, close = null, ...rest } = props; + + const visitUrl = useCallback(() => + { + NotificationUtilities.openUrl(item.clickUrl); + + close(); + }, [ item, close ]); + + return ( + + { (item.messages.length > 0) && item.messages.map((message, index) => + { + const htmlText = message.replace(/\r\n|\r|\n/g, '
'); + + return ( +
+ ); + }) } +
+ +
+ { item.clickUrl && item.clickUrl.length && + } + + ); +} diff --git a/src/views/notification-center/views/alert-layouts/default/NotificationDefaultAlertView.types.ts b/src/views/notification-center/views/alert-layouts/default/NotificationDefaultAlertView.types.ts new file mode 100644 index 00000000..287d8ca3 --- /dev/null +++ b/src/views/notification-center/views/alert-layouts/default/NotificationDefaultAlertView.types.ts @@ -0,0 +1,7 @@ +import { DetailsHTMLAttributes } from 'react'; +import { NotificationAlertLayoutViewProps } from '../NotificationAlertLayoutView.types'; + +export interface NotificationDefaultAlertViewProps extends NotificationAlertLayoutViewProps, DetailsHTMLAttributes +{ + +} diff --git a/src/views/notification-center/views/alert-layouts/event/NotificationEventAlertView.tsx b/src/views/notification-center/views/alert-layouts/event/NotificationEventAlertView.tsx new file mode 100644 index 00000000..8910e22e --- /dev/null +++ b/src/views/notification-center/views/alert-layouts/event/NotificationEventAlertView.tsx @@ -0,0 +1,33 @@ +import { FC, useCallback } from 'react'; +import { LocalizeText } from '../../../../../api'; +import { NotificationAlertView } from '../../../../../layout'; +import { NotificationUtilities } from '../../../common/NotificationUtilities'; +import { NotificationEventAlertViewProps } from './NotificationEventAlertView.types'; + +export const NotificationEventAlertView: FC = props => +{ + const { item = null, close = null, ...rest } = props; + + const visitUrl = useCallback(() => + { + NotificationUtilities.openUrl(item.clickUrl); + + close(); + }, [ item, close ]); + + return ( + + { (item.messages.length > 0) && item.messages.map((message, index) => + { + const htmlText = message.replace(/\r\n|\r|\n/g, '
'); + + return ( +
+ ); + }) } +
+ +
+ + ); +} diff --git a/src/views/notification-center/views/alert-layouts/event/NotificationEventAlertView.types.ts b/src/views/notification-center/views/alert-layouts/event/NotificationEventAlertView.types.ts new file mode 100644 index 00000000..1d8b2906 --- /dev/null +++ b/src/views/notification-center/views/alert-layouts/event/NotificationEventAlertView.types.ts @@ -0,0 +1,7 @@ +import { DetailsHTMLAttributes } from 'react'; +import { NotificationAlertLayoutViewProps } from '../NotificationAlertLayoutView.types'; + +export interface NotificationEventAlertViewProps extends NotificationAlertLayoutViewProps, DetailsHTMLAttributes +{ + +} diff --git a/src/views/notification-center/views/broadcast-message/NotificationCenterBroadcastMessageView.tsx b/src/views/notification-center/views/broadcast-message/NotificationCenterBroadcastMessageView.tsx deleted file mode 100644 index 04908525..00000000 --- a/src/views/notification-center/views/broadcast-message/NotificationCenterBroadcastMessageView.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import { FC, useMemo } from 'react'; -import { LocalizeText } from '../../../../api'; -import { NotificationCenterAlertBase } from '../alert-base/NotificationCenterAlertBase'; -import { NotificationCenterBroadcastMessageViewProps } from './NotificationCenterBroadcastMessageView.types'; - -export const NotificationCenterBroadcastMessageView: FC = props => -{ - const { notification = null, onClose = null } = props; - - const message = useMemo(() => - { - let finalMessage = ''; - - notification.message.forEach(message => - { - finalMessage += message.replace(/\r\n|\r|\n/g, '
'); - }); - - return finalMessage; - }, [ notification ]); - - return ( - -
-
- -
- - ); -}; diff --git a/src/views/notification-center/views/broadcast-message/NotificationCenterBroadcastMessageView.types.ts b/src/views/notification-center/views/broadcast-message/NotificationCenterBroadcastMessageView.types.ts deleted file mode 100644 index bd89dd38..00000000 --- a/src/views/notification-center/views/broadcast-message/NotificationCenterBroadcastMessageView.types.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { NotificationCenterAlertEvent } from '../../../../events'; - -export class NotificationCenterBroadcastMessageViewProps -{ - notification: NotificationCenterAlertEvent; - onClose: () => void; -} diff --git a/src/views/notification-center/views/bubble-layouts/GetBubbleLayout.tsx b/src/views/notification-center/views/bubble-layouts/GetBubbleLayout.tsx index 08492b92..4426df56 100644 --- a/src/views/notification-center/views/bubble-layouts/GetBubbleLayout.tsx +++ b/src/views/notification-center/views/bubble-layouts/GetBubbleLayout.tsx @@ -1,9 +1,9 @@ -import { NotificationItem } from '../../common/NotificationItem'; -import { NotificationType } from '../../common/NotificationType'; +import { NotificationBubbleItem } from '../../common/NotificationBubbleItem'; +import { NotificationBubbleType } from '../../common/NotificationBubbleType'; import { NotificationClubGiftBubbleView } from './club-gift/NotificationClubGiftBubbleView'; import { NotificationDefaultBubbleView } from './default/NotificationDefaultBubbleView'; -export const GetBubbleLayout = (item: NotificationItem, close: () => void) => +export const GetBubbleLayout = (item: NotificationBubbleItem, close: () => void) => { if(!item) return null; @@ -11,7 +11,7 @@ export const GetBubbleLayout = (item: NotificationItem, close: () => void) => switch(item.notificationType) { - case NotificationType.CLUBGIFT: + case NotificationBubbleType.CLUBGIFT: return default: return diff --git a/src/views/notification-center/views/bubble-layouts/NotificationBubbleLayoutView.types.ts b/src/views/notification-center/views/bubble-layouts/NotificationBubbleLayoutView.types.ts index ca1fd341..5f9c81d6 100644 --- a/src/views/notification-center/views/bubble-layouts/NotificationBubbleLayoutView.types.ts +++ b/src/views/notification-center/views/bubble-layouts/NotificationBubbleLayoutView.types.ts @@ -1,7 +1,7 @@ -import { NotificationItem } from '../../common/NotificationItem'; +import { NotificationBubbleItem } from '../../common/NotificationBubbleItem'; export interface NotificationBubbleLayoutViewProps { - item: NotificationItem; + item: NotificationBubbleItem; close: () => void; } diff --git a/src/views/notification-center/views/hotel-will-shutdown/HotelWillShutdownView.tsx b/src/views/notification-center/views/hotel-will-shutdown/HotelWillShutdownView.tsx deleted file mode 100644 index 650de0e4..00000000 --- a/src/views/notification-center/views/hotel-will-shutdown/HotelWillShutdownView.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { FC } from 'react'; -import { LocalizeText } from '../../../../api'; -import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout'; -import { NotificationTrayItemView } from '../tray-item/NotificationTrayItemView'; -import { HotelWillShutdownViewProps } from './HotelWillShutdownView.types'; - -export const HotelWillShutdownView: FC = props => -{ - const { notification = null, inTray = null, onButtonClick = null } = props; - - if(!notification) return null; - - const content = <>{ LocalizeText('opening.hours.shutdown', ['m'], [notification.minutes.toString()]) }; - - if(inTray) - return ( - onButtonClick('remove_notification') } /> - ); - - return ( - - onButtonClick('dismiss_notification') } /> - - { content } - - - ); -}; diff --git a/src/views/notification-center/views/hotel-will-shutdown/HotelWillShutdownView.types.ts b/src/views/notification-center/views/hotel-will-shutdown/HotelWillShutdownView.types.ts deleted file mode 100644 index 89915153..00000000 --- a/src/views/notification-center/views/hotel-will-shutdown/HotelWillShutdownView.types.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { HotelWillShutdownNotification } from '../../common/HotelWillShutdownNotification'; -import { NotificationViewProps } from '../../NotificationCenterView.types'; - -export class HotelWillShutdownViewProps extends NotificationViewProps -{ - notification: HotelWillShutdownNotification; -} diff --git a/src/views/notification-center/views/moderator-message/ModeratorMessageView.tsx b/src/views/notification-center/views/moderator-message/ModeratorMessageView.tsx deleted file mode 100644 index 341d31ea..00000000 --- a/src/views/notification-center/views/moderator-message/ModeratorMessageView.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { FC } from 'react'; -import { LocalizeText } from '../../../../api'; -import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout'; -import { NotificationTrayItemView } from '../tray-item/NotificationTrayItemView'; -import { ModeratorMessageViewProps } from './ModeratorMessageView.types'; - -export const ModeratorMessageView: FC = props => -{ - const { notification = null, inTray = null, onButtonClick = null } = props; - - if(!notification) return null; - - const content = <> -
- - ; - - if(inTray) - return ( - onButtonClick('remove_notification') } /> - ); - - return ( - - onButtonClick('dismiss_notification') } /> - - { content } - - - ); -}; diff --git a/src/views/notification-center/views/moderator-message/ModeratorMessageView.types.ts b/src/views/notification-center/views/moderator-message/ModeratorMessageView.types.ts deleted file mode 100644 index 2e7c63de..00000000 --- a/src/views/notification-center/views/moderator-message/ModeratorMessageView.types.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { ModeratorMessageNotification } from '../../common/ModeratorMessageNotification'; -import { NotificationViewProps } from '../../NotificationCenterView.types'; - -export class ModeratorMessageViewProps extends NotificationViewProps -{ - notification: ModeratorMessageNotification; -} diff --git a/src/views/notification-center/views/motd/NotificationCenterMotdView.tsx b/src/views/notification-center/views/motd/NotificationCenterMotdView.tsx deleted file mode 100644 index 1039f298..00000000 --- a/src/views/notification-center/views/motd/NotificationCenterMotdView.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { FC } from 'react'; -import { NotificationCenterBroadcastMessageView } from '../broadcast-message/NotificationCenterBroadcastMessageView'; -import { NotificationCenterMotdViewProps } from './NotificationCenterMotdView.types'; - -export const NotificationCenterMotdView: FC = props => -{ - const { notification = null, onClose = null } = props; - - return ; -} diff --git a/src/views/notification-center/views/motd/NotificationCenterMotdView.types.ts b/src/views/notification-center/views/motd/NotificationCenterMotdView.types.ts deleted file mode 100644 index 921e8634..00000000 --- a/src/views/notification-center/views/motd/NotificationCenterMotdView.types.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { NotificationCenterAlertEvent } from '../../../../events'; - -export interface NotificationCenterMotdViewProps -{ - notification: NotificationCenterAlertEvent; - onClose: () => void; -} diff --git a/src/views/notification-center/views/tray-item/NotificationTrayItemView.tsx b/src/views/notification-center/views/tray-item/NotificationTrayItemView.tsx deleted file mode 100644 index cc836c6a..00000000 --- a/src/views/notification-center/views/tray-item/NotificationTrayItemView.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { FC } from 'react'; -import { NotificationTrayItemViewProps } from './NotificationTrayItemView.types'; - -export const NotificationTrayItemView: FC = props => -{ - const { title = null, content = null, timestamp = null, onCloseClick = null } = props; - - return ( -
-
-
{ title }
- -
-
- { content } -
-
- { timestamp } -
-
- ); -}; diff --git a/src/views/notification-center/views/tray-item/NotificationTrayItemView.types.ts b/src/views/notification-center/views/tray-item/NotificationTrayItemView.types.ts deleted file mode 100644 index c84e1793..00000000 --- a/src/views/notification-center/views/tray-item/NotificationTrayItemView.types.ts +++ /dev/null @@ -1,7 +0,0 @@ -export class NotificationTrayItemViewProps -{ - title: string; - content: any; - timestamp: number; - onCloseClick: () => void; -} From 9e3dcc2271dc72ccb406e5c73eecd8acc92b094b Mon Sep 17 00:00:00 2001 From: MyNameIsBatman Date: Sat, 18 Sep 2021 14:37:14 -0300 Subject: [PATCH 12/31] Achievements updates --- src/views/achievements/AchievementsView.scss | 29 ++++++++++++++----- src/views/achievements/AchievementsView.tsx | 2 +- .../AchievementCategoryListItemView.tsx | 11 ++++--- .../category-list/AchievementsListView.tsx | 7 ++--- .../category/AchievementCategoryView.tsx | 16 ++++++---- 5 files changed, 43 insertions(+), 22 deletions(-) diff --git a/src/views/achievements/AchievementsView.scss b/src/views/achievements/AchievementsView.scss index 00014327..fa6343fb 100644 --- a/src/views/achievements/AchievementsView.scss +++ b/src/views/achievements/AchievementsView.scss @@ -1,24 +1,28 @@ .nitro-achievements { width: 650px; - - .content-area { - min-height: 376px; - height: 376px; - } - + .score { border-color: $grid-border-color !important; background-color: $grid-bg-color; } .category { + border-color: $grid-border-color !important; + background-color: $grid-bg-color; + cursor: pointer; + + &.active { + border-color: $grid-active-border-color !important; + background-color: $grid-active-bg-color; + } + .category-score { margin-top: 43.5px; } } .achievements { - height: 230px; + height: 152px; overflow-y: auto; overflow-x: hidden; @@ -44,4 +48,15 @@ } } } + + .achievement-image { + height: 80px; + width: 80px; + + .badge-image { + width: 80px; + height: 80px; + background-size: contain; + } + } } diff --git a/src/views/achievements/AchievementsView.tsx b/src/views/achievements/AchievementsView.tsx index 38cdcf6c..48bb619b 100644 --- a/src/views/achievements/AchievementsView.tsx +++ b/src/views/achievements/AchievementsView.tsx @@ -40,7 +40,7 @@ export const AchievementsView: FC = props => { isVisible && - + setIsVisible(false) } />
diff --git a/src/views/achievements/views/category-list-item/AchievementCategoryListItemView.tsx b/src/views/achievements/views/category-list-item/AchievementCategoryListItemView.tsx index 21ebb6a7..ddc6ed24 100644 --- a/src/views/achievements/views/category-list-item/AchievementCategoryListItemView.tsx +++ b/src/views/achievements/views/category-list-item/AchievementCategoryListItemView.tsx @@ -1,6 +1,6 @@ +import classNames from 'classnames'; import { FC, useCallback, useMemo } from 'react'; import { GetConfiguration } from '../../../../api'; -import { NitroCardGridItemView } from '../../../../layout/card/grid/item/NitroCardGridItemView'; import { useAchievementsContext } from '../../context/AchievementsContext'; import { AchievementsActions } from '../../reducers/AchievementsReducer'; import { AchievementCategoryListItemViewProps } from './AchievementCategoryListItemView.types'; @@ -58,8 +58,11 @@ export const AchievementCategoryListItemView: FC selectCategory(category.name) }> -
{ getCategoryProgress }
- +
+
selectCategory(category.name) }> + +
{ getCategoryProgress }
+
+
); } diff --git a/src/views/achievements/views/category-list/AchievementsListView.tsx b/src/views/achievements/views/category-list/AchievementsListView.tsx index 216a3c3c..2ca173c7 100644 --- a/src/views/achievements/views/category-list/AchievementsListView.tsx +++ b/src/views/achievements/views/category-list/AchievementsListView.tsx @@ -1,5 +1,4 @@ import { FC } from 'react'; -import { NitroCardGridView } from '../../../../layout/card/grid/NitroCardGridView'; import { useAchievementsContext } from '../../context/AchievementsContext'; import { AchievementCategoryListItemView } from '../category-list-item/AchievementCategoryListItemView'; @@ -9,11 +8,11 @@ export const AchievementsListView: FC<{}> = props => const { categories = null, selectedCategoryName = null } = achievementsState; return ( - +
{ categories && categories.map((category, index) => { - return ; + return ; }) } - +
); }; diff --git a/src/views/achievements/views/category/AchievementCategoryView.tsx b/src/views/achievements/views/category/AchievementCategoryView.tsx index 050d6a64..8d59bba5 100644 --- a/src/views/achievements/views/category/AchievementCategoryView.tsx +++ b/src/views/achievements/views/category/AchievementCategoryView.tsx @@ -1,7 +1,7 @@ import { AchievementData } from '@nitrots/nitro-renderer'; import classNames from 'classnames'; -import { FC, useCallback } from 'react'; -import { LocalizeText } from '../../../../api'; +import { FC, useCallback, useMemo } from 'react'; +import { LocalizeBadgeDescription, LocalizeBadgeName, LocalizeText } from '../../../../api'; import { BadgeImageView } from '../../../shared/badge-image/BadgeImageView'; import { useAchievementsContext } from '../../context/AchievementsContext'; import { AchievementsActions } from '../../reducers/AchievementsReducer'; @@ -34,7 +34,7 @@ export const AchievementCategoryView: FC = props = return badgeId; }, []); - const getSelectedAchievement = useCallback(() => + const selectedAchievement = useMemo(() => { if(!getSelectedCategory()) return null; @@ -54,13 +54,17 @@ export const AchievementCategoryView: FC = props = return (
-
+
{ LocalizeText('quests.' + selectedCategoryName + '.name') }
IMAGE
-
+
+
+ +
- +
{ LocalizeBadgeName(selectedAchievement.badgeId) }
+
{ LocalizeBadgeDescription(selectedAchievement.badgeId) }
From e0b7acd3686e0ad60f8b739ec56cd96d8cce931e Mon Sep 17 00:00:00 2001 From: MyNameIsBatman Date: Sun, 19 Sep 2021 17:56:46 -0300 Subject: [PATCH 13/31] Fix Achievements (shut up harmony) --- src/views/achievements/reducers/AchievementsReducer.tsx | 6 ++++-- .../achievements/views/category/AchievementCategoryView.tsx | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/views/achievements/reducers/AchievementsReducer.tsx b/src/views/achievements/reducers/AchievementsReducer.tsx index 460d998a..8ae9f004 100644 --- a/src/views/achievements/reducers/AchievementsReducer.tsx +++ b/src/views/achievements/reducers/AchievementsReducer.tsx @@ -43,13 +43,15 @@ export const AchievementsReducer: Reducer 0) { - selectedCategoryName = categories[0].name; + selectedCategoryName = categories[0].name; + selectedAchievementId = categories[0].achievements[0].achievementId; } - return { ...state, categories, selectedCategoryName }; + return { ...state, categories, selectedCategoryName, selectedAchievementId }; } case AchievementsActions.SET_SCORE: { const score = (action.payload.score || state.score || null); diff --git a/src/views/achievements/views/category/AchievementCategoryView.tsx b/src/views/achievements/views/category/AchievementCategoryView.tsx index 8d59bba5..879c4d84 100644 --- a/src/views/achievements/views/category/AchievementCategoryView.tsx +++ b/src/views/achievements/views/category/AchievementCategoryView.tsx @@ -58,7 +58,7 @@ export const AchievementCategoryView: FC = props =
{ LocalizeText('quests.' + selectedCategoryName + '.name') }
IMAGE
-
+ { selectedAchievement &&
@@ -66,7 +66,7 @@ export const AchievementCategoryView: FC = props =
{ LocalizeBadgeName(selectedAchievement.badgeId) }
{ LocalizeBadgeDescription(selectedAchievement.badgeId) }
-
+
}
{ getSelectedCategory().achievements.map((achievement, index) => From d5e6a79c8a0f9be2602407e3a65f95473f43b134 Mon Sep 17 00:00:00 2001 From: MyNameIsBatman Date: Sun, 19 Sep 2021 18:01:27 -0300 Subject: [PATCH 14/31] Extra check to Achievements --- src/views/achievements/reducers/AchievementsReducer.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/views/achievements/reducers/AchievementsReducer.tsx b/src/views/achievements/reducers/AchievementsReducer.tsx index 8ae9f004..6f8e2b11 100644 --- a/src/views/achievements/reducers/AchievementsReducer.tsx +++ b/src/views/achievements/reducers/AchievementsReducer.tsx @@ -48,7 +48,8 @@ export const AchievementsReducer: Reducer 0) { selectedCategoryName = categories[0].name; - selectedAchievementId = categories[0].achievements[0].achievementId; + + if(categories[0].achievements.length > 0) selectedAchievementId = categories[0].achievements[0].achievementId; } return { ...state, categories, selectedCategoryName, selectedAchievementId }; From e97f18c53c8d56bc06ec1750c5b4b049294d7d49 Mon Sep 17 00:00:00 2001 From: Bill Date: Mon, 20 Sep 2021 04:17:38 -0400 Subject: [PATCH 15/31] Update craco config --- craco.config.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/craco.config.js b/craco.config.js index 661daecc..4f5320a4 100644 --- a/craco.config.js +++ b/craco.config.js @@ -5,6 +5,23 @@ module.exports = { webpack: { configure: (webpackConfig) => ({ ...webpackConfig, + optimization: { + ...webpackConfig.optimization, + splitChunks: { + cacheGroups: { + vendor: { + name: 'vendors', + test: /[\\/]node_modules[\\/]/, + chunks: 'all', + }, + renderer: { + name: 'renderer', + test: /[\\/]node_modules[\\/]@nitrots[\\/]nitro-renderer[\\/]/, + chunks: 'all', + } + } + } + }, module: { ...webpackConfig.module, rules: webpackConfig.module.rules.map((rule) => From 6a2821389688f5e75b3ddda2e05811dec2b2fbdb Mon Sep 17 00:00:00 2001 From: Bill Date: Tue, 21 Sep 2021 21:48:00 -0400 Subject: [PATCH 16/31] Messenger updates --- src/api/friends/OpenMessengerChat.ts | 5 +- .../friends/FriendsMessengerIconEvent.ts | 23 ++ src/events/friends/index.ts | 1 + .../card/content/NitroCardContentView.scss | 1 + .../catalog/common/AttemptCatalogPlacement.ts | 30 ++ .../catalog/common/IsCatalogOfferDraggable.ts | 8 + .../views/page/offer/CatalogPageOfferView.tsx | 15 +- .../views/page/product/CatalogProductView.tsx | 2 +- src/views/friends/FriendsMessageHandler.tsx | 23 +- src/views/friends/common/MessengerChat.ts | 49 --- .../common/MessengerChatMessageGroup.ts | 35 -- src/views/friends/common/MessengerThread.ts | 83 ++++ ...rChatMessage.ts => MessengerThreadChat.ts} | 25 +- .../common/MessengerThreadChatGroup.ts | 28 ++ src/views/friends/reducers/FriendsReducer.tsx | 64 +-- .../FriendsMessengerThreadGroup.tsx | 48 +++ .../FriendsMessengerThreadGroup.types.ts | 8 + .../FriendsMessengerThreadView.tsx | 17 + .../FriendsMessengerThreadView.types.ts | 6 + .../views/messenger/FriendsMessengerView.scss | 1 + .../views/messenger/FriendsMessengerView.tsx | 365 ++++++++++-------- .../chat/message/ChatWidgetMessageView.scss | 4 +- .../shared/avatar-image/AvatarImage.scss | 6 + .../shared/avatar-image/AvatarImageView.tsx | 11 +- .../room-previewer/RoomPreviewerView.scss | 1 - src/views/toolbar/ToolbarView.scss | 25 +- src/views/toolbar/ToolbarView.tsx | 48 ++- src/views/toolbar/ToolbarView.types.ts | 1 + tsconfig.json | 2 +- 29 files changed, 569 insertions(+), 366 deletions(-) create mode 100644 src/events/friends/FriendsMessengerIconEvent.ts create mode 100644 src/views/catalog/common/AttemptCatalogPlacement.ts create mode 100644 src/views/catalog/common/IsCatalogOfferDraggable.ts delete mode 100644 src/views/friends/common/MessengerChat.ts delete mode 100644 src/views/friends/common/MessengerChatMessageGroup.ts create mode 100644 src/views/friends/common/MessengerThread.ts rename src/views/friends/common/{MessengerChatMessage.ts => MessengerThreadChat.ts} (51%) create mode 100644 src/views/friends/common/MessengerThreadChatGroup.ts create mode 100644 src/views/friends/views/messenger-thread-group/FriendsMessengerThreadGroup.tsx create mode 100644 src/views/friends/views/messenger-thread-group/FriendsMessengerThreadGroup.types.ts create mode 100644 src/views/friends/views/messenger-thread/FriendsMessengerThreadView.tsx create mode 100644 src/views/friends/views/messenger-thread/FriendsMessengerThreadView.types.ts diff --git a/src/api/friends/OpenMessengerChat.ts b/src/api/friends/OpenMessengerChat.ts index 08520b1b..0b8ab554 100644 --- a/src/api/friends/OpenMessengerChat.ts +++ b/src/api/friends/OpenMessengerChat.ts @@ -1,6 +1,7 @@ import { CreateLinkEvent } from '..'; -export function OpenMessengerChat(friendId: number): void +export function OpenMessengerChat(friendId: number = -1): void { - CreateLinkEvent(`friends/messenger/${friendId}`); + if(friendId === -1) CreateLinkEvent('friends/messenger/open'); + else CreateLinkEvent(`friends/messenger/${friendId}`); } diff --git a/src/events/friends/FriendsMessengerIconEvent.ts b/src/events/friends/FriendsMessengerIconEvent.ts new file mode 100644 index 00000000..602eb726 --- /dev/null +++ b/src/events/friends/FriendsMessengerIconEvent.ts @@ -0,0 +1,23 @@ +import { NitroEvent } from '@nitrots/nitro-renderer'; + +export class FriendsMessengerIconEvent extends NitroEvent +{ + public static UPDATE_ICON: string = 'FMIE_UPDATE_ICON'; + public static HIDE_ICON: number = 0; + public static SHOW_ICON: number = 1; + public static UNREAD_ICON: number = 2; + + private _iconType: number; + + constructor(type: string, subType: number = FriendsMessengerIconEvent.SHOW_ICON) + { + super(type); + + this._iconType = subType; + } + + public get iconType(): number + { + return this._iconType; + } +} diff --git a/src/events/friends/index.ts b/src/events/friends/index.ts index 9a4bb3ed..2f3699c3 100644 --- a/src/events/friends/index.ts +++ b/src/events/friends/index.ts @@ -1,4 +1,5 @@ export * from './FriendEnteredRoomEvent'; export * from './FriendListContentEvent'; export * from './FriendsEvent'; +export * from './FriendsMessengerIconEvent'; export * from './FriendsSendFriendRequestEvent'; diff --git a/src/layout/card/content/NitroCardContentView.scss b/src/layout/card/content/NitroCardContentView.scss index 9ffd6fe9..4cbe6ee3 100644 --- a/src/layout/card/content/NitroCardContentView.scss +++ b/src/layout/card/content/NitroCardContentView.scss @@ -1,4 +1,5 @@ .content-area { + height: 100%; padding-top: $container-padding-x; padding-bottom: $container-padding-x; overflow: auto; diff --git a/src/views/catalog/common/AttemptCatalogPlacement.ts b/src/views/catalog/common/AttemptCatalogPlacement.ts new file mode 100644 index 00000000..af342ee3 --- /dev/null +++ b/src/views/catalog/common/AttemptCatalogPlacement.ts @@ -0,0 +1,30 @@ +import { CatalogPageMessageOfferData, RoomObjectCategory, RoomObjectPlacementSource } from '@nitrots/nitro-renderer'; +import { GetRoomEngine } from '../../../api'; +import { IsCatalogOfferDraggable } from './IsCatalogOfferDraggable'; +import { ProductTypeEnum } from './ProductTypeEnum'; + +export const AttemptCatalogPlacement = (offer: CatalogPageMessageOfferData) => +{ + if(!IsCatalogOfferDraggable(offer)) return; + + const product = offer.products[0]; + + let category: number = -1; + + switch(product.productType) + { + case ProductTypeEnum.FLOOR: + category = RoomObjectCategory.FLOOR; + break; + case ProductTypeEnum.WALL: + category = RoomObjectCategory.WALL; + break; + } + + if(category === -1) return; + + if(GetRoomEngine().processRoomObjectPlacement(RoomObjectPlacementSource.CATALOG, -(offer.offerId), category, product.furniClassId, (product.extraParam) ? product.extraParam.toString() : null)) + { + + } +} diff --git a/src/views/catalog/common/IsCatalogOfferDraggable.ts b/src/views/catalog/common/IsCatalogOfferDraggable.ts new file mode 100644 index 00000000..174ce4d0 --- /dev/null +++ b/src/views/catalog/common/IsCatalogOfferDraggable.ts @@ -0,0 +1,8 @@ +import { CatalogPageMessageOfferData, RoomControllerLevel } from '@nitrots/nitro-renderer'; +import { GetRoomSession } from '../../../api'; +import { ProductTypeEnum } from './ProductTypeEnum'; + +export const IsCatalogOfferDraggable = (offer: CatalogPageMessageOfferData) => +{ + return ((GetRoomSession().isRoomOwner || (GetRoomSession().isGuildRoom && (GetRoomSession().controllerLevel >= RoomControllerLevel.GUILD_MEMBER))) && (offer.products.length === 1) && (offer.products[0].productType !== ProductTypeEnum.EFFECT) && (offer.products[0].productType !== ProductTypeEnum.HABBO_CLUB)) +} diff --git a/src/views/catalog/views/page/offer/CatalogPageOfferView.tsx b/src/views/catalog/views/page/offer/CatalogPageOfferView.tsx index 89f6b90f..980ee8e7 100644 --- a/src/views/catalog/views/page/offer/CatalogPageOfferView.tsx +++ b/src/views/catalog/views/page/offer/CatalogPageOfferView.tsx @@ -1,5 +1,5 @@ import { MouseEventType } from '@nitrots/nitro-renderer'; -import { FC, MouseEvent, useCallback } from 'react'; +import { FC, MouseEvent, useCallback, useState } from 'react'; import { useCatalogContext } from '../../../context/CatalogContext'; import { CatalogActions } from '../../../reducers/CatalogReducer'; import { CatalogProductView } from '../product/CatalogProductView'; @@ -8,6 +8,7 @@ import { CatalogPageOfferViewProps } from './CatalogPageOfferView.types'; export const CatalogPageOfferView: FC = props => { const { isActive = false, offer = null } = props; + const [ isMouseDown, setMouseDown ] = useState(false); const { dispatchCatalogState = null } = useCatalogContext(); const onMouseEvent = useCallback((event: MouseEvent) => @@ -24,8 +25,18 @@ export const CatalogPageOfferView: FC = props => } }); return; + case MouseEventType.MOUSE_DOWN: + console.log('ye') + setMouseDown(true); + return; + case MouseEventType.MOUSE_UP: + setMouseDown(false); + return; + case MouseEventType.ROLL_OUT: + if(!isMouseDown || !isActive) return; + return; } - }, [ isActive, offer, dispatchCatalogState ]); + }, [ isActive, offer, isMouseDown, dispatchCatalogState ]); const product = ((offer.products && offer.products[0]) || null); diff --git a/src/views/catalog/views/page/product/CatalogProductView.tsx b/src/views/catalog/views/page/product/CatalogProductView.tsx index 684488d0..2bb1c543 100644 --- a/src/views/catalog/views/page/product/CatalogProductView.tsx +++ b/src/views/catalog/views/page/product/CatalogProductView.tsx @@ -65,7 +65,7 @@ export const CatalogProductView: FC = props => return (
-
+
{ !imageUrl && (product.productType === ProductTypeEnum.ROBOT) && } { (product.productCount > 1) && { product.productCount } } diff --git a/src/views/friends/FriendsMessageHandler.tsx b/src/views/friends/FriendsMessageHandler.tsx index 479fc961..ce84725e 100644 --- a/src/views/friends/FriendsMessageHandler.tsx +++ b/src/views/friends/FriendsMessageHandler.tsx @@ -1,8 +1,6 @@ -import { FriendListFragmentEvent, FriendListUpdateEvent, FriendRequestsEvent, GetFriendRequestsComposer, MessengerInitEvent, NewConsoleMessageEvent } from '@nitrots/nitro-renderer'; +import { FriendListFragmentEvent, FriendListUpdateEvent, FriendRequestsEvent, GetFriendRequestsComposer, MessengerInitEvent } from '@nitrots/nitro-renderer'; import { FC, useCallback } from 'react'; -import { GetSessionDataManager } from '../../api'; import { CreateMessageHook, SendMessageHook } from '../../hooks/messages/message-event'; -import { MessengerChatMessage } from './common/MessengerChatMessage'; import { MessengerSettings } from './common/MessengerSettings'; import { useFriendsContext } from './context/FriendsContext'; import { FriendsActions } from './reducers/FriendsReducer'; @@ -10,7 +8,6 @@ import { FriendsActions } from './reducers/FriendsReducer'; export const FriendsMessageHandler: FC<{}> = props => { const { friendsState = null, dispatchFriendsState = null } = useFriendsContext(); - const { activeChats = [] } = friendsState; const onMessengerInitEvent = useCallback((event: MessengerInitEvent) => { @@ -66,28 +63,10 @@ export const FriendsMessageHandler: FC<{}> = props => }); }, [ dispatchFriendsState ]); - const onNewConsoleMessageEvent = useCallback((event: NewConsoleMessageEvent) => - { - const parser = event.getParser(); - - let userId = parser.senderId; - - if(userId === GetSessionDataManager().userId) userId = 0; - - dispatchFriendsState({ - type: FriendsActions.ADD_CHAT_MESSAGE, - payload: { - chatMessage: new MessengerChatMessage(MessengerChatMessage.MESSAGE, userId, parser.messageText, parser.secondsSinceSent, parser.extraData), - boolValue: true - } - }); - }, [ dispatchFriendsState ]); - CreateMessageHook(MessengerInitEvent, onMessengerInitEvent); CreateMessageHook(FriendListFragmentEvent, onFriendsFragmentEvent); CreateMessageHook(FriendListUpdateEvent, onFriendsUpdateEvent); CreateMessageHook(FriendRequestsEvent, onFriendRequestsEvent); - CreateMessageHook(NewConsoleMessageEvent, onNewConsoleMessageEvent); return null; } diff --git a/src/views/friends/common/MessengerChat.ts b/src/views/friends/common/MessengerChat.ts deleted file mode 100644 index 4b49d0ae..00000000 --- a/src/views/friends/common/MessengerChat.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { MessengerChatMessage } from './MessengerChatMessage'; -import { MessengerChatMessageGroup } from './MessengerChatMessageGroup'; -export class MessengerChat -{ - private _friendId: number; - private _isRead: boolean; - private _messageGroups: MessengerChatMessageGroup[]; - - constructor(friendId: number) - { - this._friendId = friendId; - this._isRead = true; - this._messageGroups = []; - } - - public addMessage(message: MessengerChatMessage, setAsNotRead: boolean = true, isSystem: boolean = false): void - { - if(!this.lastMessageGroup || this.lastMessageGroup.userId !== message.senderId || isSystem || this.lastMessageGroup.isSystem) this._messageGroups.push(new MessengerChatMessageGroup(message.senderId, isSystem)); - - this.lastMessageGroup.addMessage(message); - - if(setAsNotRead) this._isRead = false; - } - - public read(): void - { - this._isRead = true; - } - - public get friendId(): number - { - return this._friendId; - } - - public get isRead(): boolean - { - return this._isRead; - } - - public get messageGroups(): MessengerChatMessageGroup[] - { - return this._messageGroups; - } - - public get lastMessageGroup(): MessengerChatMessageGroup - { - return this._messageGroups[this._messageGroups.length - 1]; - } -} diff --git a/src/views/friends/common/MessengerChatMessageGroup.ts b/src/views/friends/common/MessengerChatMessageGroup.ts deleted file mode 100644 index 0fad7be8..00000000 --- a/src/views/friends/common/MessengerChatMessageGroup.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { MessengerChatMessage } from './MessengerChatMessage'; - -export class MessengerChatMessageGroup -{ - private _userId: number; - private _messages: MessengerChatMessage[]; - private _isSystem: boolean; - - constructor(userId: number, isSystem: boolean) - { - this._userId = userId; - this._messages = []; - this._isSystem = isSystem; - } - - public addMessage(message: MessengerChatMessage): void - { - this._messages.push(message); - } - - public get userId(): number - { - return this._userId; - } - - public get messages(): MessengerChatMessage[] - { - return this._messages; - } - - public get isSystem(): boolean - { - return this._isSystem; - } -} diff --git a/src/views/friends/common/MessengerThread.ts b/src/views/friends/common/MessengerThread.ts new file mode 100644 index 00000000..a2ee75e1 --- /dev/null +++ b/src/views/friends/common/MessengerThread.ts @@ -0,0 +1,83 @@ +import { LocalizeText } from '../../../api'; +import { MessengerFriend } from './MessengerFriend'; +import { MessengerThreadChat } from './MessengerThreadChat'; +import { MessengerThreadChatGroup } from './MessengerThreadChatGroup'; + +export class MessengerThread +{ + public static MESSAGE_RECEIVED: string = 'MT_MESSAGE_RECEIVED'; + + private _participant: MessengerFriend; + private _groups: MessengerThreadChatGroup[]; + private _lastUpdated: Date; + private _unread: boolean; + + constructor(participant: MessengerFriend, isNew: boolean = true) + { + this._participant = participant; + this._groups = []; + this._lastUpdated = new Date(); + this._unread = false; + + if(isNew) + { + this.addMessage(-1, LocalizeText('messenger.moderationinfo'), 0, null, MessengerThreadChat.SECURITY_NOTIFICATION); + + this._unread = false; + } + } + + public addMessage(senderId: number, message: string, secondsSinceSent: number = 0, extraData: string = null, type: number = 0): MessengerThreadChat + { + const group = this.getLastGroup(senderId); + + if(!group) return; + + const chat = new MessengerThreadChat(senderId, message, secondsSinceSent, extraData, type); + + group.addChat(chat); + + this._lastUpdated = new Date(); + this._unread = true; + + return chat; + } + + private getLastGroup(userId: number): MessengerThreadChatGroup + { + let group = this._groups[(this._groups.length - 1)]; + + if(group && (group.userId === userId)) return group; + + group = new MessengerThreadChatGroup(userId); + + this._groups.push(group); + + return group; + } + + public setRead(): void + { + this._unread = false; + } + + public get participant(): MessengerFriend + { + return this._participant; + } + + public get groups(): MessengerThreadChatGroup[] + { + return this._groups; + } + + public get lastUpdated(): Date + { + return this._lastUpdated; + } + + public get unread(): boolean + { + return this._unread; + } +} diff --git a/src/views/friends/common/MessengerChatMessage.ts b/src/views/friends/common/MessengerThreadChat.ts similarity index 51% rename from src/views/friends/common/MessengerChatMessage.ts rename to src/views/friends/common/MessengerThreadChat.ts index 6a0aced7..2927fecc 100644 --- a/src/views/friends/common/MessengerChatMessage.ts +++ b/src/views/friends/common/MessengerThreadChat.ts @@ -1,23 +1,25 @@ -export class MessengerChatMessage +export class MessengerThreadChat { - public static MESSAGE: number = 0; + public static CHAT: number = 0; public static ROOM_INVITE: number = 1; - public static SECURITY_ALERT: number = 2; - public static STATUS_ALERT: number = 3; + public static STATUS_NOTIFICATION: number = 2; + public static SECURITY_NOTIFICATION: number = 3; private _type: number; private _senderId: number; private _message: string; - private _sentAt: number; + private _secondsSinceSent: number; private _extraData: string; + private _date: Date; - constructor(type: number, senderId: number, message: string, sentAt: number, extraData?: string) + constructor(senderId: number, message: string, secondsSinceSent: number = 0, extraData: string = null, type: number = 0) { this._type = type; this._senderId = senderId; this._message = message; - this._sentAt = sentAt; + this._secondsSinceSent = secondsSinceSent; this._extraData = extraData; + this._date = new Date(); } public get type(): number @@ -35,13 +37,18 @@ export class MessengerChatMessage return this._message; } - public get sentAt(): number + public get secondsSinceSent(): number { - return this._sentAt; + return this._secondsSinceSent; } public get extraData(): string { return this._extraData; } + + public get date(): Date + { + return this._date; + } } diff --git a/src/views/friends/common/MessengerThreadChatGroup.ts b/src/views/friends/common/MessengerThreadChatGroup.ts new file mode 100644 index 00000000..661dcb07 --- /dev/null +++ b/src/views/friends/common/MessengerThreadChatGroup.ts @@ -0,0 +1,28 @@ +import { MessengerThreadChat } from './MessengerThreadChat'; + +export class MessengerThreadChatGroup +{ + private _userId: number; + private _chats: MessengerThreadChat[]; + + constructor(userId: number) + { + this._userId = userId; + this._chats = []; + } + + public addChat(message: MessengerThreadChat): void + { + this._chats.push(message); + } + + public get userId(): number + { + return this._userId; + } + + public get chats(): MessengerThreadChat[] + { + return this._chats; + } +} diff --git a/src/views/friends/reducers/FriendsReducer.tsx b/src/views/friends/reducers/FriendsReducer.tsx index 82f2e734..1901bb49 100644 --- a/src/views/friends/reducers/FriendsReducer.tsx +++ b/src/views/friends/reducers/FriendsReducer.tsx @@ -1,7 +1,5 @@ import { FriendListUpdateParser, FriendParser, FriendRequestData } from '@nitrots/nitro-renderer'; import { Reducer } from 'react'; -import { MessengerChat } from '../common/MessengerChat'; -import { MessengerChatMessage } from '../common/MessengerChatMessage'; import { MessengerFriend } from '../common/MessengerFriend'; import { MessengerRequest } from '../common/MessengerRequest'; import { MessengerSettings } from '../common/MessengerSettings'; @@ -18,8 +16,6 @@ export interface IFriendsState settings: MessengerSettings; friends: MessengerFriend[]; requests: MessengerRequest[]; - activeChats: MessengerChat[]; - firstChatEverOpen: boolean; } export interface IFriendsAction @@ -30,8 +26,6 @@ export interface IFriendsAction fragment?: FriendParser[]; update?: FriendListUpdateParser; requests?: FriendRequestData[]; - chats?: MessengerChat[]; - chatMessage?: MessengerChatMessage; numberValue?: number; boolValue?: boolean; } @@ -44,17 +38,12 @@ export class FriendsActions public static PROCESS_FRAGMENT: string = 'FA_PROCESS_FRAGMENT'; public static PROCESS_UPDATE: string = 'FA_PROCESS_UPDATE'; public static PROCESS_REQUESTS: string = 'FA_PROCESS_REQUESTS'; - public static SET_ACTIVE_CHATS: string = 'FA_SET_ACTIVE_CHATS'; - public static SET_CHAT_READ: string = 'FA_SET_CHAT_READ'; - public static ADD_CHAT_MESSAGE: string = 'FA_ADD_CHAT_MESSAGE'; } export const initialFriends: IFriendsState = { settings: null, friends: [], - requests: [], - activeChats: [], - firstChatEverOpen: false + requests: [] } export const FriendsReducer: Reducer = (state, action) => @@ -108,11 +97,17 @@ export const FriendsReducer: Reducer = (state, ac { const index = friends.findIndex(existingFriend => (existingFriend.id === friend.id)); - const newFriend = new MessengerFriend(); - newFriend.populate(friend); + if(index === -1) + { + const newFriend = new MessengerFriend(); + newFriend.populate(friend); - if(index > -1) friends[index] = newFriend; - else friends.unshift(newFriend); + friends.unshift(newFriend); + } + else + { + friends[index].populate(friend); + } } for(const friend of update.addedFriends) processUpdate(friend); @@ -146,43 +141,6 @@ export const FriendsReducer: Reducer = (state, ac return { ...state, requests }; } - case FriendsActions.SET_ACTIVE_CHATS: { - const activeChats = (action.payload.chats || []); - - if(!state.firstChatEverOpen && activeChats.length > 0) activeChats[0].addMessage(new MessengerChatMessage(MessengerChatMessage.SECURITY_ALERT, 0, null, 0), false, true); - - return { ...state, activeChats, firstChatEverOpen: true }; - } - case FriendsActions.SET_CHAT_READ: { - const friendId = action.payload.numberValue; - - const activeChats = Array.from(state.activeChats); - - let activeChatIndex = activeChats.findIndex(c => c.friendId === friendId); - - if(activeChatIndex > -1) activeChats[activeChatIndex].read(); - - return { ...state, activeChats }; - } - case FriendsActions.ADD_CHAT_MESSAGE: { - const message = action.payload.chatMessage; - const toFriendId = action.payload.numberValue; - const setAsNotRead = action.payload.boolValue; - - const activeChats = Array.from(state.activeChats); - - let activeChatIndex = activeChats.findIndex(c => c.friendId === toFriendId ? toFriendId : message.senderId); - - if(activeChatIndex === -1) - { - activeChats.push(new MessengerChat(message.senderId)); - activeChatIndex = activeChats.length - 1; - } - - activeChats[activeChatIndex].addMessage(message, setAsNotRead); - - return { ...state, activeChats }; - } default: return state; } diff --git a/src/views/friends/views/messenger-thread-group/FriendsMessengerThreadGroup.tsx b/src/views/friends/views/messenger-thread-group/FriendsMessengerThreadGroup.tsx new file mode 100644 index 00000000..b0d30ea7 --- /dev/null +++ b/src/views/friends/views/messenger-thread-group/FriendsMessengerThreadGroup.tsx @@ -0,0 +1,48 @@ +import { FC } from 'react'; +import { GetSessionDataManager } from '../../../../api'; +import { AvatarImageView } from '../../../shared/avatar-image/AvatarImageView'; +import { MessengerThreadChat } from '../../common/MessengerThreadChat'; +import { FriendsMessengerThreadGroupProps } from './FriendsMessengerThreadGroup.types'; + +export const FriendsMessengerThreadGroup: FC = props => +{ + const { thread = null, group = null } = props; + + if(!thread || !group) return null; + + if(group.userId === -1) + { + return ( +
+ { group.chats.map((chat, index) => + { + return ( +
+ { chat.type === MessengerThreadChat.SECURITY_NOTIFICATION && +
+ +
{ chat.message }
+
} +
+ ); + }) } +
+ ); + } + + return ( +
+ { (group.userId > 0) && +
+ +
} +
+ { group.chats.map((chat, index) =>
{ chat.message }
) } +
+ { (group.userId === 0) && +
+ +
} +
+ ); +} diff --git a/src/views/friends/views/messenger-thread-group/FriendsMessengerThreadGroup.types.ts b/src/views/friends/views/messenger-thread-group/FriendsMessengerThreadGroup.types.ts new file mode 100644 index 00000000..12a0ed17 --- /dev/null +++ b/src/views/friends/views/messenger-thread-group/FriendsMessengerThreadGroup.types.ts @@ -0,0 +1,8 @@ +import { MessengerThread } from '../../common/MessengerThread'; +import { MessengerThreadChatGroup } from '../../common/MessengerThreadChatGroup'; + +export interface FriendsMessengerThreadGroupProps +{ + thread: MessengerThread; + group: MessengerThreadChatGroup; +} diff --git a/src/views/friends/views/messenger-thread/FriendsMessengerThreadView.tsx b/src/views/friends/views/messenger-thread/FriendsMessengerThreadView.tsx new file mode 100644 index 00000000..3bf6326a --- /dev/null +++ b/src/views/friends/views/messenger-thread/FriendsMessengerThreadView.tsx @@ -0,0 +1,17 @@ +import { FC } from 'react'; +import { FriendsMessengerThreadGroup } from '../messenger-thread-group/FriendsMessengerThreadGroup'; +import { FriendsMessengerThreadViewProps } from './FriendsMessengerThreadView.types'; + +export const FriendsMessengerThreadView: FC = props => +{ + const { thread = null } = props; + + return ( + <> + { (thread.groups.length > 0) && thread.groups.map((group, index) => + { + return ; + }) } + + ); +} diff --git a/src/views/friends/views/messenger-thread/FriendsMessengerThreadView.types.ts b/src/views/friends/views/messenger-thread/FriendsMessengerThreadView.types.ts new file mode 100644 index 00000000..a6e0f4c4 --- /dev/null +++ b/src/views/friends/views/messenger-thread/FriendsMessengerThreadView.types.ts @@ -0,0 +1,6 @@ +import { MessengerThread } from '../../common/MessengerThread'; + +export interface FriendsMessengerThreadViewProps +{ + thread: MessengerThread; +} diff --git a/src/views/friends/views/messenger/FriendsMessengerView.scss b/src/views/friends/views/messenger/FriendsMessengerView.scss index bbfdb0aa..596ab19f 100644 --- a/src/views/friends/views/messenger/FriendsMessengerView.scss +++ b/src/views/friends/views/messenger/FriendsMessengerView.scss @@ -1,5 +1,6 @@ .nitro-friends-messenger { width: 280px; + resize: both; .friend-head { position: relative; diff --git a/src/views/friends/views/messenger/FriendsMessengerView.tsx b/src/views/friends/views/messenger/FriendsMessengerView.tsx index 882b435f..dac6a7a5 100644 --- a/src/views/friends/views/messenger/FriendsMessengerView.tsx +++ b/src/views/friends/views/messenger/FriendsMessengerView.tsx @@ -1,41 +1,134 @@ -import { FollowFriendMessageComposer, ILinkEventTracker, NitroEvent, SendMessageComposer, UserProfileComposer } from '@nitrots/nitro-renderer'; +import { FollowFriendMessageComposer, ILinkEventTracker, NewConsoleMessageEvent, SendMessageComposer, UserProfileComposer } from '@nitrots/nitro-renderer'; import { FC, KeyboardEvent, useCallback, useEffect, useMemo, useRef, useState } from 'react'; -import { AddEventLinkTracker, GetSessionDataManager, LocalizeText, RemoveLinkEventTracker } from '../../../../api'; -import { FriendsEvent } from '../../../../events/friends/FriendsEvent'; -import { SendMessageHook, useUiEvent } from '../../../../hooks'; +import { AddEventLinkTracker, LocalizeText, RemoveLinkEventTracker } from '../../../../api'; +import { FriendsMessengerIconEvent } from '../../../../events'; +import { BatchUpdates, CreateMessageHook, dispatchUiEvent, SendMessageHook } from '../../../../hooks'; import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout'; import { AvatarImageView } from '../../../shared/avatar-image/AvatarImageView'; -import { MessengerChat } from '../../common/MessengerChat'; -import { MessengerChatMessage } from '../../common/MessengerChatMessage'; +import { MessengerThread } from '../../common/MessengerThread'; +import { MessengerThreadChat } from '../../common/MessengerThreadChat'; import { useFriendsContext } from '../../context/FriendsContext'; -import { FriendsActions } from '../../reducers/FriendsReducer'; +import { FriendsMessengerThreadView } from '../messenger-thread/FriendsMessengerThreadView'; export const FriendsMessengerView: FC<{}> = props => { - const { friendsState = null, dispatchFriendsState = null } = useFriendsContext(); - const { activeChats = [], friends = [] } = friendsState; - const [ isVisible, setIsVisible ] = useState(false); - const [ selectedChatIndex, setSelectedChatIndex ] = useState(0); - const [ message, setMessage ] = useState(''); - + const [ messageThreads, setMessageThreads ] = useState([]); + const [ activeThreadIndex, setActiveThreadIndex ] = useState(-1); + const [ hiddenThreadIndexes, setHiddenThreadIndexes ] = useState([]); + const [ messageText, setMessageText ] = useState(''); + const { friendsState = null } = useFriendsContext(); + const { friends = [] } = friendsState; const messagesBox = useRef(); - - const onNitroEvent = useCallback((event: NitroEvent) => - { - switch(event.type) - { - case FriendsEvent.SHOW_FRIEND_MESSENGER: - setIsVisible(true); - return; - case FriendsEvent.TOGGLE_FRIEND_MESSENGER: - setIsVisible(value => !value); - return; - } - }, []); + const [ updateValue, setUpdateValue ] = useState({}); - useUiEvent(FriendsEvent.SHOW_FRIEND_MESSENGER, onNitroEvent); - useUiEvent(FriendsEvent.TOGGLE_FRIEND_MESSENGER, onNitroEvent); + const followFriend = useCallback(() => + { + SendMessageHook(new FollowFriendMessageComposer(messageThreads[activeThreadIndex].participant.id)); + }, [ messageThreads, activeThreadIndex ]); + + const openProfile = useCallback(() => + { + SendMessageHook(new UserProfileComposer(messageThreads[activeThreadIndex].participant.id)); + }, [ messageThreads, activeThreadIndex ]); + + const getFriend = useCallback((userId: number) => + { + return ((friends.find(friend => (friend.id === userId))) || null); + }, [ friends ]); + + const visibleThreads = useMemo(() => + { + return messageThreads.filter((thread, index) => + { + if(hiddenThreadIndexes.indexOf(index) >= 0) return false; + + return true; + }); + }, [ messageThreads, hiddenThreadIndexes ]); + + const getMessageThreadWithIndex = useCallback<(userId: number) => [ number, MessengerThread ]>((userId: number) => + { + if(messageThreads.length > 0) + { + for(let i = 0; i < messageThreads.length; i++) + { + const thread = messageThreads[i]; + + if(thread.participant && (thread.participant.id === userId)) + { + const hiddenIndex = hiddenThreadIndexes.indexOf(i); + + if(hiddenIndex >= 0) + { + setHiddenThreadIndexes(prevValue => + { + const newIndexes = [ ...prevValue ]; + + newIndexes.splice(hiddenIndex, 1); + + return newIndexes; + }); + } + + return [ i, thread ]; + } + } + } + + const friend = getFriend(userId); + + if(!friend) return [ -1, null ]; + + const thread = new MessengerThread(friend); + const newThreads = [ ...messageThreads, thread ]; + + setMessageThreads(newThreads); + + return [ (newThreads.length - 1), thread ]; + }, [ messageThreads, hiddenThreadIndexes, getFriend ]); + + const onNewConsoleMessageEvent = useCallback((event: NewConsoleMessageEvent) => + { + const parser = event.getParser(); + const [ threadIndex, thread ] = getMessageThreadWithIndex(parser.senderId); + + if((threadIndex === -1) || !thread) return; + + thread.addMessage(parser.senderId, parser.messageText, parser.secondsSinceSent, parser.extraData); + + setMessageThreads(prevValue => [ ...prevValue ]); + }, [ getMessageThreadWithIndex ]); + + CreateMessageHook(NewConsoleMessageEvent, onNewConsoleMessageEvent); + + const sendMessage = useCallback(() => + { + if(!messageText || !messageText.length) return; + + if(activeThreadIndex === -1) return; + + const thread = messageThreads[activeThreadIndex]; + + if(!thread) return; + + SendMessageHook(new SendMessageComposer(thread.participant.id, messageText)); + + thread.addMessage(0, messageText, 0, null, MessengerThreadChat.CHAT); + + BatchUpdates(() => + { + setMessageThreads(prevValue => [ ...prevValue ]); + setMessageText(''); + }); + }, [ messageThreads, activeThreadIndex, messageText ]); + + const onKeyDown = useCallback((event: KeyboardEvent) => + { + if(event.key !== 'Enter') return; + + sendMessage(); + }, [ sendMessage ]); const linkReceived = useCallback((url: string) => { @@ -43,69 +136,35 @@ export const FriendsMessengerView: FC<{}> = props => if(parts.length < 3) return; - const friendId = parseInt(parts[2]); - - let existingChatIndex = activeChats.findIndex(c => c.friendId === friendId); - - if(existingChatIndex === -1) + if(parts[2] === 'open') { - const clonedActiveChats = Array.from(activeChats); - clonedActiveChats.push(new MessengerChat(friendId)); + setIsVisible(true); - dispatchFriendsState({ - type: FriendsActions.SET_ACTIVE_CHATS, - payload: { - chats: clonedActiveChats - } - }); - - existingChatIndex = clonedActiveChats.length - 1; + return; } - setSelectedChatIndex(existingChatIndex); - setIsVisible(true); - }, [ activeChats, dispatchFriendsState ]); + const [ threadIndex ] = getMessageThreadWithIndex(parseInt(parts[2])); - const getFriendFigure = useCallback((id: number) => - { - const friend = friends.find(f => f.id === id); + if(threadIndex === -1) return; - if(!friend) return null; - - return friend.figure; - }, [ friends ]); - - const selectChat = useCallback((index: number) => - { - const chat = activeChats[index]; - - if(!chat) return; - - dispatchFriendsState({ - type: FriendsActions.SET_CHAT_READ, - payload: { - numberValue: chat.friendId - } + BatchUpdates(() => + { + setActiveThreadIndex(threadIndex); + setIsVisible(true); }); - - setSelectedChatIndex(index); - }, [ activeChats, dispatchFriendsState ]); + }, [ getMessageThreadWithIndex ]); - const selectedChat = useMemo(() => - { - return activeChats[selectedChatIndex]; - }, [ activeChats, selectedChatIndex ]); - - const selectedChatFriend = useMemo(() => + const closeThread = useCallback((threadIndex: number) => { - if(!selectedChat) return null; + setHiddenThreadIndexes(prevValue => + { + const values = [ ...prevValue ]; - const friend = friends.find(f => f.id === selectedChat.friendId); + if(values.indexOf(threadIndex) === -1) values.push(threadIndex); - if(!friend) return null; - - return friend; - }, [ friends, selectedChat ]); + return values; + }); + }, []); useEffect(() => { @@ -121,112 +180,102 @@ export const FriendsMessengerView: FC<{}> = props => useEffect(() => { - if(!messagesBox || !messagesBox.current) return; - - messagesBox.current.scrollTop = messagesBox.current.scrollHeight; + if(!isVisible) return; - }, [ selectedChat ]); + if(activeThreadIndex === -1) setActiveThreadIndex(0); + }, [ isVisible, activeThreadIndex ]); - const followFriend = useCallback(() => + useEffect(() => { - SendMessageHook(new FollowFriendMessageComposer(selectedChatFriend.id)); - }, [ selectedChatFriend ]); + if(hiddenThreadIndexes.indexOf(activeThreadIndex) >= 0) setActiveThreadIndex(0); + }, [ activeThreadIndex, hiddenThreadIndexes ]); - const openProfile = useCallback(() => + useEffect(() => { - SendMessageHook(new UserProfileComposer(selectedChatFriend.id)); - }, [ selectedChatFriend ]); + if(!isVisible || (activeThreadIndex === -1)) return; - const sendMessage = useCallback(() => + const activeThread = messageThreads[activeThreadIndex]; + + if(activeThread.unread) + { + messagesBox.current.scrollTop = messagesBox.current.scrollHeight; + activeThread.setRead(); + setUpdateValue({}); + } + }, [ isVisible, messageThreads, activeThreadIndex ]); + + useEffect(() => { - if(message.length === 0) return; + if(!visibleThreads.length) + { + setIsVisible(false); - SendMessageHook(new SendMessageComposer(selectedChat.friendId, message)); + dispatchUiEvent(new FriendsMessengerIconEvent(FriendsMessengerIconEvent.UPDATE_ICON, FriendsMessengerIconEvent.HIDE_ICON)); - dispatchFriendsState({ - type: FriendsActions.ADD_CHAT_MESSAGE, - payload: { - chatMessage: new MessengerChatMessage(MessengerChatMessage.MESSAGE, 0, message, (new Date().getMilliseconds())), - numberValue: selectedChat.friendId, - boolValue: false + return; + } + + let isUnread = false; + + for(const thread of visibleThreads) + { + if(thread.unread) + { + isUnread = true; + + break; } - }); - setMessage(''); - }, [ selectedChat, message, dispatchFriendsState ]); + } - const onKeyDown = useCallback((event: KeyboardEvent) => - { - if(event.key !== 'Enter') return; - - sendMessage(); - }, [ sendMessage ]); + dispatchUiEvent(new FriendsMessengerIconEvent(FriendsMessengerIconEvent.UPDATE_ICON, isUnread ? FriendsMessengerIconEvent.UNREAD_ICON : FriendsMessengerIconEvent.SHOW_ICON)); + }, [ visibleThreads, updateValue ]); if(!isVisible) return null; - return ( - setIsVisible(false) } /> - -
- { activeChats && activeChats.map((chat, index) => + return ( + + setIsVisible(false) } /> + +
+ { visibleThreads && (visibleThreads.length > 0) && visibleThreads.map((thread, index) => { - return
selectChat(index) }> - { !chat.isRead && } - -
; + const messageThreadIndex = messageThreads.indexOf(thread); + + return ( +
setActiveThreadIndex(messageThreadIndex) }> + { thread.unread && } + +
+ ); }) } -
-
- { selectedChat && selectedChatFriend && <> -
{ LocalizeText('messenger.window.separator', ['FRIEND_NAME'], [ selectedChatFriend.name ]) }
+
+
+ { (activeThreadIndex >= 0) && + <> +
+ { LocalizeText('messenger.window.separator', [ 'FRIEND_NAME' ], [ messageThreads[activeThreadIndex].participant.name ]) } +
- -
- +
- { selectedChat.messageGroups.map((group, groupIndex) => - { - return
- { group.isSystem && <> - { group.messages.map((message, messageIndex) => - { - return
- { message.type === MessengerChatMessage.SECURITY_ALERT &&
- -
{ LocalizeText('messenger.moderationinfo') }
-
} -
- }) } - } - { !group.isSystem && <> - { group.userId !== 0 &&
- -
} -
- { group.messages.map((message, messageIndex) => - { - return
{ message.message }
- }) } -
- { group.userId === 0 &&
- -
} - } -
; - }) } +
- setMessage(e.target.value) } onKeyDown={ onKeyDown } /> + setMessageText(event.target.value) } onKeyDown={ onKeyDown } />
} -
-
); -}; + + + ); +} diff --git a/src/views/room/widgets/chat/message/ChatWidgetMessageView.scss b/src/views/room/widgets/chat/message/ChatWidgetMessageView.scss index 9bdbcb6b..9337ed85 100644 --- a/src/views/room/widgets/chat/message/ChatWidgetMessageView.scss +++ b/src/views/room/widgets/chat/message/ChatWidgetMessageView.scss @@ -696,7 +696,6 @@ justify-content: center; height: 100%; max-height: 24px; - image-rendering: -webkit-optimize-contrast; overflow: hidden; .user-image { @@ -707,8 +706,9 @@ height: 130px; background-repeat: no-repeat; background-position: center; - transform: scale(0.5) translateZ(0); + transform: scale(0.5); overflow: hidden; + image-rendering: -webkit-optimize-contrast; } } diff --git a/src/views/shared/avatar-image/AvatarImage.scss b/src/views/shared/avatar-image/AvatarImage.scss index f85ca9c4..a552dbb2 100644 --- a/src/views/shared/avatar-image/AvatarImage.scss +++ b/src/views/shared/avatar-image/AvatarImage.scss @@ -6,4 +6,10 @@ background-position-x: center; background-position-y: -8px !important; pointer-events: none; + image-rendering: pixelated; + + &.scale-0-5, + &.scale-0-75 { + image-rendering: -webkit-optimize-contrast; + } } diff --git a/src/views/shared/avatar-image/AvatarImageView.tsx b/src/views/shared/avatar-image/AvatarImageView.tsx index 5d2a2a33..d8e96979 100644 --- a/src/views/shared/avatar-image/AvatarImageView.tsx +++ b/src/views/shared/avatar-image/AvatarImageView.tsx @@ -1,5 +1,5 @@ import { AvatarScaleType, AvatarSetType } from '@nitrots/nitro-renderer'; -import { FC, useEffect, useRef, useState } from 'react'; +import { FC, useEffect, useMemo, useRef, useState } from 'react'; import { GetAvatarRenderManager } from '../../../api'; import { AvatarImageViewProps } from './AvatarImageView.types'; @@ -10,6 +10,13 @@ export const AvatarImageView: FC = props => const [ randomValue, setRandomValue ] = useState(-1); const isDisposed = useRef(false); + const getScaleStyle = useMemo(() => + { + if(scale === .5) return '0-5'; + + return scale.toString(); + }, [ scale ]); + useEffect(() => { const avatarImage = GetAvatarRenderManager().createAvatarImage(figure, AvatarScaleType.LARGE, gender, { @@ -50,5 +57,5 @@ export const AvatarImageView: FC = props => const url = `url('${ avatarUrl }')`; - return
; + return
; } diff --git a/src/views/shared/room-previewer/RoomPreviewerView.scss b/src/views/shared/room-previewer/RoomPreviewerView.scss index 55328299..e6192624 100644 --- a/src/views/shared/room-previewer/RoomPreviewerView.scss +++ b/src/views/shared/room-previewer/RoomPreviewerView.scss @@ -12,7 +12,6 @@ background-color: $light; background-repeat: no-repeat; background-position: center; - image-rendering: auto; &.border-0 { &::after { diff --git a/src/views/toolbar/ToolbarView.scss b/src/views/toolbar/ToolbarView.scss index 44abb043..57401e81 100644 --- a/src/views/toolbar/ToolbarView.scss +++ b/src/views/toolbar/ToolbarView.scss @@ -29,31 +29,28 @@ align-items: center; justify-content: center; cursor: pointer; - width: 50px; - margin: 0 1px; + //margin: 0 1px; position: relative; - .toolbar-avatar { - height: 50px; + &.item-avatar { + width: 50px; + height: 45px; + overflow: hidden; .avatar-image { margin-left: -5px; - margin-top: -30px; - } - - &:hover, &.active { - height: 53px; + margin-top: 25px; } } .icon, - .toolbar-avatar { + &.item-avatar { position: relative; - transition: transform .2s ease-out; + //transition: transform .2s ease-out; &:hover, &.active { - -webkit-transform: translate(0, -3px); - transform: translate(0, -3px); + -webkit-transform: translate(-1px, -1px); + transform: translate(-1px, -1px); filter: drop-shadow(2px 2px 0 rgba($black, 0.8)); } } @@ -68,7 +65,7 @@ .count { top: 0rem; - right: 5px; + right: 2px; font-size: 10px; } } diff --git a/src/views/toolbar/ToolbarView.tsx b/src/views/toolbar/ToolbarView.tsx index 3ab96937..4d10456b 100644 --- a/src/views/toolbar/ToolbarView.tsx +++ b/src/views/toolbar/ToolbarView.tsx @@ -1,7 +1,7 @@ import { Dispose, DropBounce, EaseOut, FigureUpdateEvent, JumpBy, Motions, NitroToolbarAnimateIconEvent, Queue, UserInfoDataParser, UserInfoEvent, UserProfileComposer, Wait } from '@nitrots/nitro-renderer'; import { FC, useCallback, useState } from 'react'; -import { GetRoomSession, GetRoomSessionManager, GetSessionDataManager, GoToDesktop } from '../../api'; -import { AvatarEditorEvent, CatalogEvent, FriendsEvent, InventoryEvent, NavigatorEvent, RoomWidgetCameraEvent } from '../../events'; +import { GetRoomSession, GetRoomSessionManager, GetSessionDataManager, GoToDesktop, OpenMessengerChat } from '../../api'; +import { AvatarEditorEvent, CatalogEvent, FriendsEvent, FriendsMessengerIconEvent, InventoryEvent, NavigatorEvent, RoomWidgetCameraEvent } from '../../events'; import { AchievementsUIEvent } from '../../events/achievements'; import { UnseenItemTrackerUpdateEvent } from '../../events/inventory/UnseenItemTrackerUpdateEvent'; import { ModToolsEvent } from '../../events/mod-tools/ModToolsEvent'; @@ -14,6 +14,10 @@ import { AvatarImageView } from '../shared/avatar-image/AvatarImageView'; import { ToolbarMeView } from './me/ToolbarMeView'; import { ToolbarViewItems, ToolbarViewProps } from './ToolbarView.types'; +const CHAT_ICON_HIDDEN: number = 0; +const CHAT_ICON_SHOWING: number = 1; +const CHAT_ICON_UNREAD: number = 2; + export const ToolbarView: FC = props => { const { isInRoom } = props; @@ -21,6 +25,7 @@ export const ToolbarView: FC = props => const [ userInfo, setUserInfo ] = useState(null); const [ userFigure, setUserFigure ] = useState(null); const [ isMeExpanded, setMeExpanded ] = useState(false); + const [ chatIconType, setChatIconType ] = useState(CHAT_ICON_HIDDEN); const [ unseenInventoryCount, setUnseenInventoryCount ] = useState(0); const unseenFriendListCount = 0; @@ -45,6 +50,13 @@ export const ToolbarView: FC = props => CreateMessageHook(FigureUpdateEvent, onUserFigureEvent); + const onFriendsMessengerIconEvent = useCallback((event: FriendsMessengerIconEvent) => + { + setChatIconType(event.iconType); + }, []); + + useUiEvent(FriendsMessengerIconEvent.UPDATE_ICON, onFriendsMessengerIconEvent); + const onUnseenItemTrackerUpdateEvent = useCallback((event: UnseenItemTrackerUpdateEvent) => { setUnseenInventoryCount(event.count); @@ -131,6 +143,9 @@ export const ToolbarView: FC = props => dispatchUiEvent(new UserSettingsUIEvent(UserSettingsUIEvent.TOGGLE_USER_SETTINGS)); setMeExpanded(false); return; + case ToolbarViewItems.FRIEND_CHAT_ITEM: + OpenMessengerChat(); + return; } }, []); @@ -148,20 +163,16 @@ export const ToolbarView: FC = props =>
-
-
-
-
setMeExpanded(!isMeExpanded) }> - -
+
+
+
setMeExpanded(!isMeExpanded) }> + + { (unseenAchievementsCount > 0) && +
{ unseenAchievementsCount }
}
- { (unseenAchievementsCount > 0) && ( -
{ unseenAchievementsCount }
) } -
-
{ isInRoom && (
- +
) } { !isInRoom && (
@@ -188,13 +199,20 @@ export const ToolbarView: FC = props =>
-
-
+
+
handleToolbarItemClick(ToolbarViewItems.FRIEND_LIST_ITEM) }> { (unseenFriendListCount > 0) && (
{ unseenFriendListCount }
) }
+ { ((chatIconType === CHAT_ICON_SHOWING) || (chatIconType === CHAT_ICON_UNREAD)) && +
handleToolbarItemClick(ToolbarViewItems.FRIEND_CHAT_ITEM) }> + { (chatIconType === CHAT_ICON_SHOWING) && } + { (chatIconType === CHAT_ICON_UNREAD) && } + { (unseenFriendListCount > 0) && +
{ unseenFriendListCount }
} +
}
diff --git a/src/views/toolbar/ToolbarView.types.ts b/src/views/toolbar/ToolbarView.types.ts index 0670bca7..48a376d1 100644 --- a/src/views/toolbar/ToolbarView.types.ts +++ b/src/views/toolbar/ToolbarView.types.ts @@ -9,6 +9,7 @@ export class ToolbarViewItems public static INVENTORY_ITEM: string = 'TVI_INVENTORY_ITEM'; public static CATALOG_ITEM: string = 'TVI_CATALOG_ITEM'; public static FRIEND_LIST_ITEM: string = 'TVI_FRIEND_LIST_ITEM'; + public static FRIEND_CHAT_ITEM: string = 'TVI_FRIEND_CHAT_ITEM'; public static CLOTHING_ITEM: string = 'TVI_CLOTHING_ITEM'; public static CAMERA_ITEM: string = 'TVI_CAMERA_ITEM'; public static MOD_TOOLS_ITEM: string = 'TVI_MOD_TOOLS_ITEM'; diff --git a/tsconfig.json b/tsconfig.json index df4dcf04..ac2a9fd7 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -24,6 +24,6 @@ }, "include": [ "src", - "node_modules/@nitrots/nitro-renderer/**/*.ts", + "node_modules/@nitrots/nitro-renderer/src/**/*.ts", ] } From 34ab1e6fd381722f401f86551e2a449ad10c707f Mon Sep 17 00:00:00 2001 From: Bill Date: Wed, 22 Sep 2021 15:01:56 -0400 Subject: [PATCH 17/31] Layout updates --- src/App.scss | 15 +++ src/assets/styles/bootstrap/_variables.scss | 3 +- src/assets/styles/utils.scss | 8 ++ src/layout/card/NitroCardView.scss | 1 + .../card/content/NitroCardContentView.scss | 1 - .../card/content/NitroCardContentView.tsx | 2 +- src/layout/card/grid/NitroCardGridView.scss | 4 +- src/layout/card/grid/NitroCardGridView.tsx | 35 ++++-- .../card/grid/NitroCardGridView.types.ts | 7 -- .../grid/context/NitroCardGridContext.tsx | 13 -- .../context/NitroCardGridContext.types.ts | 11 -- src/layout/card/grid/context/index.ts | 2 - src/layout/card/grid/index.ts | 1 - .../card/grid/item/NitroCardGridItemView.scss | 112 ++++++------------ .../card/grid/item/NitroCardGridItemView.tsx | 53 ++++++--- .../grid/item/NitroCardGridItemView.types.ts | 2 - src/views/achievements/AchievementsView.scss | 8 +- src/views/avatar-editor/AvatarEditorView.scss | 39 +++++- .../figure-set/AvatarEditorFigureSetView.tsx | 3 +- .../views/model/AvatarEditorModelView.tsx | 2 +- .../AvatarEditorPaletteSetView.tsx | 3 +- .../wardrobe/AvatarEditorWardrobeView.tsx | 3 +- src/views/catalog/CatalogView.scss | 9 +- src/views/inventory/InventoryView.scss | 9 +- .../item/InventoryFurnitureItemView.tsx | 2 +- .../views/trade/InventoryTradeView.tsx | 6 +- src/views/navigator/NavigatorView.scss | 9 +- .../shared/avatar-image/AvatarImage.scss | 3 +- .../shared/avatar-image/AvatarImageView.tsx | 6 + 29 files changed, 183 insertions(+), 189 deletions(-) delete mode 100644 src/layout/card/grid/context/NitroCardGridContext.tsx delete mode 100644 src/layout/card/grid/context/NitroCardGridContext.types.ts delete mode 100644 src/layout/card/grid/context/index.ts diff --git a/src/App.scss b/src/App.scss index 8d450e5a..474a2f07 100644 --- a/src/App.scss +++ b/src/App.scss @@ -17,6 +17,21 @@ $grid-active-border-color: $white; $toolbar-height: 55px; +$achievement-width: 650px; +$achievement-height: 400px; + +$avatar-editor-width: 620px; +$avatar-editor-height: 374px; + +$catalog-width: 620px; +$catalog-height: 400px; + +$inventory-width: 485px; +$inventory-height: 315px; + +$navigator-width: 400px; +$navigator-height: 420px; + .nitro-app { width: 100%; height: 100%; diff --git a/src/assets/styles/bootstrap/_variables.scss b/src/assets/styles/bootstrap/_variables.scss index 57aa9b7d..feb71255 100644 --- a/src/assets/styles/bootstrap/_variables.scss +++ b/src/assets/styles/bootstrap/_variables.scss @@ -85,6 +85,7 @@ $ghost: #c8cad0 !default; $gray-chateau: #a3a7b1 !default; $gable-green: #1C323F !default; $william: #3d5f6e !default; +$bluewood: #304059 !default; $success: $green !default; $info: $cyan !default; $warning: $yellow !default; @@ -385,7 +386,7 @@ $enable-transitions: true !default; $enable-reduced-motion: true !default; $enable-smooth-scroll: true !default; $enable-grid-classes: true !default; -$enable-cssgrid: false !default; +$enable-cssgrid: true !default; $enable-button-pointers: true !default; $enable-rfs: true !default; $enable-validation-icons: true !default; diff --git a/src/assets/styles/utils.scss b/src/assets/styles/utils.scss index 0050c41b..cc44e17f 100644 --- a/src/assets/styles/utils.scss +++ b/src/assets/styles/utils.scss @@ -10,6 +10,14 @@ transform: scale(1) translateZ(0); } +.scale-1-25 { + transform: scale(1.25) translateZ(0); +} + +.scale-1-50 { + transform: scale(1.50) translateZ(0); +} + .scale-2 { transform: scale(2) translateZ(0); } diff --git a/src/layout/card/NitroCardView.scss b/src/layout/card/NitroCardView.scss index cd7bfebf..84390259 100644 --- a/src/layout/card/NitroCardView.scss +++ b/src/layout/card/NitroCardView.scss @@ -3,6 +3,7 @@ $nitro-card-tabs-height: 33px; .nitro-card { pointer-events: all; + resize: both; @import './accordion/NitroCardAccordionView'; @import './content/NitroCardContentView'; diff --git a/src/layout/card/content/NitroCardContentView.scss b/src/layout/card/content/NitroCardContentView.scss index 4cbe6ee3..c56cad8c 100644 --- a/src/layout/card/content/NitroCardContentView.scss +++ b/src/layout/card/content/NitroCardContentView.scss @@ -10,6 +10,5 @@ height: 100% !important; min-height: auto !important; max-height: 100% !important; - resize: none !important; } } diff --git a/src/layout/card/content/NitroCardContentView.tsx b/src/layout/card/content/NitroCardContentView.tsx index 969069b2..ee3c1a72 100644 --- a/src/layout/card/content/NitroCardContentView.tsx +++ b/src/layout/card/content/NitroCardContentView.tsx @@ -8,7 +8,7 @@ export const NitroCardContentView: FC = props => const { simple = false } = useNitroCardContext(); return ( -
+
{ children }
); diff --git a/src/layout/card/grid/NitroCardGridView.scss b/src/layout/card/grid/NitroCardGridView.scss index f5794406..71acb2ee 100644 --- a/src/layout/card/grid/NitroCardGridView.scss +++ b/src/layout/card/grid/NitroCardGridView.scss @@ -66,6 +66,6 @@ } } } - - @import './item/NitroCardGridItemView.scss'; } + +@import './item/NitroCardGridItemView.scss'; diff --git a/src/layout/card/grid/NitroCardGridView.tsx b/src/layout/card/grid/NitroCardGridView.tsx index a9a85c64..033927a4 100644 --- a/src/layout/card/grid/NitroCardGridView.tsx +++ b/src/layout/card/grid/NitroCardGridView.tsx @@ -1,18 +1,31 @@ -import { FC } from 'react'; -import { NitroCardGridContextProvider } from './context/NitroCardGridContext'; -import { NitroCardGridThemes, NitroCardGridViewProps } from './NitroCardGridView.types'; +import { FC, useMemo } from 'react'; +import { NitroCardGridViewProps } from './NitroCardGridView.types'; export const NitroCardGridView: FC = props => { - const { columns = 5, theme = NitroCardGridThemes.THEME_DEFAULT, className = '', children = null, ...rest } = props; + const { columns = 5, className = '', style = null, children = null, ...rest } = props; + + const getClassName = useMemo(() => + { + let newClassName = 'grid gap-2 overflow-auto'; + + if(className && className.length) newClassName += ' ' + className; + + return newClassName; + }, [ className ]); + + const getStyle = useMemo(() => + { + const newStyle = { ...style }; + + newStyle['--bs-columns'] = columns.toString(); + + return newStyle; + }, [ style, columns ]); return ( - -
-
- { children } -
-
-
+
+ { children } +
); } diff --git a/src/layout/card/grid/NitroCardGridView.types.ts b/src/layout/card/grid/NitroCardGridView.types.ts index f3cc6c80..d5dc256d 100644 --- a/src/layout/card/grid/NitroCardGridView.types.ts +++ b/src/layout/card/grid/NitroCardGridView.types.ts @@ -3,11 +3,4 @@ import { DetailsHTMLAttributes } from 'react'; export interface NitroCardGridViewProps extends DetailsHTMLAttributes { columns?: number; - theme?: string; -} - -export class NitroCardGridThemes -{ - public static THEME_DEFAULT: string = 'theme-default'; - public static THEME_SHADOWED: string = 'theme-shadowed'; } diff --git a/src/layout/card/grid/context/NitroCardGridContext.tsx b/src/layout/card/grid/context/NitroCardGridContext.tsx deleted file mode 100644 index 18661b76..00000000 --- a/src/layout/card/grid/context/NitroCardGridContext.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import { createContext, FC, useContext } from 'react'; -import { INitroCardGridContext, NitroCardGridContextProps } from './NitroCardGridContext.types'; - -const NitroCardGridContext = createContext({ - theme: null -}); - -export const NitroCardGridContextProvider: FC = props => -{ - return { props.children } -} - -export const useNitroCardGridContext = () => useContext(NitroCardGridContext); diff --git a/src/layout/card/grid/context/NitroCardGridContext.types.ts b/src/layout/card/grid/context/NitroCardGridContext.types.ts deleted file mode 100644 index a0f97c95..00000000 --- a/src/layout/card/grid/context/NitroCardGridContext.types.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { ProviderProps } from 'react'; - -export interface INitroCardGridContext -{ - theme: string; -} - -export interface NitroCardGridContextProps extends ProviderProps -{ - -} diff --git a/src/layout/card/grid/context/index.ts b/src/layout/card/grid/context/index.ts deleted file mode 100644 index 9e3f79e8..00000000 --- a/src/layout/card/grid/context/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './NitroCardGridContext'; -export * from './NitroCardGridContext.types'; diff --git a/src/layout/card/grid/index.ts b/src/layout/card/grid/index.ts index 4b3dea50..8a191eec 100644 --- a/src/layout/card/grid/index.ts +++ b/src/layout/card/grid/index.ts @@ -1,4 +1,3 @@ -export * from './context'; export * from './item'; export * from './NitroCardGridView'; export * from './NitroCardGridView.types'; diff --git a/src/layout/card/grid/item/NitroCardGridItemView.scss b/src/layout/card/grid/item/NitroCardGridItemView.scss index b2959864..ab6ad600 100644 --- a/src/layout/card/grid/item/NitroCardGridItemView.scss +++ b/src/layout/card/grid/item/NitroCardGridItemView.scss @@ -1,86 +1,48 @@ -.grid-item-container { +.grid-item { + position: relative; + display: flex; + justify-content: center; + align-items: center; height: 50px; max-height: 50px; + width: 100%; + background-position: center; + background-repeat: no-repeat; + border-radius: $border-radius; + border-color: $grid-border-color !important; + background-color: $grid-bg-color; + border: nth(map-values($border-widths), 2) solid; - .grid-item { - display: flex; - justify-content: center; - align-items: center; - position: relative; - width: 100%; - height: 100%; - background-position: center; - background-repeat: no-repeat; - overflow: hidden; + &.active { + border-color: $grid-active-border-color !important; + background-color: $grid-active-bg-color !important; + } - &.theme-default { - border-radius: $border-radius; - border-color: $grid-border-color !important; - background-color: $grid-bg-color; - border: nth(map-values($border-widths), 2) solid; - } + &.unseen { + background-color: rgba($success, 0.4); + } - &.theme-shadowed { - border-radius: $border-radius; - background-color: $light; + .badge { + top: 2px; + right: 2px; + font-size: 8px; + } - &::after { - position: absolute; - content: ''; - top: 0; - bottom: 0; - left: 0; - right: 0; - border-radius: $border-radius; - border-bottom: 2px solid white; - border-right: 2px solid white; - box-shadow: -2px -2px rgba(0, 0, 0, .4), inset 3px 3px rgba(0, 0, 0, .2); - } + .avatar-image { + background-position-y: 10px; + } - &.active { - border: nth(map-values($border-widths), 2) solid; - border-color: $oslo-gray !important; - background-color: #F5F5F5; + .trade-button { + position: absolute; + bottom: 2px; + right: 2px; + font-size: 5px; + padding: 3px; + min-height: unset; - &:after { - content: unset; - } - } - } - - &.active { - border-color: $grid-active-border-color !important; - background-color: $grid-active-bg-color !important; - } - - &.unseen { - background-color: rgba($success, 0.4); - } - - .badge { - top: 2px; - right: 2px; - font-size: 8px; - } - - .avatar-image { - background-position: center; - background-repeat: no-repeat; - background-position-y: 12px !important; - } - - .trade-button { - position: absolute; - bottom: 2px; - right: 2px; - font-size: 5px; - padding: 3px; - min-height: unset; - - &.left { - right: unset; - left: 2px; - } + &.left { + right: unset; + left: 2px; } } } diff --git a/src/layout/card/grid/item/NitroCardGridItemView.tsx b/src/layout/card/grid/item/NitroCardGridItemView.tsx index a1e4b253..3713b490 100644 --- a/src/layout/card/grid/item/NitroCardGridItemView.tsx +++ b/src/layout/card/grid/item/NitroCardGridItemView.tsx @@ -1,27 +1,48 @@ -import { FC } from 'react'; +import { FC, useMemo } from 'react'; import { LimitedEditionStyledNumberView } from '../../../../views/shared/limited-edition/styled-number/LimitedEditionStyledNumberView'; -import { useNitroCardGridContext } from '../context'; -import { NitroCardGridThemes } from '../NitroCardGridView.types'; import { NitroCardGridItemViewProps } from './NitroCardGridItemView.types'; export const NitroCardGridItemView: FC = props => { - const { itemImage = undefined, itemColor = undefined, itemActive = false, itemCount = 1, itemUnique = false, itemUniqueNumber = 0, itemUnseen = false, columns = undefined, className = '', style = {}, children = null, ...rest } = props; - const { theme = NitroCardGridThemes.THEME_DEFAULT } = useNitroCardGridContext(); + const { itemImage = undefined, itemColor = undefined, itemActive = false, itemCount = 1, itemUniqueNumber = 0, itemUnseen = false, className = '', style = {}, children = null, ...rest } = props; - const imageUrl = `url(${ itemImage })`; + const getClassName = useMemo(() => + { + let newClassName = 'grid-item cursor-pointer overflow-hidden'; + + if(itemActive) newClassName += ' active'; + + if(itemUniqueNumber > 0) newClassName += ' unique-item'; + + if(itemUnseen) newClassName += ' unseen'; + + if(itemImage === null) newClassName += ' icon loading-icon'; + + if(className && className.length) newClassName += ' ' + className; + + return newClassName; + }, [ className, itemActive, itemUniqueNumber, itemUnseen, itemImage ]); + + const getStyle = useMemo(() => + { + const newStyle = { ...style }; + + if(itemImage) newStyle.backgroundImage = `url(${ itemImage })`; + + if(itemColor) newStyle.backgroundColor = itemColor; + + return newStyle; + }, [ style, itemImage, itemColor ]); return ( -
-
- { (itemCount > 1) && - { itemCount } } - { itemUnique && -
- -
} - { children } -
+
+ { (itemCount > 1) && + { itemCount } } + { (itemUniqueNumber > 0) && +
+ +
} + { children }
); } diff --git a/src/layout/card/grid/item/NitroCardGridItemView.types.ts b/src/layout/card/grid/item/NitroCardGridItemView.types.ts index bf005811..97861569 100644 --- a/src/layout/card/grid/item/NitroCardGridItemView.types.ts +++ b/src/layout/card/grid/item/NitroCardGridItemView.types.ts @@ -6,8 +6,6 @@ export interface NitroCardGridItemViewProps extends DetailsHTMLAttributes = pro }, [ model, category, setMaxPaletteCount ]); return ( - + { (category.parts.length > 0) && category.parts.map((item, index) => { return ; diff --git a/src/views/avatar-editor/views/model/AvatarEditorModelView.tsx b/src/views/avatar-editor/views/model/AvatarEditorModelView.tsx index 68e1645b..7bce299c 100644 --- a/src/views/avatar-editor/views/model/AvatarEditorModelView.tsx +++ b/src/views/avatar-editor/views/model/AvatarEditorModelView.tsx @@ -71,7 +71,7 @@ export const AvatarEditorModelView: FC = props =>
-
+
{ (maxPaletteCount >= 1) && } { (maxPaletteCount === 2) && diff --git a/src/views/avatar-editor/views/palette-set/AvatarEditorPaletteSetView.tsx b/src/views/avatar-editor/views/palette-set/AvatarEditorPaletteSetView.tsx index 65c2968f..8b32c044 100644 --- a/src/views/avatar-editor/views/palette-set/AvatarEditorPaletteSetView.tsx +++ b/src/views/avatar-editor/views/palette-set/AvatarEditorPaletteSetView.tsx @@ -1,6 +1,5 @@ import { FC, useCallback } from 'react'; import { NitroCardGridView } from '../../../../layout/card/grid/NitroCardGridView'; -import { NitroCardGridThemes } from '../../../../layout/card/grid/NitroCardGridView.types'; import { AvatarEditorGridColorItem } from '../../common/AvatarEditorGridColorItem'; import { AvatarEditorPaletteSetItem } from '../palette-set-item/AvatarEditorPaletteSetItem'; import { AvatarEditorPaletteSetViewProps } from './AvatarEditorPaletteSetView.types'; @@ -19,7 +18,7 @@ export const AvatarEditorPaletteSetView: FC = p }, [ model, category, paletteSet, paletteIndex ]); return ( - + { (paletteSet.length > 0) && paletteSet.map((item, index) => { return selectColor(item) } />; diff --git a/src/views/avatar-editor/views/wardrobe/AvatarEditorWardrobeView.tsx b/src/views/avatar-editor/views/wardrobe/AvatarEditorWardrobeView.tsx index fd0e756b..f6c4e68d 100644 --- a/src/views/avatar-editor/views/wardrobe/AvatarEditorWardrobeView.tsx +++ b/src/views/avatar-editor/views/wardrobe/AvatarEditorWardrobeView.tsx @@ -5,7 +5,6 @@ import { GetAvatarRenderManager, GetSessionDataManager } from '../../../../api'; import { SendMessageHook } from '../../../../hooks'; import { NitroCardGridItemView } from '../../../../layout/card/grid/item/NitroCardGridItemView'; import { NitroCardGridView } from '../../../../layout/card/grid/NitroCardGridView'; -import { NitroCardGridThemes } from '../../../../layout/card/grid/NitroCardGridView.types'; import { AvatarImageView } from '../../../shared/avatar-image/AvatarImageView'; import { CurrencyIcon } from '../../../shared/currency-icon/CurrencyIcon'; import { AvatarEditorWardrobeViewProps } from './AvatarEditorWardrobeView.types'; @@ -68,7 +67,7 @@ export const AvatarEditorWardrobeView: FC = props return (
- + { figures }
diff --git a/src/views/catalog/CatalogView.scss b/src/views/catalog/CatalogView.scss index 4061767a..ec71c0ad 100644 --- a/src/views/catalog/CatalogView.scss +++ b/src/views/catalog/CatalogView.scss @@ -1,11 +1,6 @@ .nitro-catalog { - width: 620px; - - .content-area { - min-height: 350px; - height: 350px; - resize: vertical; - } + width: $catalog-width; + height: $catalog-height; font[size="16"] { font-size: 20px; diff --git a/src/views/inventory/InventoryView.scss b/src/views/inventory/InventoryView.scss index 2da93ac4..8d5953d9 100644 --- a/src/views/inventory/InventoryView.scss +++ b/src/views/inventory/InventoryView.scss @@ -1,11 +1,6 @@ .nitro-inventory { - width: 475px; - - .content-area { - min-height: 240px; - height: 240px; - resize: vertical; - } + width: $inventory-width; + height: $inventory-height; .empty-image { background: url('../../assets/images/inventory/empty.png'); diff --git a/src/views/inventory/views/furniture/item/InventoryFurnitureItemView.tsx b/src/views/inventory/views/furniture/item/InventoryFurnitureItemView.tsx index 4b49d6a3..a75cf789 100644 --- a/src/views/inventory/views/furniture/item/InventoryFurnitureItemView.tsx +++ b/src/views/inventory/views/furniture/item/InventoryFurnitureItemView.tsx @@ -46,5 +46,5 @@ export const InventoryFurnitureItemView: FC = p const count = groupItem.getUnlockedCount(); - return ; + return ; } diff --git a/src/views/inventory/views/trade/InventoryTradeView.tsx b/src/views/inventory/views/trade/InventoryTradeView.tsx index 5969daec..c5f9b47d 100644 --- a/src/views/inventory/views/trade/InventoryTradeView.tsx +++ b/src/views/inventory/views/trade/InventoryTradeView.tsx @@ -233,7 +233,7 @@ export const InventoryTradeView: FC = props => const count = item.getUnlockedCount(); return ( - (count && setGroupItem(item)) }> + (count && setGroupItem(item)) }> { ((count > 0) && (groupItem === item)) && } + +
{ petBreedName }
+ + }
- { (petIndex === -1) && -
-
- -
-
{ GetCatalogPageText(pageParser, 0) }
-
} - { (petIndex >= 0) && -
- - { (petIndex > -1 && petIndex <= 7) && - } - -
{ petBreedName }
- -
}
); } diff --git a/src/views/catalog/views/page/layout/pets/purchase/CatalogLayoutPetPurchaseView.tsx b/src/views/catalog/views/page/layout/pets/purchase/CatalogLayoutPetPurchaseView.tsx index 9f1ebb31..c7b02518 100644 --- a/src/views/catalog/views/page/layout/pets/purchase/CatalogLayoutPetPurchaseView.tsx +++ b/src/views/catalog/views/page/layout/pets/purchase/CatalogLayoutPetPurchaseView.tsx @@ -6,6 +6,7 @@ import { useUiEvent } from '../../../../../../../hooks/events/ui/ui-event'; import { SendMessageHook } from '../../../../../../../hooks/messages/message-event'; import { CurrencyIcon } from '../../../../../../shared/currency-icon/CurrencyIcon'; import { CatalogPurchaseButtonView } from '../../../purchase/purchase-button/CatalogPurchaseButtonView'; +import { CatalogPurchaseGiftButtonView } from '../../../purchase/purchase-gift-button/CatalogPurchaseGiftButtonView'; import { CatalogPetNameApprovalView } from '../name-approval/CatalogPetNameApprovalView'; import { CatalogLayoutPetPurchaseViewProps } from './CatalogLayoutPetPurchaseView.types'; @@ -59,6 +60,8 @@ export const CatalogLayoutPetPurchaseView: FC
+ { offer.giftable && + }
diff --git a/src/views/catalog/views/page/layout/pets2/CatalogLayoutPets2View.scss b/src/views/catalog/views/page/layout/pets2/CatalogLayoutPets2View.scss deleted file mode 100644 index 1b85077d..00000000 --- a/src/views/catalog/views/page/layout/pets2/CatalogLayoutPets2View.scss +++ /dev/null @@ -1,2 +0,0 @@ -.nitro-catalog-layout-pets2 { -} diff --git a/src/views/catalog/views/page/layout/pets2/CatalogLayoutPets2View.tsx b/src/views/catalog/views/page/layout/pets2/CatalogLayoutPets2View.tsx index 3e901711..06dd970c 100644 --- a/src/views/catalog/views/page/layout/pets2/CatalogLayoutPets2View.tsx +++ b/src/views/catalog/views/page/layout/pets2/CatalogLayoutPets2View.tsx @@ -1,23 +1,8 @@ import { FC } from 'react'; -import { GetCatalogPageImage, GetCatalogPageText } from '../../../../common/CatalogUtilities'; +import { CatalogLayoutPets3View } from '../pets3/CatalogLayoutPets3View'; import { CatalogLayoutPets2ViewProps } from './CatalogLayoutPets2View.types'; export const CatalogLayoutPets2View: FC = props => { - const { pageParser = null } = props; - - return ( -
-
-
-
- -
-
{ GetCatalogPageText(pageParser, 1) }
-
-
- {GetCatalogPageText(pageParser, 3) &&
} -
-
- ); + return } diff --git a/src/views/catalog/views/page/layout/pets3/CatalogLayoutPets3View.scss b/src/views/catalog/views/page/layout/pets3/CatalogLayoutPets3View.scss deleted file mode 100644 index 2f2bc31c..00000000 --- a/src/views/catalog/views/page/layout/pets3/CatalogLayoutPets3View.scss +++ /dev/null @@ -1,2 +0,0 @@ -.nitro-catalog-layout-pets3 { -} diff --git a/src/views/catalog/views/page/layout/pets3/CatalogLayoutPets3View.tsx b/src/views/catalog/views/page/layout/pets3/CatalogLayoutPets3View.tsx index 23fa4048..94ab0a81 100644 --- a/src/views/catalog/views/page/layout/pets3/CatalogLayoutPets3View.tsx +++ b/src/views/catalog/views/page/layout/pets3/CatalogLayoutPets3View.tsx @@ -5,18 +5,24 @@ import { CatalogLayoutPets3ViewProps } from './CatalogLayoutPets3View.types'; export const CatalogLayoutPets3View: FC = props => { const { pageParser = null } = props; + + const imageUrl = GetCatalogPageImage(pageParser, 1); return ( -
-
-
-
- +
+
+
+
+ { imageUrl && } +
+
+
+
+
+
+
-
{ GetCatalogPageText(pageParser, 1) }
-
- {GetCatalogPageText(pageParser, 3) &&
}
); diff --git a/src/views/catalog/views/page/layout/single-bundle/CatalogLayoutSingleBundleView.scss b/src/views/catalog/views/page/layout/single-bundle/CatalogLayoutSingleBundleView.scss deleted file mode 100644 index 664041a9..00000000 --- a/src/views/catalog/views/page/layout/single-bundle/CatalogLayoutSingleBundleView.scss +++ /dev/null @@ -1,6 +0,0 @@ -.nitro-catalog-layout-single-bundle { - - .single-bundle-items-container { - - } -} diff --git a/src/views/catalog/views/page/layout/single-bundle/CatalogLayoutSingleBundleView.tsx b/src/views/catalog/views/page/layout/single-bundle/CatalogLayoutSingleBundleView.tsx index c85baeae..bab6711f 100644 --- a/src/views/catalog/views/page/layout/single-bundle/CatalogLayoutSingleBundleView.tsx +++ b/src/views/catalog/views/page/layout/single-bundle/CatalogLayoutSingleBundleView.tsx @@ -1,6 +1,7 @@ import { FC } from 'react'; -import { GetCatalogPageImage, GetCatalogPageText } from '../../../../common/CatalogUtilities'; +import { NitroCardGridView } from '../../../../../../layout'; import { useCatalogContext } from '../../../../context/CatalogContext'; +import { CatalogPageDetailsView } from '../../../page-details/CatalogPageDetailsView'; import { CatalogProductView } from '../../product/CatalogProductView'; import { CatalogPurchaseView } from '../../purchase/CatalogPurchaseView'; import { CatalogLayoutSingleBundleViewProps } from './CatalogLayoutSingleBundleView.types'; @@ -12,20 +13,17 @@ export const CatalogLayoutSingleBundleView: FC -
-
+
+
+ { activeOffer && activeOffer.products && (activeOffer.products.length > 0) && activeOffer.products.map((product, index) => { return }) } -
+
-
-
- -
-
{ GetCatalogPageText(pageParser, 0) }
+
+ { activeOffer && }
diff --git a/src/views/catalog/views/page/layout/spaces-new/CatalogLayoutSpacesView.scss b/src/views/catalog/views/page/layout/spaces-new/CatalogLayoutSpacesView.scss deleted file mode 100644 index ce1e1c03..00000000 --- a/src/views/catalog/views/page/layout/spaces-new/CatalogLayoutSpacesView.scss +++ /dev/null @@ -1,3 +0,0 @@ -.nitro-catalog-layout-spaces { - -} diff --git a/src/views/catalog/views/page/layout/spaces-new/CatalogLayoutSpacesView.tsx b/src/views/catalog/views/page/layout/spaces-new/CatalogLayoutSpacesView.tsx index c2c15a26..65da4622 100644 --- a/src/views/catalog/views/page/layout/spaces-new/CatalogLayoutSpacesView.tsx +++ b/src/views/catalog/views/page/layout/spaces-new/CatalogLayoutSpacesView.tsx @@ -1,12 +1,10 @@ import { CatalogPageMessageOfferData, IFurnitureData } from '@nitrots/nitro-renderer'; import { FC, useEffect, useState } from 'react'; import { GetSessionDataManager, LocalizeText } from '../../../../../../api'; -import { GetCatalogPageImage, GetCatalogPageText, GetOfferName } from '../../../../common/CatalogUtilities'; import { ProductTypeEnum } from '../../../../common/ProductTypeEnum'; import { useCatalogContext } from '../../../../context/CatalogContext'; -import { CatalogRoomPreviewerView } from '../../../catalog-room-previewer/CatalogRoomPreviewerView'; import { CatalogPageOffersView } from '../../offers/CatalogPageOffersView'; -import { CatalogPurchaseView } from '../../purchase/CatalogPurchaseView'; +import { CatalogProductPreviewView } from '../../product-preview/CatalogProductPreviewView'; import { CatalogLayoutSpacesViewProps } from './CatalogLayoutSpacesView.types'; export const CatalogLayoutSpacesView: FC = props => @@ -68,9 +66,9 @@ export const CatalogLayoutSpacesView: FC = props = const product = ((activeOffer && activeOffer.products[0]) || null); return ( -
-
-
+
+
+
{ groupNames.map((name, index) => { return @@ -78,19 +76,9 @@ export const CatalogLayoutSpacesView: FC = props =
- { !product && -
-
- -
-
{ GetCatalogPageText(pageParser, 0) }
-
} - { product && -
- -
{ GetOfferName(activeOffer) }
- -
} +
+ +
); } diff --git a/src/views/catalog/views/page/layout/trophies/CatalogLayoutTrophiesView.scss b/src/views/catalog/views/page/layout/trophies/CatalogLayoutTrophiesView.scss deleted file mode 100644 index 58637ed9..00000000 --- a/src/views/catalog/views/page/layout/trophies/CatalogLayoutTrophiesView.scss +++ /dev/null @@ -1,8 +0,0 @@ -.nitro-catalog-layout-trophies { - - textarea { - height: 119px; - resize: none; - } - -} diff --git a/src/views/catalog/views/page/layout/trophies/CatalogLayoutTrophiesView.tsx b/src/views/catalog/views/page/layout/trophies/CatalogLayoutTrophiesView.tsx index 471001a1..03379cf0 100644 --- a/src/views/catalog/views/page/layout/trophies/CatalogLayoutTrophiesView.tsx +++ b/src/views/catalog/views/page/layout/trophies/CatalogLayoutTrophiesView.tsx @@ -1,9 +1,7 @@ import { FC, useState } from 'react'; -import { GetOfferName } from '../../../../common/CatalogUtilities'; import { useCatalogContext } from '../../../../context/CatalogContext'; -import { CatalogRoomPreviewerView } from '../../../catalog-room-previewer/CatalogRoomPreviewerView'; import { CatalogPageOffersView } from '../../offers/CatalogPageOffersView'; -import { CatalogPurchaseView } from '../../purchase/CatalogPurchaseView'; +import { CatalogProductPreviewView } from '../../product-preview/CatalogProductPreviewView'; import { CatalogLayoutTrophiesViewProps } from './CatalogLayoutTrophiesView.types'; export const CatalogLayoutTrophiesView: FC = props => @@ -16,19 +14,14 @@ export const CatalogLayoutTrophiesView: FC = pro const product = ((activeOffer && activeOffer.products[0]) || null); return ( -
-
+
+
-
- -
+