nitro-v36-with-renderer-v36
/
src /
components /
navigator /
views /
search /
NavigatorSearchResultView.tsx
NavigatorSearchResultView.tsx 8.8 Ko
Télécharger le fichier
import { Collapsible } from '@base-ui/react/collapsible';
import { NavigatorSearchResultList, NavigatorSearchSaveComposer, PerkEnum } from '@octane/renderer';
import { FC } from 'react';
import { LocalizeText, localizeServerText, localizeWithFallback, NavigatorSearchResultViewDisplayMode, SendMessageComposer } from '../../../../api';
import categoryCollapse from '../../../../assets/images/navigator/air/category-collapse.png';
import categoryExpand from '../../../../assets/images/navigator/air/category-expand.png';
import categoryShowMore from '../../../../assets/images/navigator/air/category-show-more.png';
import navViewMini from '../../../../assets/images/navigator/air/nav-view-mini.png';
import navViewRow from '../../../../assets/images/navigator/air/nav-view-row.png';
import navViewThumbs from '../../../../assets/images/navigator/air/nav-view-thumbs.png';
import { LayoutSearchSavesView } from '../../../../common';
import { useNavigatorData, useNavigatorUiStore, usePerkAllowed } from '../../../../hooks';
import { NavigatorSearchResultItemView } from './NavigatorSearchResultItemView';
import { BaseButton } from '../../../../common/BaseButton';
import { Hint } from '../../../../common/Tooltip';
import { NativeTextTree } from '../../../../common/native-text/NativeTextTree';
export interface NavigatorSearchResultViewProps {
searchResult: NavigatorSearchResultList;
parentCode?: string;
parentFilter?: string;
forceOpen?: boolean;
}
const isEventView = (code: string) => code === 'roomads_view' || code === 'new_ads' || code.startsWith('eventcategory__');
export const NavigatorSearchResultView: FC<NavigatorSearchResultViewProps> = (props) => {
const { searchResult = null, parentCode = '', parentFilter = '', forceOpen = false } = props;
const { topLevelContext } = useNavigatorData();
const isExtended = useNavigatorUiStore((state) => {
if (forceOpen && !state.collapsedResultCodes.includes(searchResult.code)) return true;
return state.expandedResultCodes.includes(searchResult.code) || (!state.collapsedResultCodes.includes(searchResult.code) && !searchResult.closed);
});
const thumbnailPerk = usePerkAllowed(PerkEnum.NAVIGATOR_ROOM_THUMBNAIL_CAMERA);
const chosenMode = useNavigatorUiStore((state) => state.resultViewModes[searchResult.code] ?? searchResult.mode);
// AIR BlockResultsView: without the thumbnail perk every block is rows, except under the official view.
const officialView = topLevelContext?.code === 'official_view' || parentCode === 'official_view';
const displayMode = thumbnailPerk ? chosenMode : officialView ? searchResult.mode : NavigatorSearchResultViewDisplayMode.LIST;
const getResultTitle = () => {
const name = searchResult.code;
// AIR: the server's block text when it has one, else the search code's title.
// The server often sends a text key (`${navigator.flatcategory.global.BC}`): it is looked up like AIR does.
if (searchResult.data) return localizeServerText(searchResult.data);
if (!name || !name.length) return '';
if (name.startsWith('${')) return localizeServerText(name);
return localizeWithFallback('navigator.searchcode.title.' + name, name);
};
const toggleDisplayMode = () => {
const nextMode =
displayMode === NavigatorSearchResultViewDisplayMode.LIST
? NavigatorSearchResultViewDisplayMode.THUMBNAILS
: NavigatorSearchResultViewDisplayMode.LIST;
useNavigatorUiStore.getState().setResultViewMode(searchResult.code, nextMode);
};
const showMore = () => {
if (searchResult.action == 1) {
useNavigatorUiStore.getState().setSearch(searchResult.code, parentFilter);
return;
}
if (searchResult.action != 2) return;
// Back returns to the previous search, like Habbo; without history it goes to the tab root.
const store = useNavigatorUiStore.getState();
if (store.searchHistoryOffset > 0) store.goBack();
else if (topLevelContext) store.setSearch(topLevelContext.code, '');
};
const isTileMode = displayMode >= NavigatorSearchResultViewDisplayMode.THUMBNAILS;
const resultTitle = getResultTitle();
const listViewLabel = localizeWithFallback('navigator.viewmode.list', 'Show rooms as a list');
const tileViewLabel = localizeWithFallback('navigator.viewmode.tiles', 'Show rooms as tiles');
const hideSave = parentCode === 'official_view' || searchResult.code === 'official_view';
const eventTitle = isEventView(searchResult.code) || isEventView(parentCode);
return (
<NativeTextTree>
<Collapsible.Root
render={<section />}
className={`octane-navigator-air__category${isExtended ? '' : ' is-collapsed'}`}
open={isExtended}
onOpenChange={() => useNavigatorUiStore.getState().setResultCollapsed(searchResult.code, isExtended)}
>
<header className="octane-navigator-air__category-header">
<Collapsible.Trigger className="octane-navigator-air__category-toggle" aria-label={resultTitle}>
<img src={isExtended ? categoryCollapse : categoryExpand} alt="" />
<span>{resultTitle}</span>
</Collapsible.Trigger>
<div className="octane-navigator-air__category-controls">
{isExtended && thumbnailPerk && displayMode === NavigatorSearchResultViewDisplayMode.LIST && (
<Hint content={tileViewLabel}>
<BaseButton
type="button"
className="octane-navigator-air__icon-button"
aria-label={tileViewLabel}
onClick={toggleDisplayMode}
>
<img src={navViewThumbs} alt="" />
</BaseButton>
</Hint>
)}
{isExtended && thumbnailPerk && isTileMode && (
<Hint content={listViewLabel}>
<BaseButton
type="button"
className="octane-navigator-air__icon-button"
aria-label={listViewLabel}
onClick={toggleDisplayMode}
>
<img src={navViewRow} alt="" />
</BaseButton>
</Hint>
)}
{searchResult.action > 0 && searchResult.action === 1 && (
<Hint content={LocalizeText('navigator.more.rooms')}>
<BaseButton aria-label={LocalizeText('navigator.more.rooms')} type="button" className="octane-navigator-air__icon-button" onClick={showMore}>
<img src={categoryShowMore} alt="" />
</BaseButton>
</Hint>
)}
{searchResult.action > 0 && searchResult.action !== 1 && (
<Hint content={LocalizeText('navigator.back')}>
<BaseButton aria-label={LocalizeText('navigator.back')} type="button" className="octane-navigator-air__icon-button" onClick={showMore}>
<img src={navViewMini} alt="" />
</BaseButton>
</Hint>
)}
{!hideSave && (
<LayoutSearchSavesView
title={LocalizeText('navigator.tooltip.add.saved.search')}
onClick={() => SendMessageComposer(new NavigatorSearchSaveComposer(searchResult.code, parentFilter))}
/>
)}
</div>
</header>
<Collapsible.Panel className={isTileMode ? 'octane-navigator-air__tiles' : 'octane-navigator-air__rows'}>
{searchResult.rooms.map((room, index) => (
<NavigatorSearchResultItemView
key={room.roomId || index}
roomData={room}
thumbnail={isTileMode}
eventTitle={eventTitle}
stripe={isTileMode ? Math.floor(index / 3) % 2 === 1 : index % 2 === 1}
/>
))}
</Collapsible.Panel>
</Collapsible.Root>
</NativeTextTree>
);
};
