Commit Graph

33 Commits

Author SHA1 Message Date
medievalshell 8e95ca9570 style(catalog): logo info torna a contain (immagine intera con bordi) 2026-05-30 03:22:48 +02:00
medievalshell a034517143 style(catalog): logo info edge-to-edge (object-cover) 2026-05-30 03:17:32 +02:00
medievalshell 624a310c59 style(catalog): logo info massimizzato senza crop, testo box piu piccolo 2026-05-30 03:14:36 +02:00
medievalshell 9f737c5129 style(catalog): logo info a tutta larghezza (no crop, no margini) 2026-05-30 03:08:44 +02:00
medievalshell 552cd1f538 fix(catalog): layout info BC nasconde la navigazione vuota a sinistra 2026-05-30 02:43:07 +02:00
medievalshell 6db8d3e191 feat(catalog): layout info BC (logo 70% + box testo nero) via info_duckets 2026-05-30 02:34:25 +02:00
medievalshell 4f133abe33 feat(catalog): default upstream, toggle classico = Hippiehotel
Default catalog = rebuild upstream ultima release (CatalogClassicView).
Il toggle 'stile classico' mostra il catalogo Hippiehotel (CatalogModernView).
2026-05-29 23:55:36 +02:00
medievalshell 2b8aca23b6 revert(catalog): ripristina catalogo Hippiehotel.nl (Modern+Classic)
Rimpiazza il catalogo del rebuild upstream con quello originale di
Hippiehotel.nl Nitro-V3 (CatalogModernView ripristinato, ClassicView/
sub-views/CSS pre-merge). CatalogView sceglie Modern (default) o Classic
via il toggle 'stile classico'. Rimosso l'hack CatalogClassicLegacy.css.
2026-05-29 23:49:10 +02:00
duckietm 888073acb1 🆙 Update #2 2026-05-29 15:16:14 +02:00
duckietm d0c11f047a 🆙 Complete rebuild of toolbar / catalog / inventory make it 100% mobile friendly Take #1 2026-05-29 11:30:17 +02:00
simoleo89 1d580e6d24 refactor(navigator): migrate all 13 consumers off useNavigator god-hook
Mechanical swap to the new filter hooks landed in the previous commits:
- NavigatorDoorStateView -> useDoorState (snapshot/setSnapshot/reset)
- NavigatorView -> useNavigatorData + useNavigatorUiState +
  useNavigatorActions + direct useNavigatorUiStore.getState() in handlers
  (linkTracker collapsed to a dispatch table; 9 useState gone)
- NavigatorSearchView -> useNavigatorData + useNavigatorActions
  (sendSearch prop drilling removed)
- NavigatorSearchResultItemView -> useDoorState (setSnapshot aliased as
  setDoorData; call sites unchanged - DoorStateSnapshot is compatible)
- 9 bulk consumers (one-line import swap) -> useNavigatorData

Zero behavioural change intended. yarn typecheck + yarn test --run +
yarn lint:hooks all clean on this commit.
2026-05-27 18:58:03 +02:00
duckietm b1244cbd5a 🆙 Fix BOTS in catalog and inventory 2026-05-27 13:42:11 +02:00
DuckieTM cef27d5646 Merge branch 'Dev' into merge-duckie-main-2026-05-06 2026-05-25 18:51:48 +02:00
Lorenzune b038ca4542 Add emulator stats dashboard and refresh classic UI views 2026-05-25 10:10:40 +02:00
duckietm 5002b2fcdc 🆙 Fix Catalog Edit 2026-05-21 16:58:47 +02:00
duckietm 49917ed49b 🆕 Redesign of HC Club buy, now also give as gift 2026-05-21 14:00:03 +02:00
simoleo89 0f9fa1203b catalog: migrate remaining 36 useCatalog() consumers to the three filters
Replaces every direct call to the deprecated useCatalog() shim with the
targeted filter(s) (useCatalogData / useCatalogUiState / useCatalogActions).
Each consumer now subscribes only to the slice it actually reads, which
restores React Compiler memoization and stops catalog-wide re-renders
whenever an unrelated key changes.

