diff --git a/src/api/navigator/ToggleFavoriteRoom.ts b/src/api/navigator/ToggleFavoriteRoom.ts new file mode 100644 index 0000000..25295fd --- /dev/null +++ b/src/api/navigator/ToggleFavoriteRoom.ts @@ -0,0 +1,11 @@ +import { AddFavouriteRoomMessageComposer, DeleteFavouriteRoomMessageComposer } from '@nitrots/nitro-renderer'; +import { SendMessageComposer } from '..'; + +export const ToggleFavoriteRoom = (roomId: number, isFavorite: boolean): void => +{ + if(roomId <= 0) return; + + SendMessageComposer(isFavorite + ? new DeleteFavouriteRoomMessageComposer(roomId) + : new AddFavouriteRoomMessageComposer(roomId)); +}; diff --git a/src/api/navigator/index.ts b/src/api/navigator/index.ts index bceb33e..fae422b 100644 --- a/src/api/navigator/index.ts +++ b/src/api/navigator/index.ts @@ -9,4 +9,5 @@ export * from './NavigatorSearchResultViewDisplayMode'; export * from './RoomInfoData'; export * from './RoomSettingsUtils'; export * from './SearchFilterOptions'; +export * from './ToggleFavoriteRoom'; export * from './TryVisitRoom'; diff --git a/src/api/nitro/CreateLinkEvent.ts b/src/api/nitro/CreateLinkEvent.ts new file mode 100644 index 0000000..dd14c22 --- /dev/null +++ b/src/api/nitro/CreateLinkEvent.ts @@ -0,0 +1 @@ +export { CreateLinkEvent } from '@nitrots/nitro-renderer'; diff --git a/src/api/nitro/index.ts b/src/api/nitro/index.ts index 11b9d02..c2ecb72 100644 --- a/src/api/nitro/index.ts +++ b/src/api/nitro/index.ts @@ -1,3 +1,4 @@ +export * from './CreateLinkEvent'; export * from './GetConfigurationValue'; export * from './OpenUrl'; export * from './SendMessageComposer'; diff --git a/src/api/nitro/session/GetSessionDataManager.ts b/src/api/nitro/session/GetSessionDataManager.ts new file mode 100644 index 0000000..d9e19fc --- /dev/null +++ b/src/api/nitro/session/GetSessionDataManager.ts @@ -0,0 +1 @@ +export { GetSessionDataManager } from '@nitrots/nitro-renderer'; diff --git a/src/api/nitro/session/index.ts b/src/api/nitro/session/index.ts index 4c0491d..88ee45a 100644 --- a/src/api/nitro/session/index.ts +++ b/src/api/nitro/session/index.ts @@ -1,4 +1,5 @@ export * from './CanManipulateFurniture'; +export * from './GetSessionDataManager'; export * from './CreateRoomSession'; export * from './GetCanStandUp'; export * from './GetCanUseExpression'; diff --git a/src/assets/images/navigator/avatar_icon.png b/src/assets/images/navigator/avatar_icon.png new file mode 100644 index 0000000..2644636 Binary files /dev/null and b/src/assets/images/navigator/avatar_icon.png differ diff --git a/src/assets/images/navigator/badge_danger.png b/src/assets/images/navigator/badge_danger.png new file mode 100644 index 0000000..b52d55e Binary files /dev/null and b/src/assets/images/navigator/badge_danger.png differ diff --git a/src/assets/images/navigator/badge_empty.png b/src/assets/images/navigator/badge_empty.png new file mode 100644 index 0000000..7b105e6 Binary files /dev/null and b/src/assets/images/navigator/badge_empty.png differ diff --git a/src/assets/images/navigator/badge_success.png b/src/assets/images/navigator/badge_success.png new file mode 100644 index 0000000..d597896 Binary files /dev/null and b/src/assets/images/navigator/badge_success.png differ diff --git a/src/assets/images/navigator/badge_warning.png b/src/assets/images/navigator/badge_warning.png new file mode 100644 index 0000000..e9335d6 Binary files /dev/null and b/src/assets/images/navigator/badge_warning.png differ diff --git a/src/assets/images/navigator/create_room.png b/src/assets/images/navigator/create_room.png new file mode 100644 index 0000000..d6a476a Binary files /dev/null and b/src/assets/images/navigator/create_room.png differ diff --git a/src/assets/images/navigator/groups.png b/src/assets/images/navigator/groups.png new file mode 100644 index 0000000..922056b Binary files /dev/null and b/src/assets/images/navigator/groups.png differ diff --git a/src/assets/images/navigator/icon-room-promote.png b/src/assets/images/navigator/icon-room-promote.png new file mode 100644 index 0000000..ee231ed Binary files /dev/null and b/src/assets/images/navigator/icon-room-promote.png differ diff --git a/src/assets/images/navigator/info_bg.png b/src/assets/images/navigator/info_bg.png new file mode 100644 index 0000000..60dc3aa Binary files /dev/null and b/src/assets/images/navigator/info_bg.png differ diff --git a/src/assets/images/navigator/info_pointer.png b/src/assets/images/navigator/info_pointer.png new file mode 100644 index 0000000..42fa3d4 Binary files /dev/null and b/src/assets/images/navigator/info_pointer.png differ diff --git a/src/assets/images/navigator/inline_view.png b/src/assets/images/navigator/inline_view.png new file mode 100644 index 0000000..acaf8eb Binary files /dev/null and b/src/assets/images/navigator/inline_view.png differ diff --git a/src/assets/images/navigator/minus.png b/src/assets/images/navigator/minus.png new file mode 100644 index 0000000..bc5b95f Binary files /dev/null and b/src/assets/images/navigator/minus.png differ diff --git a/src/assets/images/navigator/pen.png b/src/assets/images/navigator/pen.png new file mode 100644 index 0000000..3ca1c35 Binary files /dev/null and b/src/assets/images/navigator/pen.png differ diff --git a/src/assets/images/navigator/plus.png b/src/assets/images/navigator/plus.png new file mode 100644 index 0000000..e0b1c7e Binary files /dev/null and b/src/assets/images/navigator/plus.png differ diff --git a/src/assets/images/navigator/profile.png b/src/assets/images/navigator/profile.png new file mode 100644 index 0000000..83932da Binary files /dev/null and b/src/assets/images/navigator/profile.png differ diff --git a/src/assets/images/navigator/promote_room.png b/src/assets/images/navigator/promote_room.png new file mode 100644 index 0000000..3f912af Binary files /dev/null and b/src/assets/images/navigator/promote_room.png differ diff --git a/src/assets/images/navigator/random_room.png b/src/assets/images/navigator/random_room.png new file mode 100644 index 0000000..549a9b5 Binary files /dev/null and b/src/assets/images/navigator/random_room.png differ diff --git a/src/assets/images/navigator/refresh.png b/src/assets/images/navigator/refresh.png new file mode 100644 index 0000000..2899d28 Binary files /dev/null and b/src/assets/images/navigator/refresh.png differ diff --git a/src/assets/images/navigator/room_thumbnail.png b/src/assets/images/navigator/room_thumbnail.png new file mode 100644 index 0000000..b25d01d Binary files /dev/null and b/src/assets/images/navigator/room_thumbnail.png differ diff --git a/src/assets/images/navigator/saves-search/delete_search.png b/src/assets/images/navigator/saves-search/delete_search.png new file mode 100644 index 0000000..4c35559 Binary files /dev/null and b/src/assets/images/navigator/saves-search/delete_search.png differ diff --git a/src/assets/images/navigator/saves-search/delete_search_click.png b/src/assets/images/navigator/saves-search/delete_search_click.png new file mode 100644 index 0000000..657ceb3 Binary files /dev/null and b/src/assets/images/navigator/saves-search/delete_search_click.png differ diff --git a/src/assets/images/navigator/saves-search/delete_search_hover.png b/src/assets/images/navigator/saves-search/delete_search_hover.png new file mode 100644 index 0000000..ad6ccf9 Binary files /dev/null and b/src/assets/images/navigator/saves-search/delete_search_hover.png differ diff --git a/src/assets/images/navigator/saves-search/search_save.png b/src/assets/images/navigator/saves-search/search_save.png new file mode 100644 index 0000000..975fb78 Binary files /dev/null and b/src/assets/images/navigator/saves-search/search_save.png differ diff --git a/src/assets/images/navigator/similar_results.png b/src/assets/images/navigator/similar_results.png new file mode 100644 index 0000000..b025ae8 Binary files /dev/null and b/src/assets/images/navigator/similar_results.png differ diff --git a/src/assets/images/navigator/similar_results_active.png b/src/assets/images/navigator/similar_results_active.png new file mode 100644 index 0000000..017a56c Binary files /dev/null and b/src/assets/images/navigator/similar_results_active.png differ diff --git a/src/assets/images/navigator/thumbnail_bg.png b/src/assets/images/navigator/thumbnail_bg.png new file mode 100644 index 0000000..4e60c55 Binary files /dev/null and b/src/assets/images/navigator/thumbnail_bg.png differ diff --git a/src/assets/images/navigator/thumbnail_view.png b/src/assets/images/navigator/thumbnail_view.png new file mode 100644 index 0000000..b4a6116 Binary files /dev/null and b/src/assets/images/navigator/thumbnail_view.png differ diff --git a/src/assets/images/navigator/white_bg.png b/src/assets/images/navigator/white_bg.png new file mode 100644 index 0000000..fceab0e Binary files /dev/null and b/src/assets/images/navigator/white_bg.png differ diff --git a/src/assets/webfonts/Volter-b.ttf b/src/assets/webfonts/Volter-b.ttf new file mode 100644 index 0000000..219584b Binary files /dev/null and b/src/assets/webfonts/Volter-b.ttf differ diff --git a/src/assets/webfonts/Volter.ttf b/src/assets/webfonts/Volter.ttf new file mode 100644 index 0000000..1750d96 Binary files /dev/null and b/src/assets/webfonts/Volter.ttf differ diff --git a/src/common/Text.tsx b/src/common/Text.tsx index da5235d..ffc0a85 100644 --- a/src/common/Text.tsx +++ b/src/common/Text.tsx @@ -41,7 +41,7 @@ export const Text: FC = props => { } = props; const getClassNames = useMemo(() => { - const newClassNames: string[] = ['inline']; + const newClassNames: string[] = [truncate ? 'block' : 'inline']; if (variant) { if (variant === 'primary') newClassNames.push('text-[#1e7295]'); @@ -54,7 +54,7 @@ export const Text: FC = props => { if (variant == 'danger') newClassNames.push('text-[#a81a12]'); if (variant == 'warning') newClassNames.push('text-[#ffc107]'); } - + if (bold) newClassNames.push('font-bold'); if (fontWeight) newClassNames.push('font-' + fontWeight); if (fontSize) newClassNames.push('fs-' + fontSize); @@ -62,7 +62,7 @@ export const Text: FC = props => { if (align) newClassNames.push('text-' + align); if (underline) newClassNames.push('underline'); if (italics) newClassNames.push('italic'); - if (truncate) newClassNames.push('text-truncate'); + if (truncate) newClassNames.push('truncate', 'min-w-0'); if (center) newClassNames.push('text-center'); if (textEnd) newClassNames.push('text-end'); if (small) newClassNames.push('text-sm'); @@ -71,7 +71,7 @@ export const Text: FC = props => { if (textBreak) newClassNames.push('text-break'); return newClassNames; - }, [variant, fontWeight, fontSize, fontSizeCustom, align, bold, underline, italics, truncate, center, textEnd, small, wrap, noWrap, textBreak]); + }, [ variant, fontWeight, fontSize, fontSizeCustom, align, bold, underline, italics, truncate, center, textEnd, small, wrap, noWrap, textBreak ]); const style = fontSizeCustom ? { '--font-size': `${fontSizeCustom}px` } as React.CSSProperties : undefined; diff --git a/src/common/layout/LayoutSearchSavesView.tsx b/src/common/layout/LayoutSearchSavesView.tsx new file mode 100644 index 0000000..3c6ca88 --- /dev/null +++ b/src/common/layout/LayoutSearchSavesView.tsx @@ -0,0 +1,23 @@ +import { FC } from 'react'; +import { FaBolt } from 'react-icons/fa'; + +export interface LayoutSearchSavesViewProps +{ + title: string; + onClick?: () => void; +} + +export const LayoutSearchSavesView: FC = props => +{ + const { title = null, onClick = null } = props; + + return ( +
+ +
+ ); +}; diff --git a/src/common/layout/index.ts b/src/common/layout/index.ts index cbb0568..9723cc0 100644 --- a/src/common/layout/index.ts +++ b/src/common/layout/index.ts @@ -19,6 +19,7 @@ export * from './LayoutRarityLevelView'; export * from './LayoutRoomObjectImageView'; export * from './LayoutRoomPreviewerView'; export * from './LayoutRoomThumbnailView'; +export * from './LayoutSearchSavesView'; export * from './LayoutTrophyView'; export * from './UserProfileIconView'; export * from './limited-edition'; diff --git a/src/components/navigator/NavigatorView.scss b/src/components/navigator/NavigatorView.scss new file mode 100644 index 0000000..bdb279e --- /dev/null +++ b/src/components/navigator/NavigatorView.scss @@ -0,0 +1,8 @@ +.button-search-saves { + padding: 4px; + height: 17px; + margin-top: -1px; + font-size: 10px; + border-radius: 4px; + background-color: #FAA700; +} diff --git a/src/components/navigator/NavigatorView.tsx b/src/components/navigator/NavigatorView.tsx index 813c390..820220a 100644 --- a/src/components/navigator/NavigatorView.tsx +++ b/src/components/navigator/NavigatorView.tsx @@ -1,8 +1,13 @@ import { NitroCard } from '@layout/NitroCard'; -import { AddLinkEventTracker, ConvertGlobalRoomIdMessageComposer, HabboWebTools, ILinkEventTracker, LegacyExternalInterface, NavigatorInitComposer, NavigatorSearchComposer, RemoveLinkEventTracker, RoomSessionEvent } from '@nitrots/nitro-renderer'; +import { AddLinkEventTracker, ConvertGlobalRoomIdMessageComposer, FindNewFriendsMessageComposer, HabboWebTools, ILinkEventTracker, LegacyExternalInterface, NavigatorInitComposer, NavigatorSearchComposer, RemoveLinkEventTracker, RoomSessionEvent } from '@nitrots/nitro-renderer'; import { FC, useCallback, useEffect, useRef, useState } from 'react'; import { FaPlus } from 'react-icons/fa'; -import { LocalizeText, SendMessageComposer, TryVisitRoom } from '../../api'; +import savesSearchIcon from '../../assets/images/navigator/saves-search/search_save.png'; +import createRoomImg from '../../assets/images/navigator/create_room.png'; +import randomRoomImg from '../../assets/images/navigator/random_room.png'; +import promoteRoomImg from '../../assets/images/navigator/promote_room.png'; +import { CreateLinkEvent, LocalizeText, SendMessageComposer, TryVisitRoom } from '../../api'; +import { Flex, Text } from '../../common'; import { useNavigator, useNitroEvent } from '../../hooks'; import { NavigatorDoorStateView } from './views/NavigatorDoorStateView'; import { NavigatorRoomCreatorView } from './views/NavigatorRoomCreatorView'; @@ -10,6 +15,7 @@ import { NavigatorRoomInfoView } from './views/NavigatorRoomInfoView'; import { NavigatorRoomLinkView } from './views/NavigatorRoomLinkView'; import { NavigatorRoomSettingsView } from './views/room-settings/NavigatorRoomSettingsView'; import { NavigatorSearchResultView } from './views/search/NavigatorSearchResultView'; +import { NavigatorSearchSavesResultView } from './views/search/NavigatorSearchSavesResultView'; import { NavigatorSearchView } from './views/search/NavigatorSearchView'; export const NavigatorView: FC<{}> = props => @@ -19,10 +25,11 @@ export const NavigatorView: FC<{}> = props => const [ isCreatorOpen, setCreatorOpen ] = useState(false); const [ isRoomInfoOpen, setRoomInfoOpen ] = useState(false); const [ isRoomLinkOpen, setRoomLinkOpen ] = useState(false); + const [ isOpenSavesSearches, setIsOpenSavesSearches ] = useState(false); const [ isLoading, setIsLoading ] = useState(false); const [ needsInit, setNeedsInit ] = useState(true); const [ needsSearch, setNeedsSearch ] = useState(false); - const { searchResult = null, topLevelContext = null, topLevelContexts = null, navigatorData = null } = useNavigator(); + const { searchResult = null, topLevelContext = null, topLevelContexts = null, navigatorData = null, navigatorSearches = null } = useNavigator(); const pendingSearch = useRef<{ value: string, code: string }>(null); const elementRef = useRef(); @@ -197,12 +204,18 @@ export const NavigatorView: FC<{}> = props => <> { isVisible && setIsVisible(false) } /> + setIsOpenSavesSearches(prev => !prev) }> + + { topLevelContexts && (topLevelContexts.length > 0) && topLevelContexts.map((context, index) => { return ( @@ -222,12 +235,58 @@ export const NavigatorView: FC<{}> = props => { !isCreatorOpen && - <> - -
- { (searchResult && searchResult.results.map((result, index) => )) } +
+ { isOpenSavesSearches && +
+ +
} +
+ +
+ { (searchResult && searchResult.results.map((result, index) => )) } +
+ + setCreatorOpen(true) } + > + + { LocalizeText('navigator.createroom.create') } + + + { (searchResult?.code !== 'myworld_view' && searchResult?.code !== 'roomads_view') && + SendMessageComposer(new FindNewFriendsMessageComposer()) } + > + + { LocalizeText('navigator.random.room') } + + } + { (searchResult?.code === 'myworld_view' || searchResult?.code === 'roomads_view') && + CreateLinkEvent('catalog/open/room_event') } + > + + { LocalizeText('navigator.promote.room') } + + } +
- } +
} { isCreatorOpen && } } diff --git a/src/components/navigator/views/NavigatorRoomInfoView.tsx b/src/components/navigator/views/NavigatorRoomInfoView.tsx index 35101a9..8da9d6c 100644 --- a/src/components/navigator/views/NavigatorRoomInfoView.tsx +++ b/src/components/navigator/views/NavigatorRoomInfoView.tsx @@ -1,7 +1,7 @@ -import { CreateLinkEvent, GetCustomRoomFilterMessageComposer, GetSessionDataManager, NavigatorSearchComposer, RemoveOwnRoomRightsRoomMessageComposer, RoomControllerLevel, RoomMuteComposer, RoomSettingsComposer, SecurityLevel, ToggleStaffPickMessageComposer, UpdateHomeRoomMessageComposer } from '@nitrots/nitro-renderer'; -import { FC, useEffect, useState } from 'react'; +import { CreateLinkEvent, GetCustomRoomFilterMessageComposer, GetGuestRoomMessageComposer, GetSessionDataManager, NavigatorSearchComposer, RemoveOwnRoomRightsRoomMessageComposer, RoomControllerLevel, RoomMuteComposer, RoomSettingsComposer, SecurityLevel, ToggleStaffPickMessageComposer, UpdateHomeRoomMessageComposer } from '@nitrots/nitro-renderer'; +import { FC, useEffect, useMemo, useState } from 'react'; import { FaLink, FaSignOutAlt } from 'react-icons/fa'; -import { DispatchUiEvent, GetGroupInformation, LocalizeText, ReportType, SendMessageComposer } from '../../../api'; +import { DispatchUiEvent, GetGroupInformation, LocalizeText, ReportType, SendMessageComposer, ToggleFavoriteRoom } from '../../../api'; import { Button, Column, Flex, LayoutBadgeImageView, LayoutRoomThumbnailView, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text, UserProfileIconView } from '../../../common'; import { RoomWidgetThumbnailEvent } from '../../../events'; import { useHelp, useNavigator, useRoom } from '../../../hooks'; @@ -11,16 +11,45 @@ export interface NavigatorRoomInfoViewProps { onCloseClick: () => void; } -export const NavigatorRoomInfoView: FC = props => { +export const NavigatorRoomInfoView: FC = props => +{ const { onCloseClick = null } = props; const [ isRoomPicked, setIsRoomPicked ] = useState(false); const [ isRoomMuted, setIsRoomMuted ] = useState(false); const { report = null } = useHelp(); - const { navigatorData = null } = useNavigator(); + const { navigatorData = null, favouriteRoomIds = [] } = useNavigator(); const { roomSession = null } = useRoom(); - const hasPermission = (permission: string) => { - switch(permission) { + const enteredRoomId = navigatorData?.enteredGuestRoom?.roomId ?? 0; + + useEffect(() => + { + if(!enteredRoomId) return; + SendMessageComposer(new GetGuestRoomMessageComposer(enteredRoomId, false, false)); + }, [ enteredRoomId ]); + + const isRoomInFavouritesList = useMemo(() => + { + if(!enteredRoomId) return false; + + return favouriteRoomIds.some((id: any) => + { + if(id && typeof id === 'object') + { + if('roomId' in id) return Number(id.roomId) === enteredRoomId; + if('id' in id) return Number(id.id) === enteredRoomId; + } + + return String(id) === String(enteredRoomId); + }); + }, [ favouriteRoomIds, enteredRoomId ]); + + const hasPermission = (permission: string) => + { + if(!navigatorData?.enteredGuestRoom) return false; + + switch(permission) + { case 'settings': return (GetSessionDataManager().userId === navigatorData.enteredGuestRoom.ownerId || GetSessionDataManager().isModerator); case 'staff_pick': @@ -33,17 +62,21 @@ export const NavigatorRoomInfoView: FC = props => { } }; - const processAction = (action: string, value?: string) => { - if(!navigatorData || !navigatorData.enteredGuestRoom) return; + const processAction = (action: string, value?: string) => + { + if(!navigatorData?.enteredGuestRoom) return; - switch(action) { + const roomId = navigatorData.enteredGuestRoom.roomId; + + switch(action) + { case 'set_home_room': + { let newRoomId = -1; - if(navigatorData.homeRoomId !== navigatorData.enteredGuestRoom.roomId) { - newRoomId = navigatorData.enteredGuestRoom.roomId; - } + if(navigatorData.homeRoomId !== roomId) newRoomId = roomId; if(newRoomId > 0) SendMessageComposer(new UpdateHomeRoomMessageComposer(newRoomId)); return; + } case 'navigator_search_tag': CreateLinkEvent(`navigator/search/${ value }`); SendMessageComposer(new NavigatorSearchComposer('hotel_view', `tag:${ value }`)); @@ -58,27 +91,33 @@ export const NavigatorRoomInfoView: FC = props => { CreateLinkEvent('navigator/toggle-room-link'); return; case 'open_room_settings': - SendMessageComposer(new RoomSettingsComposer(navigatorData.enteredGuestRoom.roomId)); + SendMessageComposer(new RoomSettingsComposer(roomId)); return; case 'toggle_pick': - setIsRoomPicked(value => !value); - SendMessageComposer(new ToggleStaffPickMessageComposer(navigatorData.enteredGuestRoom.roomId)); + setIsRoomPicked(prev => !prev); + SendMessageComposer(new ToggleStaffPickMessageComposer(roomId)); + SendMessageComposer(new GetGuestRoomMessageComposer(roomId, false, false)); return; case 'toggle_mute': - setIsRoomMuted(value => !value); + setIsRoomMuted(prev => !prev); SendMessageComposer(new RoomMuteComposer()); + SendMessageComposer(new GetGuestRoomMessageComposer(roomId, false, false)); return; case 'room_filter': - SendMessageComposer(new GetCustomRoomFilterMessageComposer(navigatorData.enteredGuestRoom.roomId)); + SendMessageComposer(new GetCustomRoomFilterMessageComposer(roomId)); return; case 'open_floorplan_editor': CreateLinkEvent('floor-editor/toggle'); return; case 'report_room': - report(ReportType.ROOM, { roomId: navigatorData.enteredGuestRoom.roomId, roomName: navigatorData.enteredGuestRoom.roomName }); + report(ReportType.ROOM, { roomId, roomName: navigatorData.enteredGuestRoom.roomName }); + return; + case 'room_favourite': + ToggleFavoriteRoom(roomId, isRoomInFavouritesList); + SendMessageComposer(new GetGuestRoomMessageComposer(roomId, false, false)); return; case 'remove_rights': - SendMessageComposer(new RemoveOwnRoomRightsRoomMessageComposer(navigatorData.enteredGuestRoom.roomId)); + SendMessageComposer(new RemoveOwnRoomRightsRoomMessageComposer(roomId)); return; case 'close': onCloseClick(); @@ -86,96 +125,105 @@ export const NavigatorRoomInfoView: FC = props => { } }; - useEffect(() => { + useEffect(() => + { if(!navigatorData) return; - setIsRoomPicked(navigatorData.currentRoomIsStaffPick); if(navigatorData.enteredGuestRoom) setIsRoomMuted(navigatorData.enteredGuestRoom.allInRoomMuted); }, [ navigatorData ]); - if(!navigatorData.enteredGuestRoom) return null; + if(!navigatorData?.enteredGuestRoom) return null; return ( processAction('close') } /> - { navigatorData.enteredGuestRoom && - <> - - - { hasPermission('settings') && processAction('open_room_thumbnail_camera') } /> } - - + + + { hasPermission('settings') && processAction('open_room_thumbnail_camera') } /> } + + +
+
- -
- { navigatorData.enteredGuestRoom.roomName } -
- { navigatorData.enteredGuestRoom.showOwner && -
- { LocalizeText('navigator.roomownercaption') } -
- - { navigatorData.enteredGuestRoom.ownerName } -
-
} -
- { LocalizeText('navigator.roomrating') } - { navigatorData.currentRoomRating } -
- { (navigatorData.enteredGuestRoom.tags.length > 0) && -
- { navigatorData.enteredGuestRoom.tags.map(tag => - processAction('navigator_search_tag', tag) }>#{ tag } - ) } -
} -
- - processAction('set_home_room') } /> - { hasPermission('settings') && - processAction('open_room_settings') } /> } - processAction('toggle_room_link') } /> - { hasPermission('guest') && - processAction('remove_rights') } /> } - + { navigatorData.enteredGuestRoom.roomName }
- { navigatorData.enteredGuestRoom.description } - { (navigatorData.enteredGuestRoom.habboGroupId > 0) && - processAction('open_group_info') }> - - - { LocalizeText('navigator.guildbase', [ 'groupName' ], [ navigatorData.enteredGuestRoom.groupName ]) } - - } + { navigatorData.enteredGuestRoom.showOwner && +
+ { LocalizeText('navigator.roomownercaption') } +
+ + { navigatorData.enteredGuestRoom.ownerName } +
+
} +
+ { LocalizeText('navigator.roomrating') } + { navigatorData.currentRoomRating } +
+ { (navigatorData.enteredGuestRoom.tags.length > 0) && +
+ { navigatorData.enteredGuestRoom.tags.map(tag => ( + processAction('navigator_search_tag', tag) }> + #{ tag } + + )) } +
} +
+ + processAction('set_home_room') } + /> + { GetSessionDataManager().userId !== navigatorData.enteredGuestRoom.ownerId && + processAction('room_favourite') } + /> } + { hasPermission('settings') && + processAction('open_room_settings') } /> } + processAction('toggle_room_link') } /> + { hasPermission('guest') && + processAction('remove_rights') } /> } - -
- { hasPermission('staff_pick') && - } - - { hasPermission('settings') && - <> - - - - } - { hasPermission('floor') && !hasPermission('settings') && - }
- } + { navigatorData.enteredGuestRoom.description } + { (navigatorData.enteredGuestRoom.habboGroupId > 0) && + processAction('open_group_info') }> + + + { LocalizeText('navigator.guildbase', [ 'groupName' ], [ navigatorData.enteredGuestRoom.groupName ]) } + + } + + +
+ { hasPermission('staff_pick') && + } + + { hasPermission('settings') && + <> + + + + } + { hasPermission('floor') && !hasPermission('settings') && + } +
); -}; \ No newline at end of file +}; diff --git a/src/components/navigator/views/search/NavigatorSearchResultItemInfoView.tsx b/src/components/navigator/views/search/NavigatorSearchResultItemInfoView.tsx index 5c52c8b..dc548ce 100644 --- a/src/components/navigator/views/search/NavigatorSearchResultItemInfoView.tsx +++ b/src/components/navigator/views/search/NavigatorSearchResultItemInfoView.tsx @@ -1,106 +1,196 @@ -import { RoomDataParser } from '@nitrots/nitro-renderer'; -import { FC, useRef, useState } from 'react'; +import { RoomDataParser, RoomSettingsComposer, UpdateHomeRoomMessageComposer } from '@nitrots/nitro-renderer'; +import React, { FC, useRef, useState } from 'react'; import { FaUser } from 'react-icons/fa'; - import { ArrowContainer, Popover } from 'react-tiny-popover'; -import { LocalizeText } from '../../../../api'; -import { Flex, LayoutBadgeImageView, LayoutRoomThumbnailView, NitroCardContentView, Text, UserProfileIconView } from '../../../../common'; +import { GetGroupInformation, GetSessionDataManager, GetUserProfile, LocalizeText, ReportType, SendMessageComposer, ToggleFavoriteRoom } from '../../../../api'; +import { Column, Flex, LayoutBadgeImageView, LayoutRoomThumbnailView, NitroCardContentView, Text, UserProfileIconView } from '../../../../common'; +import { useHelp, useNavigator } from '../../../../hooks'; +import { classNames } from '../../../../layout'; -export const NavigatorSearchResultItemInfoView: FC<{ - roomData: RoomDataParser; -}> = props => +interface NavigatorSearchResultItemInfoViewProps { - const { roomData = null } = props; - const [ isVisible, setIsVisible ] = useState(false); - const elementRef = useRef(); + roomData: RoomDataParser; + isVisible?: boolean; + onToggle?: (e: React.MouseEvent) => void; + setIsPopoverActive?: React.Dispatch>; +} + +export const NavigatorSearchResultItemInfoView: FC = props => +{ + const { roomData = null, isVisible = undefined, onToggle, setIsPopoverActive } = props; + const elementRef = useRef(null); + const [ internalVisible, setInternalVisible ] = useState(false); + const { navigatorData = null, favouriteRoomIds = [] } = useNavigator(); + const { report = null } = useHelp(); + + const isControlled = isVisible !== undefined; + const popoverOpen = isControlled ? isVisible : internalVisible; const getUserCounterColor = () => { const num: number = (100 * (roomData.userCount / roomData.maxUserCount)); - let bg = 'bg-primary'; + if(num >= 92) return 'bg-danger'; + if(num >= 50) return 'bg-warning'; + if(num > 0) return 'bg-success'; - if(num >= 92) - { - bg = 'bg-danger'; - } - else if(num >= 50) - { - bg = 'bg-warning'; - } - else if(num > 0) - { - bg = 'bg-success'; - } - - return bg; + return 'bg-primary'; }; - function dispatch(arg0: string): void + const processAction = (action: string) => { - throw new Error('Function not implemented.'); - } + if(!navigatorData || !roomData) return; + switch(action) + { + case 'set_home_room': + { + let newRoomId = -1; + if(navigatorData.homeRoomId !== roomData.roomId) newRoomId = roomData.roomId; + if(newRoomId > 0) SendMessageComposer(new UpdateHomeRoomMessageComposer(newRoomId)); + return; + } + case 'open_room_settings': + SendMessageComposer(new RoomSettingsComposer(roomData.roomId)); + return; + case 'report_room': + report(ReportType.ROOM, { roomId: roomData.roomId, roomName: roomData.roomName }); + return; + case 'room_favourite': + ToggleFavoriteRoom(roomData.roomId, favouriteRoomIds.includes(roomData.roomId)); + return; + } + }; + + const handleOwnerClick = (e: React.MouseEvent) => + { + e.stopPropagation(); + GetUserProfile(roomData.ownerId); + }; + + const handleGroupClick = (e: React.MouseEvent) => + { + e.stopPropagation(); + GetGroupInformation(roomData.habboGroupId); + }; + + const getTradeModeText = (): string => + { + if(roomData.tradeMode === 1) return LocalizeText('trading.mode.free'); + return LocalizeText('trading.mode.not.allowed'); + }; + + const handleIconClick = (e: React.MouseEvent) => + { + e.preventDefault(); + e.stopPropagation(); + if(onToggle) onToggle(e); + }; return ( - <> - - - ( - - - - - { roomData.habboGroupId > 0 && ( - ) } - { roomData.doorMode !== RoomDataParser.OPEN_STATE && ( - ) } - -
- - { roomData.roomName } - -
- - { LocalizeText('navigator.roomownercaption') } - -
- - { roomData.ownerName } -
-
- - { roomData.description } - - - - { roomData.userCount } - -
+ ( + + e.stopPropagation() }> + + + { roomData.habboGroupId > 0 && ( + ) } + { roomData.doorMode !== RoomDataParser.OPEN_STATE && ( + ) } + + + + { roomData.roomName.length > 35 ? roomData.roomName.substring(0, 35) + '…' : roomData.roomName } + + { roomData.description } + + + + + { roomData.ownerName && roomData.ownerName.length > 0 && + + + { roomData.ownerName } + } + { roomData.habboGroupId > 0 && + + + { roomData.groupName } + } - - - ) } - isOpen={ isVisible } - padding={ 10 } - positions={ [ 'right' ] } - > - -
setIsVisible(false) } onMouseOver={ event => setIsVisible(true) } /> - - - - + + + + { LocalizeText('navigator.roompopup.property.trading') } + { getTradeModeText() } + + + { LocalizeText('navigator.roompopup.property.max_users') } + { roomData.maxUserCount } + + + + + { roomData.userCount } + + + + + processAction('room_favourite') }> + + { LocalizeText('navigator.room.popup.room.info.favorite') } + + processAction('set_home_room') }> + + { LocalizeText('navigator.room.popup.room.info.home') } + + { GetSessionDataManager().userId === roomData.ownerId && + processAction('open_room_settings') }> + + { LocalizeText('navigator.room.popup.info.room.settings') } + } + { GetSessionDataManager().userId !== roomData.ownerId && + processAction('report_room') }> + + { LocalizeText('navigator.room.popup.report.room') } + } + + + { roomData.tags && roomData.tags.length > 0 && + + { roomData.tags.map((tag, i) => ( + #{ tag } + )) } + } + + + + ) } + isOpen={ popoverOpen } + onClickOutside={ () => + { + if(!isControlled) setInternalVisible(false); + if(setIsPopoverActive) setIsPopoverActive(false); + } } + padding={ 10 } + positions={ [ 'right', 'left', 'top', 'bottom' ] } + > +
{ if(!isControlled) setInternalVisible(true); } } + onMouseLeave={ () => { if(!isControlled) setInternalVisible(false); } } + /> + ); }; diff --git a/src/components/navigator/views/search/NavigatorSearchResultItemView.tsx b/src/components/navigator/views/search/NavigatorSearchResultItemView.tsx index 2213f45..2f746e9 100644 --- a/src/components/navigator/views/search/NavigatorSearchResultItemView.tsx +++ b/src/components/navigator/views/search/NavigatorSearchResultItemView.tsx @@ -1,5 +1,5 @@ import { GetSessionDataManager, RoomDataParser } from '@nitrots/nitro-renderer'; -import { FC, MouseEvent } from 'react'; +import React, { FC, MouseEvent, useEffect } from 'react'; import { FaUser } from 'react-icons/fa'; import { CreateRoomSession, DoorStateType, TryVisitRoom } from '../../../../api'; import { Column, Flex, LayoutBadgeImageView, LayoutGridItemProps, LayoutRoomThumbnailView, Text } from '../../../../common'; @@ -8,35 +8,84 @@ import { NavigatorSearchResultItemInfoView } from './NavigatorSearchResultItemIn export interface NavigatorSearchResultItemViewProps extends LayoutGridItemProps { - roomData: RoomDataParser - thumbnail?: boolean + roomData: RoomDataParser; + thumbnail?: boolean; + selectedRoomId?: number | null; + setSelectedRoomId?: React.Dispatch>; + isPopoverActive?: boolean; + setIsPopoverActive?: React.Dispatch>; } export const NavigatorSearchResultItemView: FC = props => { - const { roomData = null, children = null, thumbnail = false, ...rest } = props; + const { roomData = null, children = null, thumbnail = false, selectedRoomId, setSelectedRoomId, isPopoverActive, setIsPopoverActive, ...rest } = props; const { setDoorData = null } = useNavigator(); + const handleMouseEnter = () => + { + if(isPopoverActive && setSelectedRoomId) setSelectedRoomId(roomData.roomId); + }; + + const handleMouseLeave = () => + { + if(setSelectedRoomId && setIsPopoverActive) + { + setSelectedRoomId(null); + setIsPopoverActive(false); + } + }; + + const handleInfoClick = (e: React.MouseEvent) => + { + e.preventDefault(); + e.stopPropagation(); + + if(setIsPopoverActive && setSelectedRoomId) + { + if(!isPopoverActive) + { + setSelectedRoomId(roomData.roomId); + setIsPopoverActive(true); + } + else if(selectedRoomId === roomData.roomId) + { + setSelectedRoomId(null); + setIsPopoverActive(false); + } + else + { + setSelectedRoomId(roomData.roomId); + } + } + }; + + useEffect(() => + { + const handleClickOutside = (event: Event) => + { + const target = event.target as HTMLElement; + const navigatorItem = target.closest('.navigator-item'); + + if(!navigatorItem && setIsPopoverActive && setSelectedRoomId) + { + setIsPopoverActive(false); + setSelectedRoomId(null); + } + }; + + document.addEventListener('click', handleClickOutside); + return () => document.removeEventListener('click', handleClickOutside); + }, [ setIsPopoverActive, setSelectedRoomId ]); + const getUserCounterColor = () => { const num: number = (100 * (roomData.userCount / roomData.maxUserCount)); - let bg = 'bg-primary'; + if(num >= 92) return 'bg-danger'; + if(num >= 50) return 'bg-warning'; + if(num > 0) return 'bg-success'; - if(num >= 92) - { - bg = 'bg-danger'; - } - else if(num >= 50) - { - bg = 'bg-warning'; - } - else if(num > 0) - { - bg = 'bg-success'; - } - - return bg; + return 'bg-primary'; }; const visitRoom = (event: MouseEvent) => @@ -46,7 +95,6 @@ export const NavigatorSearchResultItemView: FC { const newValue = { ...prevValue }; - newValue.roomInfo = roomData; newValue.state = DoorStateType.START_DOORBELL; - return newValue; }); return; @@ -67,10 +113,8 @@ export const NavigatorSearchResultItemView: FC { const newValue = { ...prevValue }; - newValue.roomInfo = roomData; newValue.state = DoorStateType.START_PASSWORD; - return newValue; }); return; @@ -81,10 +125,20 @@ export const NavigatorSearchResultItemView: FC + - { roomData.habboGroupId > 0 && } - + { roomData.habboGroupId > 0 && } + { roomData.userCount } @@ -94,23 +148,42 @@ export const NavigatorSearchResultItemView: FC { roomData.roomName } - + { children } - ); return ( - - + + { roomData.userCount } - { roomData.roomName } - - + { roomData.roomName } + + { roomData.habboGroupId > 0 && } { (roomData.doorMode !== RoomDataParser.OPEN_STATE) && } diff --git a/src/components/navigator/views/search/NavigatorSearchResultView.tsx b/src/components/navigator/views/search/NavigatorSearchResultView.tsx index d7cd752..fcbe7d7 100644 --- a/src/components/navigator/views/search/NavigatorSearchResultView.tsx +++ b/src/components/navigator/views/search/NavigatorSearchResultView.tsx @@ -1,8 +1,8 @@ -import { NavigatorSearchComposer, NavigatorSearchResultList } from '@nitrots/nitro-renderer'; +import { NavigatorSearchComposer, NavigatorSearchResultList, NavigatorSearchSaveComposer } from '@nitrots/nitro-renderer'; import { FC, useEffect, useState } from 'react'; import { FaBars, FaMinus, FaPlus, FaTh, FaWindowMaximize, FaWindowRestore } from 'react-icons/fa'; import { LocalizeText, NavigatorSearchResultViewDisplayMode, SendMessageComposer } from '../../../../api'; -import { AutoGrid, AutoGridProps, Column, Flex, Grid, Text } from '../../../../common'; +import { AutoGrid, AutoGridProps, Column, Flex, Grid, LayoutSearchSavesView, Text } from '../../../../common'; import { useNavigator } from '../../../../hooks'; import { NavigatorSearchResultItemView } from './NavigatorSearchResultItemView'; @@ -16,6 +16,8 @@ export const NavigatorSearchResultView: FC = pro const { searchResult = null, ...rest } = props; const [ isExtended, setIsExtended ] = useState(true); const [ displayMode, setDisplayMode ] = useState(0); + const [ selectedRoomId, setSelectedRoomId ] = useState(null); + const [ isPopoverActive, setIsPopoverActive ] = useState(false); const { topLevelContext = null } = useNavigator(); @@ -23,7 +25,7 @@ export const NavigatorSearchResultView: FC = pro { let name = searchResult.code; - if(!name || !name.length || LocalizeText('navigator.searchcode.title.' + name) == ('navigator.searchcode.title.' + name)) return searchResult.data; + if(!name || !name.length || LocalizeText('navigator.searchcode.title.' + name) === ('navigator.searchcode.title.' + name)) return searchResult.data; if(name.startsWith('${')) return name.slice(2, (name.length - 1)); @@ -51,7 +53,6 @@ export const NavigatorSearchResultView: FC = pro if(!searchResult) return; setIsExtended(!searchResult.closed); - setDisplayMode(searchResult.mode); }, [ searchResult ]); @@ -65,54 +66,46 @@ export const NavigatorSearchResultView: FC = pro { !isExtended && } { LocalizeText(getResultTitle()) } -
- { (displayMode === NavigatorSearchResultViewDisplayMode.LIST) && } - { (displayMode >= NavigatorSearchResultViewDisplayMode.THUMBNAILS) && } - { (searchResult.action > 0) && (searchResult.action === 1) && } - { (searchResult.action > 0) && (searchResult.action !== 1) && } +
+ { (displayMode === NavigatorSearchResultViewDisplayMode.LIST) && } + { (displayMode >= NavigatorSearchResultViewDisplayMode.THUMBNAILS) && } + { (searchResult.action > 0) && (searchResult.action === 1) && } + { (searchResult.action > 0) && (searchResult.action !== 1) && } + SendMessageComposer(new NavigatorSearchSaveComposer(getResultTitle(), searchResult.data)) } + />
- - { isExtended && + + { isExtended && <> - { - gridHasTwoColumns ? - { searchResult.rooms.length > 0 && searchResult.rooms.map((room, index) => ) } - : - { searchResult.rooms.length > 0 && searchResult.rooms.map((room, index) => ) } - - } - - } + { gridHasTwoColumns + ? + { searchResult.rooms.length > 0 && searchResult.rooms.map((room, index) => ( + + )) } + + : + { searchResult.rooms.length > 0 && searchResult.rooms.map((room, index) => ( + + )) } + } + } - //
- //
- //
- // - //
{ LocalizeText(getResultTitle()) }
- // = NavigatorSearchResultViewDisplayMode.THUMBNAILS })}> - //
- // { isExtended && - //
= NavigatorSearchResultViewDisplayMode.THUMBNAILS) }) }> - // { searchResult.rooms.length > 0 && searchResult.rooms.map((room, index) => - // { - // return - // }) } - //
} - //
- //
- //
- //
- // - //
{ LocalizeText(getListCode()) }
- // = NavigatorResultListViewDisplayMode.THUMBNAILS })} onClick={ toggleDisplayMode }> - //
- //
= NavigatorResultListViewDisplayMode.THUMBNAILS }) }> - // { isExtended && resultList && resultList.rooms.map((room, index) => - // { - // return - // }) - // } - //
- //
); }; diff --git a/src/components/navigator/views/search/NavigatorSearchSavesResultItemView.tsx b/src/components/navigator/views/search/NavigatorSearchSavesResultItemView.tsx new file mode 100644 index 0000000..2c11dac --- /dev/null +++ b/src/components/navigator/views/search/NavigatorSearchSavesResultItemView.tsx @@ -0,0 +1,46 @@ +import { NavigatorDeleteSavedSearchComposer, NavigatorSavedSearch, NavigatorSearchComposer } from '@nitrots/nitro-renderer'; +import { FC, useState } from 'react'; +import { LocalizeText, SendMessageComposer } from '../../../../api'; +import { Flex, Text } from '../../../../common'; + +export interface NavigatorSearchSavesResultItemViewProps +{ + search: NavigatorSavedSearch; +} + +export const NavigatorSearchSavesResultItemView: FC = props => +{ + const { search = null } = props; + const [ isHovered, setIsHovered ] = useState(false); + + const getResultTitle = () => + { + let name = search.code; + + if(!name || !name.length || LocalizeText('navigator.searchcode.title.' + name) === ('navigator.searchcode.title.' + name)) return search.code; + + if(name.startsWith('${')) return name.slice(2, (name.length - 1)); + + return ('navigator.searchcode.title.' + name); + }; + + return ( + setIsHovered(true) } onMouseLeave={ () => setIsHovered(false) }> + { isHovered && + SendMessageComposer(new NavigatorDeleteSavedSearchComposer(search.id)) } + /> } + SendMessageComposer(new NavigatorSearchComposer(search.code.split('.').reverse()[0], search.filter)) } + > + { LocalizeText(getResultTitle()) } + + + ); +}; diff --git a/src/components/navigator/views/search/NavigatorSearchSavesResultView.tsx b/src/components/navigator/views/search/NavigatorSearchSavesResultView.tsx new file mode 100644 index 0000000..9fbc9fa --- /dev/null +++ b/src/components/navigator/views/search/NavigatorSearchSavesResultView.tsx @@ -0,0 +1,31 @@ +import { NavigatorSavedSearch } from '@nitrots/nitro-renderer'; +import { FC } from 'react'; +import { FaBolt } from 'react-icons/fa'; +import { LocalizeText } from '../../../../api'; +import { Column, Flex, Text } from '../../../../common'; +import { NavigatorSearchSavesResultItemView } from './NavigatorSearchSavesResultItemView'; + +export interface NavigatorSearchSavesResultViewProps +{ + searches: NavigatorSavedSearch[]; +} + +export const NavigatorSearchSavesResultView: FC = props => +{ + const { searches = [] } = props; + + return ( + + + + { LocalizeText('navigator.quick.links.title') } + + + { (searches && searches.length > 0) && + searches.map((search: NavigatorSavedSearch) => ( + + )) } + + + ); +}; diff --git a/src/css/icons/icons.css b/src/css/icons/icons.css index e5c0fe2..e8382b2 100644 --- a/src/css/icons/icons.css +++ b/src/css/icons/icons.css @@ -668,4 +668,18 @@ .nitro-icon.icon-loading.with-size { width: 16px; height: 16px; +} + +.nitro-icon.icon-navigator-search-delete { + background-image: url("@/assets/images/navigator/saves-search/delete_search.png"); + width: 18px; + height: 18px; +} + +.nitro-icon.icon-navigator-search-delete:hover { + background-image: url("@/assets/images/navigator/saves-search/delete_search_hover.png"); +} + +.nitro-icon.icon-navigator-search-delete:active { + background-image: url("@/assets/images/navigator/saves-search/delete_search_click.png"); } \ No newline at end of file diff --git a/src/hooks/navigator/useNavigator.ts b/src/hooks/navigator/useNavigator.ts index 60f949e..90df9fc 100644 --- a/src/hooks/navigator/useNavigator.ts +++ b/src/hooks/navigator/useNavigator.ts @@ -1,4 +1,4 @@ -import { CanCreateRoomEventEvent, CantConnectMessageParser, CreateLinkEvent, DoorbellMessageEvent, FlatAccessDeniedMessageEvent, FlatCreatedEvent, FollowFriendMessageComposer, GenericErrorEvent, GetGuestRoomMessageComposer, GetGuestRoomResultEvent, GetSessionDataManager, GetUserEventCatsMessageComposer, GetUserFlatCatsMessageComposer, HabboWebTools, LegacyExternalInterface, NavigatorCategoryDataParser, NavigatorEventCategoryDataParser, NavigatorHomeRoomEvent, NavigatorMetadataEvent, NavigatorOpenRoomCreatorEvent, NavigatorSearchEvent, NavigatorSearchResultSet, NavigatorTopLevelContext, RoomDataParser, RoomDoorbellAcceptedEvent, RoomEnterErrorEvent, RoomEntryInfoMessageEvent, RoomForwardEvent, RoomScoreEvent, RoomSettingsUpdatedEvent, SecurityLevel, UserEventCatsEvent, UserFlatCatsEvent, UserInfoEvent, UserPermissionsEvent } from '@nitrots/nitro-renderer'; +import { CanCreateRoomEventEvent, CantConnectMessageParser, CreateLinkEvent, DoorbellMessageEvent, FavouriteChangedEvent, FavouritesEvent, FlatAccessDeniedMessageEvent, FlatCreatedEvent, FollowFriendMessageComposer, GenericErrorEvent, GetGuestRoomMessageComposer, GetGuestRoomResultEvent, GetSessionDataManager, GetUserEventCatsMessageComposer, GetUserFlatCatsMessageComposer, HabboWebTools, LegacyExternalInterface, NavigatorCategoryDataParser, NavigatorEventCategoryDataParser, NavigatorHomeRoomEvent, NavigatorMetadataEvent, NavigatorOpenRoomCreatorEvent, NavigatorSavedSearch, NavigatorSearchesEvent, NavigatorSearchEvent, NavigatorSearchResultSet, NavigatorTopLevelContext, 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'; @@ -9,10 +9,12 @@ const useNavigatorState = () => { const [ categories, setCategories ] = useState(null); const [ eventCategories, setEventCategories ] = useState(null); + const [ favouriteRoomIds, setFavouriteRoomIds ] = useState([]); const [ topLevelContext, setTopLevelContext ] = useState(null); const [ topLevelContexts, setTopLevelContexts ] = useState(null); const [ doorData, setDoorData ] = useState<{ roomInfo: RoomDataParser, state: number }>({ roomInfo: null, state: DoorStateType.NONE }); const [ searchResult, setSearchResult ] = useState(null); + const [ navigatorSearches, setNavigatorSearches ] = useState(null); const [ navigatorData, setNavigatorData ] = useState({ settingsReceived: false, homeRoomId: 0, @@ -29,6 +31,29 @@ const useNavigatorState = () => }); const { simpleAlert = null } = useNotification(); + useMessageEvent(FavouritesEvent, event => + { + const parser = event.getParser(); + const favoriteIds = (parser.favoriteRoomIds || []).map((x: any) => Number(x)); + setFavouriteRoomIds(favoriteIds); + }); + + useMessageEvent(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, event => { const parser = event.getParser(); @@ -436,7 +461,14 @@ const useNavigatorState = () => useMessageEvent(NavigatorOpenRoomCreatorEvent, event => CreateLinkEvent('navigator/show')); - return { categories, doorData, setDoorData, topLevelContext, topLevelContexts, searchResult, navigatorData }; + useMessageEvent(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);