diff --git a/src/common/layout/LayoutSearchSavesView.tsx b/src/common/layout/LayoutSearchSavesView.tsx new file mode 100644 index 00000000..c9c893a6 --- /dev/null +++ b/src/common/layout/LayoutSearchSavesView.tsx @@ -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 = props => +{ + const { title = null, onSaveSearch = null, onClick = null } = props; + + return ( + + + + ); +} diff --git a/src/common/layout/index.ts b/src/common/layout/index.ts index 3c4238e1..e3c952f5 100644 --- a/src/common/layout/index.ts +++ b/src/common/layout/index.ts @@ -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'; diff --git a/src/components/navigator/NavigatorView.scss b/src/components/navigator/NavigatorView.scss index ef235bc0..09a59abb 100644 --- a/src/components/navigator/NavigatorView.scss +++ b/src/components/navigator/NavigatorView.scss @@ -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; +} diff --git a/src/components/navigator/NavigatorView.tsx b/src/components/navigator/NavigatorView.tsx index dcc2f9eb..2ef8f60f 100644 --- a/src/components/navigator/NavigatorView.tsx +++ b/src/components/navigator/NavigatorView.tsx @@ -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(); @@ -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 => setIsVisible(false) } /> + + setIsOpenSavesSearchs(prevValue => !prevValue) } /> + { topLevelContexts && (topLevelContexts.length > 0) && topLevelContexts.map((context, index) => { return ( @@ -216,10 +221,18 @@ export const NavigatorView: FC<{}> = props => } { !isCreatorOpen && <> - - - { (searchResult && searchResult.results.map((result, index) => )) } - + + { (isOpenSavesSearchs) && + + + } + + + + { (searchResult && searchResult.results.map((result, index) => )) } + + + } { isCreatorOpen && } diff --git a/src/components/navigator/views/search/NavigatorSearchResultView.tsx b/src/components/navigator/views/search/NavigatorSearchResultView.tsx index 0c25833e..ce35871f 100644 --- a/src/components/navigator/views/search/NavigatorSearchResultView.tsx +++ b/src/components/navigator/views/search/NavigatorSearchResultView.tsx @@ -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 = pro const { searchResult = null, ...rest } = props; const [ isExtended, setIsExtended ] = useState(true); const [ displayMode, setDisplayMode ] = useState(0); - - const { topLevelContext = null } = useNavigator(); + const { topLevelContext = null, searchResultQuery = null } = useNavigator(); const getResultTitle = () => { @@ -39,8 +38,8 @@ export const NavigatorSearchResultView: FC = 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 = pro if(!searchResult) return; setIsExtended(!searchResult.closed); - + setDisplayMode(searchResult.mode); }, [ searchResult ]); const gridHasTwoColumns = (displayMode >= NavigatorSearchResultViewDisplayMode.THUMBNAILS); - + return ( @@ -67,9 +66,11 @@ export const NavigatorSearchResultView: FC = pro = NavigatorSearchResultViewDisplayMode.THUMBNAILS) ? 'bars' : null) } className="text-secondary" onClick={ toggleDisplayMode } /> { (searchResult.action > 0) && } + { (topLevelContext.code !== 'official_view') && + SendMessageComposer(new NavigatorSearchSaveComposer(getResultTitle(), searchResultQuery)) } /> } - { isExtended && + { isExtended && <> { gridHasTwoColumns ? diff --git a/src/components/navigator/views/search/NavigatorSearchSavesResultItemView.tsx b/src/components/navigator/views/search/NavigatorSearchSavesResultItemView.tsx new file mode 100644 index 00000000..606e8dc3 --- /dev/null +++ b/src/components/navigator/views/search/NavigatorSearchSavesResultItemView.tsx @@ -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 = props => +{ + const { search = null } = props; + const [ isHoverText, setIsHoverText ] = useState(false); + const [ currentIndex, setCurrentIndex ] = useState(0); + + const onHover = (searchId: number) => + { + setCurrentIndex(searchId); + setIsHoverText(true); + } + + const onLeave = () => + { + setCurrentIndex(0); + setIsHoverText(false); + } + + return ( + onHover(search.id) } onMouseLeave={ () => onLeave() }> + { (isHoverText && currentIndex === search.id) && + SendMessageComposer(new NavigatorDeleteSavedSearchComposer(search.id)) } /> } + 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 }`) } + + ); +} diff --git a/src/components/navigator/views/search/NavigatorSearchSavesResultView.tsx b/src/components/navigator/views/search/NavigatorSearchSavesResultView.tsx new file mode 100644 index 00000000..12eea5d8 --- /dev/null +++ b/src/components/navigator/views/search/NavigatorSearchSavesResultView.tsx @@ -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 = props => +{ + const { searchs = [] } = props; + + return ( + + + + { LocalizeText('navigator.quick.links.title') } + + + { (searchs && searchs.length > 0) && + searchs.map((search: NavigatorSavedSearch) => ) + } + + + ); +} diff --git a/src/hooks/navigator/useNavigator.ts b/src/hooks/navigator/useNavigator.ts index 18d6ebdb..cf619faf 100644 --- a/src/hooks/navigator/useNavigator.ts +++ b/src/hooks/navigator/useNavigator.ts @@ -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(null); const [ doorData, setDoorData ] = useState<{ roomInfo: RoomDataParser, state: number }>({ roomInfo: null, state: DoorStateType.NONE }); const [ searchResult, setSearchResult ] = useState(null); + const [ searchResultQuery, setSearchResultQuery ] = useState(''); + const [ navigatorSearches, setNavigatorSearches ] = useState(null); const [ navigatorData, setNavigatorData ] = useState({ settingsReceived: false, homeRoomId: 0, @@ -198,7 +200,7 @@ const useNavigatorState = () => }); }); - useMessageEvent(DoorbellMessageEvent, event => + useMessageEvent(DoorbellMessageEvent, event => { const parser = event.getParser(); @@ -325,6 +327,7 @@ const useNavigatorState = () => }); setSearchResult(parser.result); + setSearchResultQuery(parser.result.data); }); useMessageEvent(UserFlatCatsEvent, event => @@ -436,7 +439,16 @@ 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, navigatorSearches, searchResultQuery }; } export const useNavigator = () => useBetween(useNavigatorState);