Merge branch 'duckietm:main' into feat/navigator-p4-visual-wave1

This commit is contained in:
Life
2026-05-30 09:38:44 +02:00
committed by GitHub
45 changed files with 1400 additions and 754 deletions
+1
View File
@@ -1,4 +1,5 @@
export * from './useCatalog';
export * from './useCatalogClassicStyle';
export * from './useCatalogFavorites';
export * from './useCatalogPlaceMultipleItems';
export * from './useCatalogSkipPurchaseConfirmation';
@@ -0,0 +1,14 @@
import { useBetween } from 'use-between';
import { GetConfigurationValue, LocalStorageKeys } from '../../api';
import { useLocalStorage } from '../useLocalStorage';
// Per-user toggle for the catalog visual style.
// - true => classic (old) catalog look
// - false => modern (rebuilt) catalog look
// The default for users who never touched the toggle comes from the global
// `catalog.classic.style` flag in ui-config.json, so an admin can flip the
// default for everyone (true = classic for all, false = modern for all)
// while still letting each user override it from the settings panel.
const useCatalogClassicStyleState = () => useLocalStorage<boolean>(LocalStorageKeys.CATALOG_CLASSIC_STYLE, GetConfigurationValue<boolean>('catalog.classic.style', false));
export const useCatalogClassicStyle = () => useBetween(useCatalogClassicStyleState);
+31 -3
View File
@@ -1,14 +1,29 @@
import { NavigatorSearchComposer, NavigatorSearchEvent, NavigatorSearchResultSet } from '@nitrots/nitro-renderer';
import { FlatCreatedEvent, NavigatorSearchComposer, NavigatorSearchEvent, NavigatorSearchResultSet } from '@nitrots/nitro-renderer';
import { useQueryClient } from '@tanstack/react-query';
import { useEffect, useState } from 'react';
import { SendMessageComposer } from '../../api';
import { useMessageEvent } from '../events';
import { useNavigatorUiStore } from './navigatorUiStore';
/**
* Navigator search hook.
*
* Fires NavigatorSearchComposer(tabCode, filter) whenever the active tab
* or filter changes (skipped when tabCode is '' — initial state, before
* metadata arrives). Holds the latest NavigatorSearchResultSet that
* matches the active tab.
*
* The TanStack Query variant (see useNitroQuery) was tried earlier but
* its one-shot listener doesn't always reach NavigatorSearchEvent in
* production builds with older renderer SDKs; the persistent
* useMessageEvent listener used here matches the rest of the codebase
* and reliably catches every server push.
*/
export const useNavigatorSearch = () =>
{
const tabCode = useNavigatorUiStore(s => s.currentTabCode);
const filter = useNavigatorUiStore(s => s.currentFilter);
const queryClient = useQueryClient();
const [ searchResult, setSearchResult ] = useState<NavigatorSearchResultSet | null>(null);
const [ isFetching, setIsFetching ] = useState(false);
@@ -26,12 +41,25 @@ export const useNavigatorSearch = () =>
const result = event.getParser()?.result;
if(!result) return;
if(tabCode && result.code !== tabCode) return;
// No active tab → the search query is disabled, ignore any event.
// Otherwise only accept the event whose code matches the active tab.
if(!tabCode || (result.code !== tabCode)) return;
setSearchResult(result);
setIsFetching(false);
});
// A newly created room invalidates the current search so it refetches.
useMessageEvent<FlatCreatedEvent>(FlatCreatedEvent, () =>
{
queryClient.invalidateQueries({ queryKey: [ 'navigator', 'search' ] });
if(!tabCode) return;
setIsFetching(true);
SendMessageComposer(new NavigatorSearchComposer(tabCode, filter));
});
return {
searchResult,
isFetching,
+3 -1
View File
@@ -31,7 +31,9 @@ const useRadioState = () =>
if(loadStartedRef.current) return;
loadStartedRef.current = true;
const url = GetConfigurationValue<string>('radio.stations.url') || 'configuration/radio-stations.json5';
const url = GetConfigurationValue<string>('radio.url')
|| GetConfigurationValue<string>('radio.stations.url')
|| 'configuration/radio-stations.json5';
(async () =>
{
@@ -4,6 +4,9 @@ import { CommandDefinition, LocalizeText } from '../../../api';
import { createNitroStore } from '../../../state/createNitroStore';
import { useMessageEvent } from '../../events';
// Client-only commands are static; safe to keep at module scope. The
// `descriptionKey` is a LocalizeText slot resolved at merge time so
// hotels in different locales see the right language.
const CLIENT_COMMANDS: { key: string; descriptionKey: string }[] = [
// Room effects
{ key: 'shake', descriptionKey: 'chatcmd.client.shake' },
+3 -1
View File
@@ -65,7 +65,9 @@ const useSoundboardState = () =>
if(!enabled || serverSounds.length || fileLoadStartedRef.current) return;
fileLoadStartedRef.current = true;
const url = GetConfigurationValue<string>('soundboard.sounds.url') || 'configuration/soundboard-sounds.json5';
const url = GetConfigurationValue<string>('soundboard.url')
|| GetConfigurationValue<string>('soundboard.sounds.url')
|| 'configuration/soundboard-sounds.json5';
(async () =>
{