#55 - Navigator saved searches

This commit is contained in:
oobjectt 2022-12-30 22:38:12 +01:00
parent 9693bcae0b
commit 00fab2b19e
8 changed files with 168 additions and 33 deletions

View File

@ -0,0 +1,21 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { FC } from 'react';
import { Base } from '../Base';
export interface LayoutSearchSavesViewProps
{
title: string;
onSaveSearch?: () => void;
onClick?: () => void;
}
export const LayoutSearchSavesView: FC<LayoutSearchSavesViewProps> = props =>
{
const { title = null, onSaveSearch = null, onClick = null } = props;
return (
<Base color="white" className="button-search-saves" pointer title={ title } onClickCapture={ onSaveSearch } onClick={ onClick }>
<FontAwesomeIcon icon="bolt-lightning" />
</Base>
);
}

View File

@ -18,6 +18,7 @@ export * from './LayoutProgressBar';
export * from './LayoutRarityLevelView';
export * from './LayoutRoomPreviewerView';
export * from './LayoutRoomThumbnailView';
export * from './LayoutSearchSavesView';
export * from './LayoutTrophyView';
export * from './limited-edition';
export * from './UserProfileIconView';

View File

@ -15,17 +15,17 @@
&:not(.two-columns) {
.navigator-item {
&:nth-child(odd) {
background-color: $grid-active-bg-color;
}
}
}
&.two-columns {
.navigator-item {
&:nth-child(4n-2),
&:nth-child(4n-3) {
background: $grid-active-bg-color;
@ -60,6 +60,26 @@
}
}
.nitro-navigator-search-saves-result {
background-color: #fff;
width: 100px;
height: 350px;
border-radius: 10px;
.bg-orange {
background-color: #FAA700;
}
}
.room-info {
width: 275px;
}
.button-search-saves {
padding: 4px;
height: 17px;
margin-top: -1px;
font-size: 10px;
border-radius: 4px;
background-color: #FAA700;
}

View File

@ -2,7 +2,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { ConvertGlobalRoomIdMessageComposer, HabboWebTools, ILinkEventTracker, LegacyExternalInterface, NavigatorInitComposer, NavigatorSearchComposer, RoomSessionEvent } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useRef, useState } from 'react';
import { AddEventLinkTracker, LocalizeText, RemoveLinkEventTracker, SendMessageComposer, TryVisitRoom } from '../../api';
import { Base, Column, NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../common';
import { Base, Column, Flex, LayoutSearchSavesView, NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../common';
import { useNavigator, useRoomSessionManagerEvent } from '../../hooks';
import { NavigatorDoorStateView } from './views/NavigatorDoorStateView';
import { NavigatorRoomCreatorView } from './views/NavigatorRoomCreatorView';
@ -10,6 +10,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 +20,11 @@ export const NavigatorView: FC<{}> = props =>
const [ isCreatorOpen, setCreatorOpen ] = useState(false);
const [ isRoomInfoOpen, setRoomInfoOpen ] = useState(false);
const [ isRoomLinkOpen, setRoomLinkOpen ] = useState(false);
const [ isOpenSavesSearchs, setIsOpenSavesSearchs ] = 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<HTMLDivElement>();
@ -77,9 +79,9 @@ export const NavigatorView: FC<{}> = props =>
linkReceived: (url: string) =>
{
const parts = url.split('/');
if(parts.length < 2) return;
switch(parts[1])
{
case 'show': {
@ -94,10 +96,10 @@ export const NavigatorView: FC<{}> = props =>
if(isVisible)
{
setIsVisible(false);
return;
}
setIsVisible(true);
setNeedsSearch(true);
return;
@ -110,17 +112,17 @@ export const NavigatorView: FC<{}> = props =>
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);
}
}
@ -133,13 +135,13 @@ export const NavigatorView: FC<{}> = props =>
if(parts.length > 2)
{
const topLevelContextCode = parts[2];
let searchValue = '';
if(parts.length > 3) searchValue = parts[3];
pendingSearch.current = { value: searchValue, code: topLevelContextCode };
setIsVisible(true);
setNeedsSearch(true);
}
@ -199,6 +201,9 @@ export const NavigatorView: FC<{}> = props =>
<NitroCardView uniqueKey="navigator" className="nitro-navigator">
<NitroCardHeaderView headerText={ LocalizeText(isCreatorOpen ? 'navigator.createroom.title' : 'navigator.title') } onCloseClick={ event => setIsVisible(false) } />
<NitroCardTabsView>
<Base className="mt-1">
<LayoutSearchSavesView title={ LocalizeText('navigator.tooltip.left.show.hide') } onClick={ () => setIsOpenSavesSearchs(prevValue => !prevValue) } />
</Base>
{ topLevelContexts && (topLevelContexts.length > 0) && topLevelContexts.map((context, index) =>
{
return (
@ -216,10 +221,18 @@ export const NavigatorView: FC<{}> = props =>
<Base fit position="absolute" className="top-0 start-0 z-index-1 bg-muted opacity-0-5" /> }
{ !isCreatorOpen &&
<>
<NavigatorSearchView sendSearch={ sendSearch } />
<Column innerRef={ elementRef } overflow="auto">
{ (searchResult && searchResult.results.map((result, index) => <NavigatorSearchResultView key={ index } searchResult={ result } />)) }
</Column>
<Flex gap={ 1 }>
{ (isOpenSavesSearchs) &&
<Column>
<NavigatorSearchSavesResultView searchs={ navigatorSearches } />
</Column> }
<Column fullWidth>
<NavigatorSearchView sendSearch={ sendSearch } />
<Column innerRef={ elementRef } overflow="auto">
{ (searchResult && searchResult.results.map((result, index) => <NavigatorSearchResultView key={ index } searchResult={ result } />)) }
</Column>
</Column>
</Flex>
</> }
{ isCreatorOpen && <NavigatorRoomCreatorView /> }
</NitroCardContentView>

View File

@ -1,8 +1,8 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { NavigatorSearchComposer, NavigatorSearchResultList } from '@nitrots/nitro-renderer';
import { NavigatorSearchComposer, NavigatorSearchResultList, NavigatorSearchSaveComposer } from '@nitrots/nitro-renderer';
import { FC, useEffect, useState } from 'react';
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,8 +16,7 @@ export const NavigatorSearchResultView: FC<NavigatorSearchResultViewProps> = pro
const { searchResult = null, ...rest } = props;
const [ isExtended, setIsExtended ] = useState(true);
const [ displayMode, setDisplayMode ] = useState<number>(0);
const { topLevelContext = null } = useNavigator();
const { topLevelContext = null, searchResultQuery = null } = useNavigator();
const getResultTitle = () =>
{
@ -39,8 +38,8 @@ export const NavigatorSearchResultView: FC<NavigatorSearchResultViewProps> = pro
return NavigatorSearchResultViewDisplayMode.LIST;
});
}
const showMore = () =>
const showMore = () =>
{
if(searchResult.action == 1) SendMessageComposer(new NavigatorSearchComposer(searchResult.code, ''));
else if(searchResult.action == 2 && topLevelContext) SendMessageComposer(new NavigatorSearchComposer(topLevelContext.code,''));
@ -51,12 +50,12 @@ export const NavigatorSearchResultView: FC<NavigatorSearchResultViewProps> = pro
if(!searchResult) return;
setIsExtended(!searchResult.closed);
setDisplayMode(searchResult.mode);
}, [ searchResult ]);
const gridHasTwoColumns = (displayMode >= NavigatorSearchResultViewDisplayMode.THUMBNAILS);
return (
<Column className="bg-white rounded border border-muted" gap={ 0 }>
<Flex fullWidth alignItems="center" justifyContent="between" className="px-2 py-1">
@ -67,9 +66,11 @@ export const NavigatorSearchResultView: FC<NavigatorSearchResultViewProps> = pro
<Flex gap={ 2 }>
<FontAwesomeIcon icon={ ((displayMode === NavigatorSearchResultViewDisplayMode.LIST) ? 'th' : (displayMode >= NavigatorSearchResultViewDisplayMode.THUMBNAILS) ? 'bars' : null) } className="text-secondary" onClick={ toggleDisplayMode } />
{ (searchResult.action > 0) && <FontAwesomeIcon icon={ searchResult.action == 1 ? 'window-maximize' : 'window-restore' } className="text-secondary" onClick={ showMore } /> }
{ (topLevelContext.code !== 'official_view') &&
<LayoutSearchSavesView title={ LocalizeText('navigator.tooltip.add.saved.search') } onSaveSearch={ () => SendMessageComposer(new NavigatorSearchSaveComposer(getResultTitle(), searchResultQuery)) } /> }
</Flex>
</Flex> { isExtended &&
</Flex> { isExtended &&
<>
{
gridHasTwoColumns ? <AutoGrid columnCount={ 3 } { ...rest } columnMinWidth={ 110 } columnMinHeight={ 130 } className="mx-2">

View File

@ -0,0 +1,37 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
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<NavigatorSearchSavesResultItemViewProps> = props =>
{
const { search = null } = props;
const [ isHoverText, setIsHoverText ] = useState<boolean>(false);
const [ currentIndex, setCurrentIndex ] = useState<number>(0);
const onHover = (searchId: number) =>
{
setCurrentIndex(searchId);
setIsHoverText(true);
}
const onLeave = () =>
{
setCurrentIndex(0);
setIsHoverText(false);
}
return (
<Flex grow pointer alignItems="center" gap={ 1 } onMouseEnter={ () => onHover(search.id) } onMouseLeave={ () => onLeave() }>
{ (isHoverText && currentIndex === search.id) &&
<FontAwesomeIcon color="red" icon="subtract" title={ LocalizeText('navigator.tooltip.remove.saved.search') } onClick={ () => SendMessageComposer(new NavigatorDeleteSavedSearchComposer(search.id)) } /> }
<Text pointer variant="black" title={ LocalizeText('navigator.tooltip.open.saved.search') } onClick={ () => SendMessageComposer(new NavigatorSearchComposer(search.code.split('.').reverse()[0], search.filter)) }>{ search.filter !== '' ? LocalizeText('navigator.searchcode.title.query') + ': ' + (!search.filter.split(':')[1] ? search.filter : search.filter.split(':')[1]) : LocalizeText(`${ search.code }`) }</Text>
</Flex>
);
}

View File

@ -0,0 +1,30 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { NavigatorSavedSearch } from '@nitrots/nitro-renderer';
import { FC } from 'react';
import { LocalizeText } from '../../../../api';
import { Column, Flex, Text } from '../../../../common';
import { NavigatorSearchSavesResultItemView } from './NavigatorSearchSavesResultItemView';
export interface NavigatorSearchSavesResultViewProps
{
searchs: NavigatorSavedSearch[]
}
export const NavigatorSearchSavesResultView: FC<NavigatorSearchSavesResultViewProps> = props =>
{
const { searchs = [] } = props;
return (
<Column className="nitro-navigator-search-saves-result">
<Flex className="badge p-1 bg-orange" gap={ 1 }>
<FontAwesomeIcon color="white" icon="bolt-lightning" />
<Text variant="white">{ LocalizeText('navigator.quick.links.title') }</Text>
</Flex>
<Column className="p-1" style={ { overflowX: 'hidden', overflowY: 'auto' } }>
{ (searchs && searchs.length > 0) &&
searchs.map((search: NavigatorSavedSearch) => <NavigatorSearchSavesResultItemView key={ search.id } search={ search } />)
}
</Column>
</Column>
);
}

View File

@ -1,4 +1,4 @@
import { CanCreateRoomEventEvent, CantConnectMessageParser, DoorbellMessageEvent, FlatAccessDeniedMessageEvent, FlatCreatedEvent, FollowFriendMessageComposer, GenericErrorEvent, GetGuestRoomMessageComposer, GetGuestRoomResultEvent, 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, DoorbellMessageEvent, FlatAccessDeniedMessageEvent, FlatCreatedEvent, FollowFriendMessageComposer, GenericErrorEvent, GetGuestRoomMessageComposer, GetGuestRoomResultEvent, 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 { CreateLinkEvent, CreateRoomSession, DoorStateType, GetConfiguration, GetSessionDataManager, INavigatorData, LocalizeText, NotificationAlertType, SendMessageComposer, TryVisitRoom, VisitDesktop } from '../../api';
@ -13,6 +13,8 @@ const useNavigatorState = () =>
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 [ searchResultQuery, setSearchResultQuery ] = useState<string>('');
const [ navigatorSearches, setNavigatorSearches ] = useState<NavigatorSavedSearch[]>(null);
const [ navigatorData, setNavigatorData ] = useState<INavigatorData>({
settingsReceived: false,
homeRoomId: 0,
@ -198,7 +200,7 @@ const useNavigatorState = () =>
});
});
useMessageEvent<DoorbellMessageEvent>(DoorbellMessageEvent, event =>
useMessageEvent<DoorbellMessageEvent>(DoorbellMessageEvent, event =>
{
const parser = event.getParser();
@ -325,6 +327,7 @@ const useNavigatorState = () =>
});
setSearchResult(parser.result);
setSearchResultQuery(parser.result.data);
});
useMessageEvent<UserFlatCatsEvent>(UserFlatCatsEvent, event =>
@ -436,7 +439,16 @@ const useNavigatorState = () =>
useMessageEvent<NavigatorOpenRoomCreatorEvent>(NavigatorOpenRoomCreatorEvent, event => CreateLinkEvent('navigator/show'));
return { categories, doorData, setDoorData, topLevelContext, topLevelContexts, searchResult, navigatorData };
useMessageEvent<NavigatorSearchesEvent>(NavigatorSearchesEvent, event =>
{
const parser = event.getParser();
if (!parser) return;
setNavigatorSearches(parser.searches);
});
return { categories, doorData, setDoorData, topLevelContext, topLevelContexts, searchResult, navigatorData, navigatorSearches, searchResultQuery };
}
export const useNavigator = () => useBetween(useNavigatorState);