Removes the now-unused useCatalog shim from useCatalog.ts and the
shim-specific case in tests/useCatalog.filters.test.tsx. The "all four
hooks observe the same singleton" test becomes "all three filters", since
there is no shim left to compare against. useCatalogFavorites swaps its
internal useCatalog() call for useCatalogUiState() (currentType lives in
the UI slice).

Updates CLAUDE.md and docs/ARCHITECTURE.md to reflect that all 48
historical consumers are migrated and the shim is gone.

Vitest: 162/162 (was 163 — minus the deprecated-shim contract case).
2026-05-14 20:05:44 +02:00
simoleo89 7b062299de useClubGifts + useNitroEventInvalidator: close the catalogOptions bag
This commit drains the last field out of ICatalogOptions (clubGifts)
and deletes the interface — useCatalog no longer owns a catch-all
mutable object that downstream components stuff data into.

Two pieces:

1) New useNitroEventInvalidator(eventType, queryKey, accept?) — a
   small companion to useNitroQuery for the case where the server
   pushes the same event unprompted (e.g. ClubGiftInfoEvent fires
   both as the response to GetClubGiftInfo and again after the user
   claims a gift via SelectClubGiftComposer). It calls
   queryClient.invalidateQueries() on each matching push so the
   next render of any subscriber triggers a fresh queryFn.

2) New useClubGifts() — useNitroQuery on the ClubGiftInfoEvent
   pair, paired with useNitroEventInvalidator so server-driven
   pushes refresh the cache automatically. CatalogLayoutVipGiftsView
   now consumes the query directly. The local optimistic
   'giftsAvailable--' mutation (which side-effected the parser
   object passed back to the catalog state!) is dropped — the
   server's authoritative ClubGiftInfoEvent push is the single
   source of truth via the invalidator.

useCatalog drops the matching listener + the GetClubGiftInfo dispatch
from the catalog-open effect. ICatalogOptions is now empty and
deleted; the catalogOptions / setCatalogOptions state + return-shape
field are removed from useCatalog along with the import.
2026-05-11 22:38:32 +02:00
simoleo89 9a807bf335 useMarketplaceConfiguration: lift the marketplace config self-fetch
MarketplacePostOfferView was both *the* fetcher and the listener for
MarketplaceConfigurationEvent — it dispatched
GetMarketplaceConfigurationMessageComposer from one effect when item
was set, then routed the response through setCatalogOptions.

useCatalog never touched the field; it was passing through catalogOptions
purely as a transport mechanism for this single component to talk to
itself. Replace with useMarketplaceConfiguration() — staleTime Infinity
(server-side constants for a session), enabled on item, single tidy
data path.

Drops marketplaceConfiguration from ICatalogOptions; with petPalettes
out too, ICatalogOptions is now just { clubGifts }. clubGifts is the
last one and needs invalidation (server pushes ClubGiftInfoEvent after
SelectClubGiftComposer) so it stays put until useNitroEventInvalidator
companion lands.
2026-05-11 22:32:35 +02:00
simoleo89 3947781495 useSellablePetPalette(breed): per-breed TanStack query for pet picker
CatalogLayoutPetView previously read 'catalogOptions.petPalettes' (an
accumulating array of CatalogPetPalette objects keyed by breed) and,
on cache miss, dispatched GetSellablePetPalettesComposer(productData.type)
inline. useCatalog kept the matching SellablePetPalettesMessageEvent
listener that appended each new breed to the array (deduping by breed
identity).

Migrate the request/response pair to a TanStack query parameterized on
breed:

  useSellablePetPalette(breed)
    key:     ['nitro', 'catalog', 'petPalette', breed]
    request: () => new GetSellablePetPalettesComposer(breed)
    parser:  SellablePetPalettesMessageEvent
    accept:  event.getParser().productCode === breed
    select:  build a CatalogPetPalette from parser
    enabled: !!breed (avoid spamming composers before currentOffer is set)
    staleTime: Infinity

