diff --git a/package.json b/package.json index c03ac7f7..4b9c54ae 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "@fortawesome/fontawesome-svg-core": "^6.1.0", "@fortawesome/free-solid-svg-icons": "^6.1.0", "@fortawesome/react-fontawesome": "^0.1.17", - "@nitrots/nitro-renderer": "^1.1.13", + "@nitrots/nitro-renderer": "^1.1.14", "animate.css": "^4.1.1", "classnames": "^2.3.1", "cross-env": "^7.0.3", diff --git a/public/index.html b/public/index.html index 04f4d7b3..d4019e89 100644 --- a/public/index.html +++ b/public/index.html @@ -23,7 +23,10 @@ diff --git a/src/common/card/NitroCardView.scss b/src/common/card/NitroCardView.scss index 0d886814..7e925038 100644 --- a/src/common/card/NitroCardView.scss +++ b/src/common/card/NitroCardView.scss @@ -179,6 +179,7 @@ $nitro-card-tabs-height: 33px; .nitro-card-tabs { height: 100%; + min-height: $nitro-card-tabs-height; max-height: $nitro-card-tabs-height; border-bottom: $nav-tabs-border-width solid $nav-tabs-border-color; } diff --git a/src/components/catalog/views/page/widgets/CatalogPurchaseWidgetView.tsx b/src/components/catalog/views/page/widgets/CatalogPurchaseWidgetView.tsx index 1fd376b1..4691b8a2 100644 --- a/src/components/catalog/views/page/widgets/CatalogPurchaseWidgetView.tsx +++ b/src/components/catalog/views/page/widgets/CatalogPurchaseWidgetView.tsx @@ -171,7 +171,7 @@ export const CatalogPurchaseWidgetView: FC = pro switch(purchaseState) { case CatalogPurchaseState.CONFIRM: - return ; + return ; case CatalogPurchaseState.PURCHASE: return ; case CatalogPurchaseState.FAILED: diff --git a/src/components/groups/GroupsView.tsx b/src/components/groups/GroupsView.tsx index 224fbc20..397d49bf 100644 --- a/src/components/groups/GroupsView.tsx +++ b/src/components/groups/GroupsView.tsx @@ -93,14 +93,12 @@ export const GroupsView: FC<{}> = props => return ( -
- { isCreatorVisible && - setCreatorVisible(false) } /> } - { !isCreatorVisible && - } - - -
+ { isCreatorVisible && + setCreatorVisible(false) } /> } + { !isCreatorVisible && + } + +
); }; diff --git a/src/components/navigator/NavigatorContext.tsx b/src/components/navigator/NavigatorContext.tsx index 99fe9267..8505e701 100644 --- a/src/components/navigator/NavigatorContext.tsx +++ b/src/components/navigator/NavigatorContext.tsx @@ -1,15 +1,32 @@ -import { createContext, Dispatch, FC, ProviderProps, useContext } from 'react'; -import { INavigatorAction, INavigatorState } from './reducers/NavigatorReducer'; +import { NavigatorCategoryDataParser, NavigatorSearchResultSet, NavigatorTopLevelContext } from '@nitrots/nitro-renderer'; +import { createContext, Dispatch, FC, ProviderProps, SetStateAction, useContext } from 'react'; +import { NavigatorData } from './common/NavigatorData'; interface INavigatorContext { - navigatorState: INavigatorState; - dispatchNavigatorState: Dispatch; + categories: NavigatorCategoryDataParser[]; + setCategories: Dispatch>; + topLevelContext: NavigatorTopLevelContext; + setTopLevelContext: Dispatch>; + topLevelContexts: NavigatorTopLevelContext[]; + setTopLevelContexts: Dispatch>; + navigatorData: NavigatorData; + setNavigatorData: Dispatch>; + searchResult: NavigatorSearchResultSet; + setSearchResult: Dispatch>; } const NavigatorContext = createContext({ - navigatorState: null, - dispatchNavigatorState: null + categories: null, + setCategories: null, + topLevelContext: null, + setTopLevelContext: null, + topLevelContexts: null, + setTopLevelContexts: null, + navigatorData: null, + setNavigatorData: null, + searchResult: null, + setSearchResult: null }); export const NavigatorContextProvider: FC> = props => diff --git a/src/components/navigator/NavigatorMessageHandler.tsx b/src/components/navigator/NavigatorMessageHandler.tsx index b50810d5..d3a4a5f8 100644 --- a/src/components/navigator/NavigatorMessageHandler.tsx +++ b/src/components/navigator/NavigatorMessageHandler.tsx @@ -1,14 +1,38 @@ -import { CantConnectMessageParser, GenericErrorEvent, GetGuestRoomResultEvent, LegacyExternalInterface, NavigatorCategoriesComposer, NavigatorCategoriesEvent, NavigatorHomeRoomEvent, NavigatorMetadataEvent, NavigatorOpenRoomCreatorEvent, NavigatorSearchEvent, NavigatorSettingsComposer, RoomCreatedEvent, RoomDataParser, RoomDoorbellAcceptedEvent, RoomDoorbellEvent, RoomDoorbellRejectedEvent, RoomEnterErrorEvent, RoomEntryInfoMessageEvent, RoomForwardEvent, RoomInfoComposer, RoomScoreEvent, RoomSettingsUpdatedEvent, UserInfoEvent } from '@nitrots/nitro-renderer'; +import { CanCreateRoomEventEvent, CantConnectMessageParser, FollowFriendMessageComposer, GenericErrorEvent, GetGuestRoomResultEvent, HabboWebTools, LegacyExternalInterface, NavigatorCategoriesComposer, NavigatorCategoriesEvent, NavigatorHomeRoomEvent, NavigatorMetadataEvent, NavigatorOpenRoomCreatorEvent, NavigatorSearchEvent, NavigatorSettingsComposer, RoomCreatedEvent, RoomDataParser, RoomDoorbellAcceptedEvent, RoomDoorbellEvent, RoomDoorbellRejectedEvent, RoomEnterErrorEvent, RoomEntryInfoMessageEvent, RoomForwardEvent, RoomInfoComposer, RoomScoreEvent, RoomSettingsUpdatedEvent, SecurityLevel, UserInfoEvent, UserPermissionsEvent } from '@nitrots/nitro-renderer'; import { FC, useCallback } from 'react'; -import { CreateRoomSession, GetSessionDataManager, LocalizeText, NotificationAlertType, NotificationUtilities, SendMessageComposer, VisitDesktop } from '../../api'; -import { NavigatorEvent, UpdateDoorStateEvent } from '../../events'; -import { DispatchUiEvent, UseMessageEventHook } from '../../hooks'; +import { CreateLinkEvent, CreateRoomSession, GetConfiguration, GetSessionDataManager, LocalizeText, NotificationAlertType, NotificationUtilities, SendMessageComposer, TryVisitRoom, VisitDesktop } from '../../api'; +import { UpdateDoorStateEvent } from '../../events'; +import { BatchUpdates, DispatchUiEvent, UseMessageEventHook } from '../../hooks'; import { useNavigatorContext } from './NavigatorContext'; -import { NavigatorActions } from './reducers/NavigatorReducer'; export const NavigatorMessageHandler: FC<{}> = props => { - const { navigatorState = null, dispatchNavigatorState = null } = useNavigatorContext(); + const { setCategories = null, setTopLevelContext = null, topLevelContexts = null, setTopLevelContexts = null, setNavigatorData = null, setSearchResult = null } = useNavigatorContext(); + + const onRoomSettingsUpdatedEvent = useCallback((event: RoomSettingsUpdatedEvent) => + { + const parser = event.getParser(); + + SendMessageComposer(new RoomInfoComposer(parser.roomId, false, false)); + }, []); + + UseMessageEventHook(RoomSettingsUpdatedEvent, onRoomSettingsUpdatedEvent); + + const onCanCreateRoomEventEvent = useCallback((event: CanCreateRoomEventEvent) => + { + const parser = event.getParser(); + + if(parser.canCreate) + { + // show room event cvreate + + return; + } + + NotificationUtilities.simpleAlert(LocalizeText(`navigator.cannotcreateevent.error.${ parser.errorCode }`), null, null, null, LocalizeText('navigator.cannotcreateevent.title')); + }, []); + + UseMessageEventHook(CanCreateRoomEventEvent, onCanCreateRoomEventEvent); const onUserInfoEvent = useCallback((event: UserInfoEvent) => { @@ -16,32 +40,51 @@ export const NavigatorMessageHandler: FC<{}> = props => SendMessageComposer(new NavigatorSettingsComposer()); }, []); + const onUserPermissionsEvent = useCallback((event: UserPermissionsEvent) => + { + const parser = event.getParser(); + + setNavigatorData(prevValue => + { + const newValue = { ...prevValue }; + + newValue.eventMod = (parser.securityLevel >= SecurityLevel.MODERATOR); + newValue.roomPicker = (parser.securityLevel >= SecurityLevel.COMMUNITY); + + return newValue; + }); + }, [ setNavigatorData ]); + const onRoomForwardEvent = useCallback((event: RoomForwardEvent) => { const parser = event.getParser(); - SendMessageComposer(new RoomInfoComposer(parser.roomId, false, true)); + TryVisitRoom(parser.roomId); }, []); const onRoomEntryInfoMessageEvent = useCallback((event: RoomEntryInfoMessageEvent) => { const parser = event.getParser(); - const roomInfoData = navigatorState.roomInfoData; - roomInfoData.currentRoomOwner = parser.isOwner; - roomInfoData.currentRoomId = parser.roomId; + setNavigatorData(prevValue => + { + const newValue = { ...prevValue }; - dispatchNavigatorState({ - type: NavigatorActions.SET_ROOM_INFO_DATA, - payload: { - roomInfoData: roomInfoData - } - }); + newValue.enteredGuestRoom = null; + newValue.currentRoomOwner = parser.isOwner; + newValue.currentRoomId = parser.roomId; + + return newValue; + }); + + // close room info + // close room settings + // close room filter SendMessageComposer(new RoomInfoComposer(parser.roomId, true, false)); if(LegacyExternalInterface.available) LegacyExternalInterface.call('legacyTrack', 'navigator', 'private', [ parser.roomId ]); - }, [ navigatorState, dispatchNavigatorState ]); + }, [ setNavigatorData ]); const onGetGuestRoomResultEvent = useCallback((event: GetGuestRoomResultEvent) => { @@ -49,15 +92,29 @@ export const NavigatorMessageHandler: FC<{}> = props => if(parser.roomEnter) { - const roomInfoData = navigatorState.roomInfoData; - roomInfoData.enteredGuestRoom = parser.data; + setNavigatorData(prevValue => + { + const newValue = { ...prevValue }; - dispatchNavigatorState({ - type: NavigatorActions.SET_ROOM_INFO_DATA, - payload: { - roomInfoData: roomInfoData - } - }); + newValue.enteredGuestRoom = parser.data; + newValue.currentRoomIsStaffPick = parser.staffPick; + + const isCreated = (newValue.createdFlatId === parser.data.roomId); + + if(!isCreated && parser.data.displayRoomEntryAd) + { + if(GetConfiguration('roomenterad.habblet.enabled', false)) HabboWebTools.openRoomEnterAd(); + } + + newValue.createdFlatId = 0; + + if(newValue.enteredGuestRoom && (newValue.enteredGuestRoom.habboGroupId > 0)) + { + // close event info + } + + return newValue; + }); } else if(parser.roomForward) { @@ -74,26 +131,38 @@ export const NavigatorMessageHandler: FC<{}> = props => } } + if((parser.data.doorMode === RoomDataParser.NOOB_STATE) && !GetSessionDataManager().isAmbassador && !GetSessionDataManager().isRealNoob && !GetSessionDataManager().isModerator) return; + CreateRoomSession(parser.data.roomId); } else { - const roomInfoData = navigatorState.roomInfoData; - roomInfoData.enteredGuestRoom = parser.data; + setNavigatorData(prevValue => + { + const newValue = { ...prevValue }; - dispatchNavigatorState({ - type: NavigatorActions.SET_ROOM_INFO_DATA, - payload: { - roomInfoData: roomInfoData - } - }); + newValue.enteredGuestRoom = parser.data; + newValue.currentRoomIsStaffPick = parser.staffPick; + + return newValue; + }); } - }, [ dispatchNavigatorState, navigatorState ]); + }, [ setNavigatorData ]); const onRoomScoreEvent = useCallback((event: RoomScoreEvent) => { const parser = event.getParser(); - }, [ ]); + + setNavigatorData(prevValue => + { + const newValue = { ...prevValue }; + + newValue.currentRoomRating = parser.totalLikes; + newValue.canRate = parser.canLike; + + return newValue; + }); + }, [ setNavigatorData ]); const onRoomDoorbellEvent = useCallback((event: RoomDoorbellEvent) => { @@ -141,37 +210,57 @@ export const NavigatorMessageHandler: FC<{}> = props => { const parser = event.getParser(); - dispatchNavigatorState({ - type: NavigatorActions.SET_TOP_LEVEL_CONTEXTS, - payload: { - topLevelContexts: parser.topLevelContexts - } + BatchUpdates(() => + { + setTopLevelContexts(parser.topLevelContexts); + setTopLevelContext(parser.topLevelContexts.length ? parser.topLevelContexts[0] : null); }); - }, [ dispatchNavigatorState ]); + }, [ setTopLevelContexts, setTopLevelContext ]); const onNavigatorSearchEvent = useCallback((event: NavigatorSearchEvent) => { const parser = event.getParser(); - dispatchNavigatorState({ - type: NavigatorActions.SET_SEARCH_RESULT, - payload: { - searchResult: parser.result - } + BatchUpdates(() => + { + setTopLevelContext(prevValue => + { + let newValue = prevValue; + + if(!newValue) newValue = ((topLevelContexts && topLevelContexts.length && topLevelContexts[0]) || null); + + if(!newValue) return null; + + if((parser.result.code !== newValue.code) && topLevelContexts && topLevelContexts.length) + { + for(const context of topLevelContexts) + { + if(context.code !== parser.result.code) continue; + + newValue = context; + } + } + + for(const context of topLevelContexts) + { + if(context.code !== parser.result.code) continue; + + newValue = context; + } + + return newValue; + }); + + setSearchResult(parser.result); }); - }, [ dispatchNavigatorState ]); + }, [ topLevelContexts, setTopLevelContext, setSearchResult ]); const onNavigatorCategoriesEvent = useCallback((event: NavigatorCategoriesEvent) => { const parser = event.getParser(); - dispatchNavigatorState({ - type: NavigatorActions.SET_CATEGORIES, - payload: { - categories: parser.categories - } - }); - }, [ dispatchNavigatorState ]); + setCategories(parser.categories); + }, [ setCategories ]); const onRoomCreatedEvent = useCallback((event: RoomCreatedEvent) => { @@ -184,20 +273,63 @@ export const NavigatorMessageHandler: FC<{}> = props => { const parser = event.getParser(); - dispatchNavigatorState({ - type: NavigatorActions.SET_HOME_ROOM_ID, - payload: { - homeRoomId: parser.homeRoomId + let prevSettingsReceived = false; + + setNavigatorData(prevValue => + { + prevSettingsReceived = prevValue.settingsReceived; + + const newValue = { ...prevValue }; + + newValue.homeRoomId = parser.homeRoomId; + newValue.settingsReceived = true; + + return newValue; + }); + + if(prevSettingsReceived) + { + // refresh room info window + return; + } + + let forwardType = -1; + let forwardId = -1; + + if(GetConfiguration('friend.id') !== undefined) + { + forwardType = 0; + SendMessageComposer(new FollowFriendMessageComposer(parseInt(GetConfiguration('friend.id')))); + } + + if((GetConfiguration('forward.type') !== undefined) && (GetConfiguration('forward.id') !== undefined)) + { + forwardType = parseInt(GetConfiguration('forward.type')); + forwardId = parseInt(GetConfiguration('forward.id')) + } + + if(forwardType === 2) + { + TryVisitRoom(forwardId); + } + + else if((forwardType === -1) && (parser.roomIdToEnter > 0)) + { + CreateLinkEvent('navigator/close'); + CreateRoomSession(parser.roomIdToEnter); + + if(parser.roomIdToEnter !== parser.homeRoomId) + { + CreateLinkEvent('navigator/close'); + CreateRoomSession(parser.roomIdToEnter); } - }); - }, [ dispatchNavigatorState ]); - - const onRoomSettingsUpdatedEvent = useCallback((event: RoomSettingsUpdatedEvent) => - { - const parser = event.getParser(); - - SendMessageComposer(new RoomInfoComposer(parser.roomId, false, false)); - }, []); + else + { + CreateLinkEvent('navigator/close'); + CreateRoomSession(parser.homeRoomId); + } + } + }, [ setNavigatorData ]); const onRoomEnterErrorEvent = useCallback((event: RoomEnterErrorEvent) => { @@ -226,12 +358,13 @@ export const NavigatorMessageHandler: FC<{}> = props => VisitDesktop(); }, []); - const onRoomCreatorEvent = useCallback((event: RoomEnterErrorEvent) => + const onRoomCreatorEvent = useCallback((event: NavigatorOpenRoomCreatorEvent) => { - DispatchUiEvent(new NavigatorEvent(NavigatorEvent.SHOW_ROOM_CREATOR)); - },[]); + CreateLinkEvent('navigator/show'); + }, []); UseMessageEventHook(UserInfoEvent, onUserInfoEvent); + UseMessageEventHook(UserPermissionsEvent, onUserPermissionsEvent); UseMessageEventHook(RoomForwardEvent, onRoomForwardEvent); UseMessageEventHook(RoomEntryInfoMessageEvent, onRoomEntryInfoMessageEvent); UseMessageEventHook(GetGuestRoomResultEvent, onGetGuestRoomResultEvent); @@ -245,7 +378,6 @@ export const NavigatorMessageHandler: FC<{}> = props => UseMessageEventHook(NavigatorCategoriesEvent, onNavigatorCategoriesEvent); UseMessageEventHook(RoomCreatedEvent, onRoomCreatedEvent); UseMessageEventHook(NavigatorHomeRoomEvent, onNavigatorHomeRoomEvent); - UseMessageEventHook(RoomSettingsUpdatedEvent, onRoomSettingsUpdatedEvent); UseMessageEventHook(RoomEnterErrorEvent, onRoomEnterErrorEvent); UseMessageEventHook(NavigatorOpenRoomCreatorEvent, onRoomCreatorEvent); diff --git a/src/components/navigator/NavigatorView.tsx b/src/components/navigator/NavigatorView.tsx index 2a40f9ba..97571333 100644 --- a/src/components/navigator/NavigatorView.tsx +++ b/src/components/navigator/NavigatorView.tsx @@ -1,64 +1,52 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { ConvertGlobalRoomIdMessageComposer, HabboWebTools, ILinkEventTracker, LegacyExternalInterface, NavigatorInitComposer, NavigatorSearchComposer, RoomDataParser, RoomSessionEvent } from '@nitrots/nitro-renderer'; -import { FC, useCallback, useEffect, useMemo, useReducer, useState } from 'react'; -import { AddEventLinkTracker, CreateLinkEvent, GoToDesktop, LocalizeText, RemoveLinkEventTracker, SendMessageComposer, TryVisitRoom } from '../../api'; -import { Column, NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../common'; -import { NavigatorEvent, UpdateDoorStateEvent } from '../../events'; -import { BatchUpdates, UseMountEffect, UseRoomSessionManagerEvent, UseUiEvent } from '../../hooks'; +import { ConvertGlobalRoomIdMessageComposer, HabboWebTools, ILinkEventTracker, LegacyExternalInterface, NavigatorCategoryDataParser, NavigatorInitComposer, NavigatorSearchComposer, NavigatorSearchResultSet, NavigatorTopLevelContext, RoomDataParser, RoomSessionEvent } from '@nitrots/nitro-renderer'; +import { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import { AddEventLinkTracker, GoToDesktop, LocalizeText, RemoveLinkEventTracker, SendMessageComposer, TryVisitRoom } from '../../api'; +import { Base, Column, NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../common'; +import { UpdateDoorStateEvent } from '../../events'; +import { BatchUpdates, UseRoomSessionManagerEvent, useSharedState, UseUiEvent } from '../../hooks'; +import { NavigatorData } from './common/NavigatorData'; import { NavigatorContextProvider } from './NavigatorContext'; import { NavigatorMessageHandler } from './NavigatorMessageHandler'; -import { initialNavigator, NavigatorActions, NavigatorReducer } from './reducers/NavigatorReducer'; -import { NavigatorRoomCreatorView } from './views/creator/NavigatorRoomCreatorView'; -import { NavigatorRoomDoorbellView } from './views/room-doorbell/NavigatorRoomDoorbellView'; -import { NavigatorRoomInfoView } from './views/room-info/NavigatorRoomInfoView'; -import { NavigatorRoomLinkView } from './views/room-link/NavigatorRoomLinkView'; -import { NavigatorRoomPasswordView } from './views/room-password/NavigatorRoomPasswordView'; +import { NavigatorRoomCreatorView } from './views/NavigatorRoomCreatorView'; +import { NavigatorRoomDoorbellView } from './views/NavigatorRoomDoorbellView'; +import { NavigatorRoomInfoView } from './views/NavigatorRoomInfoView'; +import { NavigatorRoomLinkView } from './views/NavigatorRoomLinkView'; +import { NavigatorRoomPasswordView } from './views/NavigatorRoomPasswordView'; import { NavigatorRoomSettingsView } from './views/room-settings/NavigatorRoomSettingsView'; -import { NavigatorSearchResultView } from './views/search-result/NavigatorSearchResultView'; -import { LAST_SEARCH, NavigatorSearchView } from './views/search/NavigatorSearchView'; +import { NavigatorSearchResultView } from './views/search/NavigatorSearchResultView'; +import { NavigatorSearchView } from './views/search/NavigatorSearchView'; export const NavigatorView: FC<{}> = props => { const [ isVisible, setIsVisible ] = useState(false); + const [ isReady, setIsReady ] = useState(false); const [ isCreatorOpen, setCreatorOpen ] = useState(false); const [ isRoomInfoOpen, setRoomInfoOpen ] = useState(false); const [ isRoomLinkOpen, setRoomLinkOpen ] = useState(false); + const [ isLoading, setIsLoading ] = useState(false); + const [ needsInit, setNeedsInit ] = useState(true); + const [ needsSearch, setNeedsSearch ] = useState(false); + const [ categories, setCategories ] = useState(null); + const [ topLevelContext, setTopLevelContext ] = useState(null); + const [ topLevelContexts, setTopLevelContexts ] = useState(null); + const [ navigatorData, setNavigatorData ] = useSharedState('@navigatorData', { + settingsReceived: false, + homeRoomId: 0, + enteredGuestRoom: null, + currentRoomOwner: false, + currentRoomId: 0, + currentRoomIsStaffPick: false, + createdFlatId: 0, + avatarId: 0, + roomPicker: false, + eventMod: false, + currentRoomRating: 0, + canRate: true + }); + const [ searchResult, setSearchResult ] = useState(null); const [ pendingDoorState, setPendingDoorState ] = useState<{ roomData: RoomDataParser, state: string }>(null); - const [ navigatorState, dispatchNavigatorState ] = useReducer(NavigatorReducer, initialNavigator); - const { needsNavigatorUpdate = true, topLevelContext = null, topLevelContexts = null, homeRoomId } = navigatorState; - - const onNavigatorEvent = useCallback((event: NavigatorEvent) => - { - switch(event.type) - { - case NavigatorEvent.SHOW_NAVIGATOR: - setIsVisible(true); - return; - case NavigatorEvent.HIDE_NAVIGATOR: - setIsVisible(false); - return; - case NavigatorEvent.TOGGLE_NAVIGATOR: - setIsVisible(value => !value); - return; - case NavigatorEvent.TOGGLE_ROOM_INFO: - setRoomInfoOpen(value => !value); - return; - case NavigatorEvent.TOGGLE_ROOM_LINK: - setRoomLinkOpen(value => !value); - return; - case NavigatorEvent.SHOW_ROOM_CREATOR: - setIsVisible(true); - setCreatorOpen(true); - return; - } - }, []); - - UseUiEvent(NavigatorEvent.SHOW_NAVIGATOR, onNavigatorEvent); - UseUiEvent(NavigatorEvent.HIDE_NAVIGATOR, onNavigatorEvent); - UseUiEvent(NavigatorEvent.TOGGLE_NAVIGATOR, onNavigatorEvent); - UseUiEvent(NavigatorEvent.TOGGLE_ROOM_INFO, onNavigatorEvent); - UseUiEvent(NavigatorEvent.TOGGLE_ROOM_LINK, onNavigatorEvent); - UseUiEvent(NavigatorEvent.SHOW_ROOM_CREATOR, onNavigatorEvent); + const pendingSearch = useRef<{ value: string, code: string }>(null); const onUpdateDoorStateEvent = useCallback((event: UpdateDoorStateEvent) => { @@ -108,26 +96,67 @@ export const NavigatorView: FC<{}> = props => switch(event.type) { case RoomSessionEvent.CREATED: - setIsVisible(false); - setCreatorOpen(false); + BatchUpdates(() => + { + setIsVisible(false); + setCreatorOpen(false); + }); return; } }, []); UseRoomSessionManagerEvent(RoomSessionEvent.CREATED, onRoomSessionEvent); + const closePendingDoorState = useCallback((state: string) => + { + if(state !== null) + { + setPendingDoorState(prevValue => + { + return { ...prevValue, state }; + }); + } + else setPendingDoorState(null); + }, []); + const sendSearch = useCallback((searchValue: string, contextCode: string) => { setCreatorOpen(false); + SendMessageComposer(new NavigatorSearchComposer(contextCode, searchValue)); + + setIsLoading(true); }, []); - const goToHomeRoom = useCallback(() => + const reloadCurrentSearch = useCallback(() => { - if(homeRoomId <= 0) return; + if(!isReady) + { + setNeedsSearch(true); + + return; + } - TryVisitRoom(homeRoomId); - }, [ homeRoomId ]); + if(pendingSearch.current) + { + sendSearch(pendingSearch.current.value, pendingSearch.current.code); + + pendingSearch.current = null; + + return; + } + + if(searchResult) + { + sendSearch(searchResult.data, searchResult.code); + + return; + } + + if(!topLevelContext) return; + + sendSearch('', topLevelContext.code); + }, [ isReady, searchResult, topLevelContext, sendSearch ]); const linkReceived = useCallback((url: string) => { @@ -137,19 +166,52 @@ export const NavigatorView: FC<{}> = props => switch(parts[1]) { - case 'goto': - if(parts.length > 2) + case 'show': { + BatchUpdates(() => { - switch(parts[2]) - { - case 'home': - goToHomeRoom(); - break; - default: { - const roomId = parseInt(parts[2]); + setIsVisible(true); + setNeedsSearch(true); + }); + return; + } + case 'hide': + setIsVisible(false); + return; + case 'toggle': { + if(isVisible) + { + setIsVisible(false); - TryVisitRoom(roomId); - } + return; + } + + BatchUpdates(() => + { + setIsVisible(true); + setNeedsSearch(true); + }); + return; + } + case 'toggle-room-info': + setRoomInfoOpen(value => !value); + return; + case 'toggle-room-link': + setRoomLinkOpen(value => !value); + return; + case 'goto': + if(parts.length <= 2) return; + + switch(parts[2]) + { + case 'home': + if(navigatorData.homeRoomId <= 0) return; + + TryVisitRoom(navigatorData.homeRoomId); + break; + default: { + const roomId = parseInt(parts[2]); + + TryVisitRoom(roomId); } } return; @@ -169,24 +231,17 @@ export const NavigatorView: FC<{}> = props => if(parts.length > 3) searchValue = parts[3]; - setIsVisible(true); - sendSearch(searchValue, topLevelContextCode); + pendingSearch.current = { value: searchValue, code: topLevelContextCode }; + + BatchUpdates(() => + { + setIsVisible(true); + setNeedsSearch(true); + }); } return; } - }, [ goToHomeRoom, sendSearch ]); - - const closePendingDoorState = useCallback((state: string) => - { - if(state !== null) - { - setPendingDoorState(prevValue => - { - return { roomData: prevValue.roomData, state }; - }); - } - else setPendingDoorState(null); - }, []); + }, [ isVisible, navigatorData.homeRoomId ]); useEffect(() => { @@ -198,52 +253,44 @@ export const NavigatorView: FC<{}> = props => AddEventLinkTracker(linkTracker); return () => RemoveLinkEventTracker(linkTracker); - }, [ linkReceived]); - - const enterRoomWebRequest = useCallback((k: string, _arg_2:boolean=false, _arg_3:string=null) => - { - SendMessageComposer(new ConvertGlobalRoomIdMessageComposer(k)); - }, []); - - UseMountEffect(() => - { - LegacyExternalInterface.addCallback(HabboWebTools.OPENROOM, enterRoomWebRequest); - }); + }, [ linkReceived ]); useEffect(() => { - if(!needsNavigatorUpdate) return; - - dispatchNavigatorState({ - type: NavigatorActions.SET_NEEDS_UPDATE, - payload: { - flag: false - } - }); + if(!searchResult) return; + + setIsLoading(false); + }, [ searchResult ]); + + useEffect(() => + { + if(!isVisible || !isReady || !needsSearch) return; + + reloadCurrentSearch(); + + setNeedsSearch(false); + }, [ isVisible, isReady, needsSearch, reloadCurrentSearch ]); + + useEffect(() => + { + if(isReady || !topLevelContext) return; + + setIsReady(true); + }, [ isReady, topLevelContext ]); + + useEffect(() => + { + if(!isVisible || !needsInit) return; SendMessageComposer(new NavigatorInitComposer()); - }, [ needsNavigatorUpdate ]); + + setNeedsInit(false); + }, [ isVisible, needsInit ]); useEffect(() => { - if(!isVisible || !topLevelContext) return; - - sendSearch('', topLevelContext.code); - }, [isVisible, sendSearch, topLevelContext]) - - useEffect(() => - { - if(!topLevelContexts || !topLevelContexts.length) return; - - sendSearch('', topLevelContexts[0].code); - }, [ topLevelContexts, sendSearch ]); - - useEffect(() => - { - if(!isVisible || !LAST_SEARCH || !LAST_SEARCH.length) return; - - CreateLinkEvent(`navigator/search/${ LAST_SEARCH }`); - }, [ isVisible ]); + LegacyExternalInterface.addCallback(HabboWebTools.OPENROOM, (k: string, _arg_2: boolean = false, _arg_3: string = null) => SendMessageComposer(new ConvertGlobalRoomIdMessageComposer(k))); + }, []); const getRoomDoorState = useMemo(() => { @@ -264,7 +311,7 @@ export const NavigatorView: FC<{}> = props => }, [ pendingDoorState, closePendingDoorState ]); return ( - + { getRoomDoorState } { isVisible && @@ -283,12 +330,14 @@ export const NavigatorView: FC<{}> = props => - + + { isLoading && + } { !isCreatorOpen && <> - { (navigatorState.searchResult && navigatorState.searchResult.results.map((result, index) => )) } + { (searchResult && searchResult.results.map((result, index) => )) } } { isCreatorOpen && } diff --git a/src/components/navigator/common/NavigatorData.ts b/src/components/navigator/common/NavigatorData.ts new file mode 100644 index 00000000..64fdd568 --- /dev/null +++ b/src/components/navigator/common/NavigatorData.ts @@ -0,0 +1,17 @@ +import { RoomDataParser } from '@nitrots/nitro-renderer'; + +export interface NavigatorData +{ + homeRoomId: number; + settingsReceived: boolean; + enteredGuestRoom: RoomDataParser; + currentRoomOwner: boolean; + currentRoomId: number; + currentRoomIsStaffPick: boolean; + createdFlatId: number; + avatarId: number; + roomPicker: boolean; + eventMod: boolean; + currentRoomRating: number; + canRate: boolean; +} diff --git a/src/components/navigator/common/RoomSettingsData.ts b/src/components/navigator/common/RoomSettingsData.ts index 7144458f..0a039baa 100644 --- a/src/components/navigator/common/RoomSettingsData.ts +++ b/src/components/navigator/common/RoomSettingsData.ts @@ -33,7 +33,7 @@ export default class RoomSettingsData public muteState: number; public kickState: number; public banState: number; - public bannedUsers: Map; + public bannedUsers: any[]; public selectedUserToUnban: number; constructor(parser: RoomSettingsParser) @@ -71,6 +71,6 @@ export default class RoomSettingsData this.muteState = parser.moderationSettings.allowMute; this.kickState = parser.moderationSettings.allowKick; this.banState = parser.moderationSettings.allowBan; - this.bannedUsers = new Map(); + this.bannedUsers = []; } } diff --git a/src/components/navigator/common/RoomSettingsUtils.ts b/src/components/navigator/common/RoomSettingsUtils.ts index 567c54fe..bc611dad 100644 --- a/src/components/navigator/common/RoomSettingsUtils.ts +++ b/src/components/navigator/common/RoomSettingsUtils.ts @@ -1,11 +1,10 @@ -export function GetMaxVisitorsList(): number[] +const BuildMaxVisitorsList = () => { const list: number[] = []; - for(let i = 10; i <= 100; i = i + 10) - { - list.push(i); - } + for(let i = 10; i <= 100; i = i + 10) list.push(i); return list; } + +export const GetMaxVisitorsList = BuildMaxVisitorsList(); diff --git a/src/components/navigator/reducers/NavigatorReducer.tsx b/src/components/navigator/reducers/NavigatorReducer.tsx deleted file mode 100644 index df1f10c8..00000000 --- a/src/components/navigator/reducers/NavigatorReducer.tsx +++ /dev/null @@ -1,115 +0,0 @@ -import { NavigatorCategoryDataParser, NavigatorSearchResultSet, NavigatorTopLevelContext } from '@nitrots/nitro-renderer'; -import { Reducer } from 'react'; -import { RoomInfoData } from '../common/RoomInfoData'; - -export interface INavigatorState -{ - needsNavigatorUpdate: boolean; - topLevelContext: NavigatorTopLevelContext; - topLevelContexts: NavigatorTopLevelContext[]; - searchResult: NavigatorSearchResultSet; - categories: NavigatorCategoryDataParser[]; - roomInfoData: RoomInfoData; - homeRoomId: number; -} - -export interface INavigatorAction -{ - type: string; - payload: { - flag?: boolean; - topLevelContext?: NavigatorTopLevelContext; - topLevelContexts?: NavigatorTopLevelContext[]; - searchResult?: NavigatorSearchResultSet; - categories?: NavigatorCategoryDataParser[]; - roomInfoData?: RoomInfoData; - homeRoomId?: number; - } -} - -export class NavigatorActions -{ - public static SET_NEEDS_UPDATE: string = 'NA_SET_NEEDS_UPDATE'; - public static SET_TOP_LEVEL_CONTEXT: string = 'NA_SET_TOP_LEVEL_CONTEXT'; - public static SET_TOP_LEVEL_CONTEXTS: string = 'NA_SET_TOP_LEVEL_CONTEXTS'; - public static SET_SEARCH_RESULT: string = 'NA_SET_SEARCH_RESULT'; - public static SET_CATEGORIES: string = 'NA_SET_CATEGORIES'; - public static SET_ROOM_INFO_DATA: string = 'NA_SET_ROOM_INFO_DATA'; - public static SET_HOME_ROOM_ID: string = 'NA_SET_HOME_ROOM_ID'; -} - -export const initialNavigator: INavigatorState = { - needsNavigatorUpdate: true, - topLevelContext: null, - topLevelContexts: null, - searchResult: null, - categories: null, - roomInfoData: new RoomInfoData(), - homeRoomId: null -} - -export const NavigatorReducer: Reducer = (state, action) => -{ - switch(action.type) - { - case NavigatorActions.SET_NEEDS_UPDATE: - return { ...state, needsNavigatorUpdate: (action.payload.flag || false) }; - case NavigatorActions.SET_TOP_LEVEL_CONTEXT: { - let topLevelContext = (action.payload.topLevelContext || state.topLevelContext || null); - - let index = 0; - - if(topLevelContext) - { - const foundIndex = state.topLevelContexts.indexOf(topLevelContext); - - if(foundIndex > -1) index = foundIndex; - } - - topLevelContext = (state.topLevelContexts[index] || null); - - return { ...state, topLevelContext }; - } - case NavigatorActions.SET_TOP_LEVEL_CONTEXTS: { - const topLevelContexts = (action.payload.topLevelContexts || state.topLevelContexts || null); - const topLevelContext = topLevelContexts[0]; - - return { ...state, topLevelContext, topLevelContexts }; - } - case NavigatorActions.SET_SEARCH_RESULT: { - const searchResult = (action.payload.searchResult || state.searchResult || null); - const searchCode = searchResult.code; - - let topLevelContext = state.topLevelContext; - - if(searchCode !== topLevelContext.code) - { - for(const existingContext of state.topLevelContexts) - { - if(existingContext.code !== searchCode) continue; - - topLevelContext = existingContext; - } - } - - return { ...state, topLevelContext, searchResult }; - } - case NavigatorActions.SET_CATEGORIES: { - const categories = (action.payload.categories || state.categories || null); - - return { ...state, categories }; - } - case NavigatorActions.SET_ROOM_INFO_DATA: { - const roomInfoData = (action.payload.roomInfoData || state.roomInfoData || null); - - return { ...state, roomInfoData }; - } - case NavigatorActions.SET_HOME_ROOM_ID: { - const homeRoomId = (action.payload.homeRoomId || state.homeRoomId || null); - - return { ...state, homeRoomId }; - } - default: - return state; - } -} diff --git a/src/components/navigator/views/creator/NavigatorRoomCreatorView.tsx b/src/components/navigator/views/NavigatorRoomCreatorView.tsx similarity index 91% rename from src/components/navigator/views/creator/NavigatorRoomCreatorView.tsx rename to src/components/navigator/views/NavigatorRoomCreatorView.tsx index 4158d1da..1637b5a5 100644 --- a/src/components/navigator/views/creator/NavigatorRoomCreatorView.tsx +++ b/src/components/navigator/views/NavigatorRoomCreatorView.tsx @@ -1,11 +1,11 @@ /* eslint-disable no-template-curly-in-string */ import { HabboClubLevelEnum, RoomCreateComposer } from '@nitrots/nitro-renderer'; import { FC, useEffect, useState } from 'react'; -import { GetClubMemberLevel, GetConfiguration, LocalizeText, SendMessageComposer } from '../../../../api'; -import { Button, Column, Flex, Grid, LayoutCurrencyIcon, LayoutGridItem, Text } from '../../../../common'; -import { BatchUpdates } from '../../../../hooks'; -import { IRoomModel, RoomModels } from '../../common/RoomModels'; -import { useNavigatorContext } from '../../NavigatorContext'; +import { GetClubMemberLevel, GetConfiguration, LocalizeText, SendMessageComposer } from '../../../api'; +import { Button, Column, Flex, Grid, LayoutCurrencyIcon, LayoutGridItem, Text } from '../../../common'; +import { BatchUpdates } from '../../../hooks'; +import { IRoomModel, RoomModels } from '../common/RoomModels'; +import { useNavigatorContext } from '../NavigatorContext'; export const NavigatorRoomCreatorView: FC<{}> = props => { @@ -16,8 +16,7 @@ export const NavigatorRoomCreatorView: FC<{}> = props => const [ visitorsCount, setVisitorsCount ] = useState(null); const [ tradesSetting, setTradesSetting ] = useState(0); const [ selectedModelName, setSelectedModelName ] = useState(RoomModels[0].name); - const { navigatorState = null } = useNavigatorContext(); - const { categories = null } = navigatorState; + const { categories = null } = useNavigatorContext(); const getRoomModelImage = (name: string) => GetConfiguration('images.url') + `/navigator/models/model_${ name }.png`; @@ -64,7 +63,7 @@ export const NavigatorRoomCreatorView: FC<{}> = props => { LocalizeText('navigator.createroom.roomdescinfo') } -