refactor(navigator): remove deprecated useNavigator god-hook

P1 complete. All 13 consumers migrated to the wired-tools-style split:
- useNavigatorData / useNavigatorUiState / useNavigatorActions (filters)
- useNavigatorStore (internal useBetween closure with sendSearch + reloadCurrentSearch)
- navigatorUiStore (Zustand for 9 UI flags)
- useDoorState (extracted to src/hooks/rooms/widgets)

Spec: docs/superpowers/specs/2026-05-26-navigator-modernization-p1-design.md
Plan: docs/superpowers/plans/2026-05-26-navigator-modernization-p1.md

Next phases (separate specs/plans): P2 (TanStack Query for search),
P3 (reactive favourites via snapshot), P4 (visual rework + virtualization
+ persistence).
This commit is contained in:
simoleo89
2026-05-27 19:01:48 +02:00
parent 1d580e6d24
commit 1148c0a628
-492
View File
@@ -1,492 +0,0 @@
import { CanCreateRoomEventEvent, CantConnectMessageParser, CreateLinkEvent, DoorbellMessageEvent, FavouriteChangedEvent, FavouritesEvent, FlatAccessDeniedMessageEvent, FlatCreatedEvent, FollowFriendMessageComposer, GenericErrorEvent, GetGuestRoomMessageComposer, GetGuestRoomResultEvent, GetRoomSessionManager, GetSessionDataManager, GetUserEventCatsMessageComposer, GetUserFlatCatsMessageComposer, HabboWebTools, LegacyExternalInterface, NavigatorCategoryDataParser, NavigatorEventCategoryDataParser, NavigatorHomeRoomEvent, NavigatorMetadataEvent, NavigatorOpenRoomCreatorEvent, NavigatorSavedSearch, NavigatorSearchesEvent, NavigatorSearchEvent, NavigatorSearchResultSet, NavigatorTopLevelContext, NitroEventType, RoomDataParser, RoomDoorbellAcceptedEvent, RoomEnterErrorEvent, RoomEntryInfoMessageEvent, RoomForwardEvent, RoomScoreEvent, RoomSettingsUpdatedEvent, SecurityLevel, UserEventCatsEvent, UserFlatCatsEvent, UserInfoEvent, UserPermissionsEvent } from '@nitrots/nitro-renderer';
import { useState } from 'react';
import { useBetween } from 'use-between';
import { CreateRoomSession, DoorStateType, GetConfigurationValue, INavigatorData, LocalizeText, NotificationAlertType, SendMessageComposer, TryVisitRoom, VisitDesktop } from '../../api';
import { useMessageEvent, useNitroEvent } from '../events';
import { useNotification } from '../notification';
const useNavigatorState = () =>
{
const [ categories, setCategories ] = useState<NavigatorCategoryDataParser[]>(null);
const [ eventCategories, setEventCategories ] = useState<NavigatorEventCategoryDataParser[]>(null);
const [ favouriteRoomIds, setFavouriteRoomIds ] = useState<number[]>([]);
const [ topLevelContext, setTopLevelContext ] = useState<NavigatorTopLevelContext>(null);
const [ topLevelContexts, setTopLevelContexts ] = useState<NavigatorTopLevelContext[]>(null);
const [ doorData, setDoorData ] = useState<{ roomInfo: RoomDataParser, state: number }>({ roomInfo: null, state: DoorStateType.NONE });
const [ searchResult, setSearchResult ] = useState<NavigatorSearchResultSet>(null);
const [ navigatorSearches, setNavigatorSearches ] = useState<NavigatorSavedSearch[]>(null);
const [ navigatorData, setNavigatorData ] = useState<INavigatorData>({
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 { simpleAlert = null } = useNotification();
useMessageEvent<FavouritesEvent>(FavouritesEvent, event =>
{
const parser = event.getParser();
const favoriteIds = (parser.favoriteRoomIds || []).map((x: any) => Number(x));
setFavouriteRoomIds(favoriteIds);
});
useMessageEvent<FavouriteChangedEvent>(FavouriteChangedEvent, event =>
{
const parser = event.getParser();
const roomId = Number(parser.flatId);
const added = !!parser.added;
setFavouriteRoomIds(prev =>
{
const ids = (prev || []).map((x: any) => Number(x));
if(added) return ids.includes(roomId) ? ids : [ ...ids, roomId ];
return ids.filter(id => id !== roomId);
});
});
useMessageEvent<RoomSettingsUpdatedEvent>(RoomSettingsUpdatedEvent, event =>
{
const parser = event.getParser();
SendMessageComposer(new GetGuestRoomMessageComposer(parser.roomId, false, false));
});
useMessageEvent<CanCreateRoomEventEvent>(CanCreateRoomEventEvent, event =>
{
const parser = event.getParser();
if(parser.canCreate)
{
// show room event cvreate
return;
}
simpleAlert(LocalizeText(`navigator.cannotcreateevent.error.${ parser.errorCode }`), null, null, null, LocalizeText('navigator.cannotcreateevent.title'));
});
useMessageEvent<UserInfoEvent>(UserInfoEvent, event =>
{
SendMessageComposer(new GetUserFlatCatsMessageComposer());
SendMessageComposer(new GetUserEventCatsMessageComposer());
});
useMessageEvent<UserPermissionsEvent>(UserPermissionsEvent, event =>
{
const parser = event.getParser();
setNavigatorData(prevValue =>
{
const newValue = { ...prevValue };
newValue.eventMod = (parser.securityLevel >= SecurityLevel.MODERATOR);
newValue.roomPicker = (parser.securityLevel >= SecurityLevel.COMMUNITY);
return newValue;
});
});
useMessageEvent<RoomForwardEvent>(RoomForwardEvent, event =>
{
const parser = event.getParser();
TryVisitRoom(parser.roomId);
});
useMessageEvent<RoomEntryInfoMessageEvent>(RoomEntryInfoMessageEvent, event =>
{
const parser = event.getParser();
setNavigatorData(prevValue =>
{
const newValue = { ...prevValue };
newValue.enteredGuestRoom = null;
newValue.currentRoomOwner = parser.isOwner;
newValue.currentRoomId = parser.roomId;
return newValue;
});
// close room info
// close room settings
// close room filter
SendMessageComposer(new GetGuestRoomMessageComposer(parser.roomId, true, false));
if(LegacyExternalInterface.available) LegacyExternalInterface.call('legacyTrack', 'navigator', 'private', [ parser.roomId ]);
});
useMessageEvent<GetGuestRoomResultEvent>(GetGuestRoomResultEvent, event =>
{
const parser = event.getParser();
if(parser.roomEnter)
{
setDoorData({ roomInfo: null, state: DoorStateType.NONE });
setNavigatorData(prevValue =>
{
const newValue = { ...prevValue };
newValue.enteredGuestRoom = parser.data;
newValue.currentRoomIsStaffPick = parser.staffPick;
const isCreated = (newValue.createdFlatId === parser.data.roomId);
if(!isCreated && parser.data.displayRoomEntryAd)
{
if(GetConfigurationValue<boolean>('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)
{
if((parser.data.ownerName !== GetSessionDataManager().userName) && !parser.isGroupMember)
{
switch(parser.data.doorMode)
{
case RoomDataParser.DOORBELL_STATE:
setDoorData(prevValue =>
{
const newValue = { ...prevValue };
newValue.roomInfo = parser.data;
newValue.state = DoorStateType.START_DOORBELL;
return newValue;
});
return;
case RoomDataParser.PASSWORD_STATE:
setDoorData(prevValue =>
{
const newValue = { ...prevValue };
newValue.roomInfo = parser.data;
newValue.state = DoorStateType.START_PASSWORD;
return newValue;
});
return;
}
}
if((parser.data.doorMode === RoomDataParser.NOOB_STATE) && !GetSessionDataManager().isAmbassador && !GetSessionDataManager().isRealNoob && !GetSessionDataManager().isModerator) return;
CreateRoomSession(parser.data.roomId);
}
else
{
setNavigatorData(prevValue =>
{
const newValue = { ...prevValue };
newValue.enteredGuestRoom = parser.data;
newValue.currentRoomIsStaffPick = parser.staffPick;
return newValue;
});
}
});
useMessageEvent<RoomScoreEvent>(RoomScoreEvent, event =>
{
const parser = event.getParser();
setNavigatorData(prevValue =>
{
const newValue = { ...prevValue };
newValue.currentRoomRating = parser.totalLikes;
newValue.canRate = parser.canLike;
return newValue;
});
});
useMessageEvent<DoorbellMessageEvent>(DoorbellMessageEvent, event =>
{
const parser = event.getParser();
if(!parser.userName || (parser.userName.length === 0))
{
setDoorData(prevValue =>
{
const newValue = { ...prevValue };
newValue.state = DoorStateType.STATE_WAITING;
return newValue;
});
}
});
useMessageEvent<RoomDoorbellAcceptedEvent>(RoomDoorbellAcceptedEvent, event =>
{
const parser = event.getParser();
if(!parser.userName || (parser.userName.length === 0))
{
setDoorData(prevValue =>
{
const newValue = { ...prevValue };
newValue.state = DoorStateType.STATE_ACCEPTED;
return newValue;
});
}
});
useMessageEvent<FlatAccessDeniedMessageEvent>(FlatAccessDeniedMessageEvent, event =>
{
const parser = event.getParser();
if(!parser.userName || (parser.userName.length === 0))
{
setDoorData(prevValue =>
{
const newValue = { ...prevValue };
newValue.state = DoorStateType.STATE_NO_ANSWER;
return newValue;
});
}
});
useMessageEvent<GenericErrorEvent>(GenericErrorEvent, event =>
{
const parser = event.getParser();
switch(parser.errorCode)
{
case -100002:
setDoorData(prevValue =>
{
const newValue = { ...prevValue };
newValue.state = DoorStateType.STATE_WRONG_PASSWORD;
return newValue;
});
return;
case 4009:
simpleAlert(LocalizeText('navigator.alert.need.to.be.vip'), NotificationAlertType.DEFAULT, null, null, LocalizeText('generic.alert.title'));
return;
case 4010:
simpleAlert(LocalizeText('navigator.alert.invalid_room_name'), NotificationAlertType.DEFAULT, null, null, LocalizeText('generic.alert.title'));
return;
case 4011:
simpleAlert(LocalizeText('navigator.alert.cannot_perm_ban'), NotificationAlertType.DEFAULT, null, null, LocalizeText('generic.alert.title'));
return;
case 4013:
simpleAlert(LocalizeText('navigator.alert.room_in_maintenance'), NotificationAlertType.DEFAULT, null, null, LocalizeText('generic.alert.title'));
return;
}
});
useMessageEvent<NavigatorMetadataEvent>(NavigatorMetadataEvent, event =>
{
const parser = event.getParser();
setTopLevelContexts(parser.topLevelContexts);
setTopLevelContext(parser.topLevelContexts.length ? parser.topLevelContexts[0] : null);
});
useMessageEvent<NavigatorSearchEvent>(NavigatorSearchEvent, event =>
{
const parser = event.getParser();
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);
});
useMessageEvent<UserFlatCatsEvent>(UserFlatCatsEvent, event =>
{
const parser = event.getParser();
setCategories(parser.categories);
});
useMessageEvent<UserEventCatsEvent>(UserEventCatsEvent, event =>
{
const parser = event.getParser();
setEventCategories(parser.categories);
});
useMessageEvent<FlatCreatedEvent>(FlatCreatedEvent, event =>
{
const parser = event.getParser();
CreateRoomSession(parser.roomId);
});
// When reconnection starts, reset settingsReceived so the login sequence's
// NavigatorHomeRoomEvent is treated as a fresh login. Without this, the
// prevSettingsReceived check blocks home room navigation after reconnection,
// leaving the user stuck on hotel view.
useNitroEvent(NitroEventType.SOCKET_RECONNECTING, () =>
{
setNavigatorData(prevValue => ({ ...prevValue, settingsReceived: false }));
});
useMessageEvent<NavigatorHomeRoomEvent>(NavigatorHomeRoomEvent, event =>
{
const parser = event.getParser();
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;
}
// If a room session was already restored (from a network disconnect reload),
// skip the normal home room navigation to avoid overriding it.
if(GetRoomSessionManager().viewerSession) return;
let forwardType = -1;
let forwardId = -1;
if((GetConfigurationValue<string>('friend.id') !== undefined) && (parseInt(GetConfigurationValue<string>('friend.id')) > 0))
{
forwardType = 0;
SendMessageComposer(new FollowFriendMessageComposer(parseInt(GetConfigurationValue<string>('friend.id'))));
}
if((GetConfigurationValue<number>('forward.type') !== undefined) && (GetConfigurationValue<number>('forward.id') !== undefined))
{
forwardType = parseInt(GetConfigurationValue<string>('forward.type'));
forwardId = parseInt(GetConfigurationValue<string>('forward.id'));
}
if(forwardType === 2)
{
TryVisitRoom(forwardId);
}
else if((forwardType === -1) && (parser.roomIdToEnter > 0))
{
CreateLinkEvent('navigator/close');
if(parser.roomIdToEnter !== parser.homeRoomId)
{
CreateRoomSession(parser.roomIdToEnter);
}
else
{
CreateRoomSession(parser.homeRoomId);
}
}
});
useMessageEvent<RoomEnterErrorEvent>(RoomEnterErrorEvent, event =>
{
const parser = event.getParser();
switch(parser.reason)
{
case CantConnectMessageParser.REASON_FULL:
simpleAlert(LocalizeText('navigator.guestroomfull.text'), NotificationAlertType.DEFAULT, null, null, LocalizeText('navigator.guestroomfull.title'));
break;
case CantConnectMessageParser.REASON_QUEUE_ERROR:
simpleAlert(LocalizeText(`room.queue.error.${ parser.parameter }`), NotificationAlertType.DEFAULT, null, null, LocalizeText('room.queue.error.title'));
break;
case CantConnectMessageParser.REASON_BANNED:
simpleAlert(LocalizeText('navigator.banned.text'), NotificationAlertType.DEFAULT, null, null, LocalizeText('navigator.banned.title'));
break;
default:
simpleAlert(LocalizeText('room.queue.error.title'), NotificationAlertType.DEFAULT, null, null, LocalizeText('room.queue.error.title'));
break;
}
// During reconnection, don't navigate to desktop — the reconnection guard
// will handle retrying or cleaning up. Calling VisitDesktop here would
// remove the session from the map and send the user to hotel view.
if(GetRoomSessionManager().isReconnecting) return;
VisitDesktop();
});
useMessageEvent<NavigatorOpenRoomCreatorEvent>(NavigatorOpenRoomCreatorEvent, event => CreateLinkEvent('navigator/show'));
useMessageEvent<NavigatorSearchesEvent>(NavigatorSearchesEvent, event =>
{
const parser = event.getParser();
if(!parser) return;
setNavigatorSearches(parser.searches);
});
return { categories, doorData, setDoorData, topLevelContext, topLevelContexts, searchResult, navigatorData, favouriteRoomIds, navigatorSearches };
};
export const useNavigator = () => useBetween(useNavigatorState);