The view now derives breed from currentOffer.product.productData.type
and reads 'const { data: petPalette }'. The cache-miss-then-fetch
two-pass effect collapses into a single effect that runs once
petPalette resolves (or clears state when offer/petPalette aren't
ready).

Drops the matching listener from useCatalog, drops petPalettes from
ICatalogOptions, and removes the now-unused CatalogPetPalette /
SellablePetPalettesMessageEvent imports from useCatalog.
2026-05-11 22:28:55 +02:00
simoleo89 2a5b9a4a98 useClubOffers: per-windowId TanStack query for HC offer pages
Two catalog layouts each fire 'new GetClubOffersMessageComposer(windowId)'
on mount and read parser.offers via HabboClubOffersMessageEvent:

  - CatalogLayoutVipBuyView (windowId 1)
  - CatalogLayoutBuildersClubBuyView (windowId 2 / 3, depending on
    the addon variant)

Plus useCatalog used to also listen for HabboClubOffersMessageEvent and
stash the offers in 'catalogOptions.clubOffersByWindowId[windowId]' and
'catalogOptions.clubOffers' (the latter being a backward-compat alias
for windowId 1). Three listeners, three independent requests when all
mounted.

New useClubOffers(windowId) wraps the request/response pair as a
TanStack query keyed by '['nitro', 'catalog', 'clubOffers', windowId]'.
accept(): correlation-key filter (parser.windowId === windowId) so
the same multiplexed event doesn't satisfy the wrong query slot.

Both layouts now read 'const { data: offers = null } = useClubOffers(windowId)';
useCatalog drops the listener, ICatalogOptions drops the
clubOffers / clubOffersByWindowId fields and HabboClubOffersMessageEvent
no longer needs to be imported in useCatalog. The localization-refresh
effect that re-cloned both fields is also dropped — React Query owns
the cache now, and ClubOfferData has no localized strings anyway.
2026-05-11 22:23:19 +02:00
simoleo89 2d9785e931 useUserGroups: consolidate 4 dedup'd CatalogGroupsComposer call sites
Four independent components used to send 'new CatalogGroupsComposer()'
on mount and listen for GuildMembershipsMessageEvent:

  - useCatalog (writing into catalogOptions.groups)
  - CatalogLayoutGuildForumView
  - CatalogGuildSelectorWidgetView
  - WiredSelectorUsersGroupView
  - WiredConditionActorIsGroupMemberView

Each fired its own request and re-listened independently. With four
of them mounted in the wired-tools panel during a builder session,
the same packet went out four times.

New useUserGroups() hook wraps the request/response pair with
useNitroQuery (queryKey ['nitro', 'user', 'groups'], staleTime
Infinity — guild membership is session-stable). All four consumers
now read 'const { data: groups = [] } = useUserGroups()' and React
Query dedups: one composer at the first mount, all subsequent mounts
get the cached array.

Drops 'groups' from ICatalogOptions and the corresponding listener +
prev-state-merge from useCatalog — no remaining consumer reads it.
2026-05-11 22:14:39 +02:00
simoleo89 388fb8ed34 Migrate CatalogLayoutRoomAdsView's room-ad fetch to useNitroQuery
Second concrete adoption of proposal #2 (first was OfferView).

Before
- A useState<RoomEntryData[]>([]) for availableRooms.
- A useMessageEvent<RoomAdPurchaseInfoEvent> handler that
  set the state on each parser event.
- A useEffect on mount that dispatched two composers, one of which
  was GetRoomAdPurchaseInfoComposer paired with the parser above.

After
- A single useNitroQuery call wires the request and parser as one
  read-only query. The select extracts parser.rooms with a default
  empty array.
- staleTime is 60s — opening the same panel within a minute reuses
  the cached value; the composer is not re-dispatched. Useful here
  because the user navigates between catalog tabs.
- The mount-only useEffect no longer dispatches the room-ad composer;
  the second composer (GetUserEventCatsMessageComposer) stays where
  it was — that one feeds useNavigator state and isn't a
  request-response pair this component owns.

