mirror of
https://github.com/duckietm/Nitro-V3.git
synced 2026-06-20 15:36:18 +00:00
catalog: extract pure helpers + 34 cases, consume them from useCatalog
First half of the proposed `useCatalog` decomposition. The 1036-line
god-hook still owns the singleton-via-useBetween, but the pure logic
it used to define inline now lives in a dependency-free module so it
can be tested in isolation and reused by future split-out hooks
(`useCatalogData` / `useCatalogUiState` / `useCatalogActions` when
those land).
New module: `src/hooks/catalog/useCatalog.helpers.ts` (222 LOC).
- `normalizeCatalogType(type?)` — coerce the optional catalog type to
`NORMAL` / `BUILDER`. Was a 5-line `useCallback` with an empty
dependency array.
- `getOfferProductKeys(offer)` — produces the canonical
`productType:id:classId` and `productType:class:className` keys
for the resolved-offer cache.
- `findNodeById` / `findNodeByName` — DFS over the catalog tree,
root explicitly excluded so callers can't select the synthetic
root by mistake.
- `getNodesByOfferIdFromMap(offerId, map, onlyVisible)` — extracted
from the closed-over `getNodesByOfferId`. The `onlyVisible`
fallback to the full bucket when nothing visible remains is
preserved.
- `buildCatalogNodeTree(NodeData)` — pulled out of the
`CatalogPagesListEvent` reducer. Builds the tree and the offerId
index in one pass; the caller now does `const { rootNode,
offersToNodes } = buildCatalogNodeTree(parser.root)` instead of
carrying an inline recursive walker + a local map.
- `resolveBuilderFurniPlaceableStatus(input)` — the placement
decision tree as a pure function. The hook keeps the
`GetRoomEngine` / `GetSessionDataManager` reads that count
non-self, non-moderator visitors (only when the subscription has
expired) and forwards the resulting `visitorCount` into the
helper, so the previous early-exit semantics are preserved.
`useCatalog.ts` now imports these and removes ~140 lines of inline
copies. Net hook size: 1036 → 961 LOC. Behavior unchanged.
Tests: `tests/useCatalog.helpers.test.ts` (34 cases).
- `normalizeCatalogType` (4) — BUILDER pass-through, NORMAL
pass-through, undefined/empty fallback, unknown string fallback.
- `getOfferProductKeys` (5) — both keys, id-only when classId<0,
class-only when className empty, no-product short-circuit,
empty productType short-circuit.
- `findNodeById` (5) — null input, root exclusion, immediate child,
grandchild, miss returns null.
- `findNodeByName` (2) — match by name + root exclusion, miss.
- `getNodesByOfferIdFromMap` (5) — empty map, raw bucket pass-through,
visible-only filter, fallback when no visible remain, miss.
- `buildCatalogNodeTree` (3) — root depth=0 + empty offer map for a
leaf-only root, DFS traversal tracks offer→nodes across branch
and leaf, child.parent === root.
- `resolveBuilderFurniPlaceableStatus` (10) — missing offer,
not-in-room, owner happy path, non-owner without fallback,
guild admin with time, furni limit reached, shared-pool override
ignoring the limit, expired+blocked-by-visitors flag,
expired+visitor count > 0, expired+empty room is okay.
To support the placement-status test the renderer mock gains real
numeric values for `RoomControllerLevel` (NONE..MODERATOR) and
`RoomObjectCategory` (MINIMUM..MAXIMUM); the previous string-keyed
Proxy stubs made `controllerLevel >= GUILD_ADMIN` evaluate to NaN.
Suite: 158/158 (was 124/124). `yarn typecheck` green.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -98,11 +98,9 @@ const makeEnumProxy = (label: string) => new Proxy({}, {
|
||||
export const NitroEventType = makeEnumProxy('NitroEventType');
|
||||
export const MouseEventType = makeEnumProxy('MouseEventType');
|
||||
export const TouchEventType = makeEnumProxy('TouchEventType');
|
||||
export const RoomObjectCategory = makeEnumProxy('RoomObjectCategory');
|
||||
export const RoomObjectPlacementSource = makeEnumProxy('RoomObjectPlacementSource');
|
||||
export const RoomObjectType = makeEnumProxy('RoomObjectType');
|
||||
export const RoomObjectVariable = makeEnumProxy('RoomObjectVariable');
|
||||
export const RoomControllerLevel = makeEnumProxy('RoomControllerLevel');
|
||||
export const RoomTradingLevelEnum = makeEnumProxy('RoomTradingLevelEnum');
|
||||
export const HabboClubLevelEnum = makeEnumProxy('HabboClubLevelEnum');
|
||||
export const FurnitureType = makeEnumProxy('FurnitureType');
|
||||
@@ -113,6 +111,29 @@ export const AvatarSetType = makeEnumProxy('AvatarSetType');
|
||||
export const AvatarAction = makeEnumProxy('AvatarAction');
|
||||
export const RoomWidgetEnumItemExtradataParameter = makeEnumProxy('RoomWidgetEnumItemExtradataParameter');
|
||||
|
||||
// Numeric enums — values mirror the real renderer SDK so comparisons
|
||||
// (`controllerLevel >= GUILD_ADMIN`, category branching) keep working.
|
||||
|
||||
export class RoomControllerLevel
|
||||
{
|
||||
static readonly NONE = 0;
|
||||
static readonly GUEST = 1;
|
||||
static readonly GUILD_MEMBER = 2;
|
||||
static readonly GUILD_ADMIN = 3;
|
||||
static readonly ROOM_OWNER = 4;
|
||||
static readonly MODERATOR = 5;
|
||||
}
|
||||
|
||||
export class RoomObjectCategory
|
||||
{
|
||||
static readonly MINIMUM = 0;
|
||||
static readonly ROOM = 10;
|
||||
static readonly UNIT = 20;
|
||||
static readonly FLOOR = 30;
|
||||
static readonly WALL = 40;
|
||||
static readonly MAXIMUM = 50;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Doorbell event class
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user