Why this file
- It was the cleanest pattern in the catalog tree: no correlation
  keys, no conditional filter on the parser, no other writes to
  availableRooms. The pure derive-from-event case useNitroQuery is
  built for.
- The big god-hook useCatalog (1100 LOC) still owns most of the
  catalog data layer; migrating that needs the data/uiState/actions
  split first.

Verification
- yarn test: 49/49 still passing.
- yarn eslint on the touched file: 1 error (the pre-existing
  set-state-in-effect on line 36, unchanged — baseline matches).
- The previous useMessageEvent import was removed cleanly.
2026-05-11 16:40:43 +00:00
simoleo89 535fa71020 ESLint --fix: auto-fix brace-style, indent, semi, no-trailing-spaces
Run eslint --fix across src/ to clear ~1900 mechanical lint errors
surfaced by the @typescript-eslint v8 + react-hooks v7 + react-compiler
upgrade in the React 19 modernization PR.

Issues fixed automatically:
- brace-style (Allman): try/catch one-liners reformatted to multi-line
- indent: tab-vs-space and depth corrections
- semi: missing trailing semicolons
- no-trailing-spaces

No semantic changes. Remaining 701 errors are real-code issues
(set-state-in-effect, rules-of-hooks, no-unsafe-* type checks) that
need manual per-file review.

https://claude.ai/code/session_01GrR87LAqnAEyKG2ZbmQt5Q
2026-05-11 16:31:50 +00:00
Lorenzune 954e477e47 feat: add builders club catalog ui flow 2026-04-07 14:40:51 +02:00
DuckieTM 7ffb213ce7 ㊙️ Security Fixes
- XSS fix: Created SanitizeHtml.ts utility using DOMPurify (already in package.json but never used). Wrapped all 21 dangerouslySetInnerHTML calls in catalog views with SanitizeHtml() — only allows safe tags (b, i, u, br, span, div, p, a, strong, em, img)

- Race condition fix: Added 10-second timeout fallbacks on purchase flags in CatalogPurchaseWidgetView and CatalogGiftView so the flag auto-resets even if the server never responds
2026-03-23 22:14:03 +01:00
duckietm 33c31fe07d 🆕 Added New catalogue page 2026-03-23 15:02:20 +01:00
duckietm a0d0b5c4a4 Revert "Merge branch 'main' into furnisettingeditor-pr"
This reverts commit dfbfb1c2c1, reversing
changes made to 07702c44d0.
2026-03-23 11:49:05 +01:00
simoleo89 74dce1d55d feat(catalog): complete UI redesign with admin mode & favorites
- Modern card-based layout with vertical icon rail, breadcrumb nav, inline search
- Admin mode: edit/create/delete pages and offers, drag & drop reorder via HK API
- Favorites system: heart on furni, star on pages, localStorage persistence
- Redesigned product card with price pills, dynamic quantity spinner
- Upgraded trophies (filter tabs, parchment textarea), pets (breed/color flow),
  custom prefix (dynamic color boxes)
- Font fix: Ubuntu Regular, proper @font-face declarations
- New Tailwind design tokens and CatalogTexts.json for localization
2026-03-21 16:49:35 +01:00
simoleo89 11543bb64c feat: custom prefix system with effects, emoji picker and per-letter colors
- Catalog page for creating custom prefixes with text, per-letter colors, emoji icon and visual effects
- Emoji picker via @emoji-mart/react with createPortal + Shadow DOM blur fix
- Inventory prefix management (activate/deactivate/delete)
- Chat bubble rendering with multi-color prefix and effect support
- Prefix utilities (getPrefixEffectStyle, parsePrefixColors, PREFIX_EFFECT_KEYFRAMES)
- All UI text in English
2026-03-20 17:07:33 +01:00
duckietm bffaccf6a3 🆙 Security Fix - Will not go into details 2026-03-18 16:52:32 +01:00
duckietm f2446d232b 🆙 Upgrade to tailwind css 4.2.0 2026-02-20 08:17:17 +01:00
DuckieTM 7feb10ab15 🆙 Init V3 2026-01-31 09:10:52 +01:00