diff --git a/src/api/catalog/ICatalogOptions.ts b/src/api/catalog/ICatalogOptions.ts index 4842d97..e50559c 100644 --- a/src/api/catalog/ICatalogOptions.ts +++ b/src/api/catalog/ICatalogOptions.ts @@ -1,9 +1,7 @@ import { ClubGiftInfoParser, MarketplaceConfigurationMessageParser } from '@nitrots/nitro-renderer'; -import { CatalogPetPalette } from './CatalogPetPalette'; export interface ICatalogOptions { - petPalettes?: CatalogPetPalette[]; clubGifts?: ClubGiftInfoParser; marketplaceConfiguration?: MarketplaceConfigurationMessageParser; } diff --git a/src/components/catalog/views/page/layout/pets/CatalogLayoutPetView.tsx b/src/components/catalog/views/page/layout/pets/CatalogLayoutPetView.tsx index 08a9356..589d6bb 100644 --- a/src/components/catalog/views/page/layout/pets/CatalogLayoutPetView.tsx +++ b/src/components/catalog/views/page/layout/pets/CatalogLayoutPetView.tsx @@ -1,10 +1,10 @@ -import { ApproveNameMessageComposer, ApproveNameMessageEvent, ColorConverter, GetSellablePetPalettesComposer, PurchaseFromCatalogComposer, SellablePetPaletteData } from '@nitrots/nitro-renderer'; +import { ApproveNameMessageComposer, ApproveNameMessageEvent, ColorConverter, PurchaseFromCatalogComposer, SellablePetPaletteData } from '@nitrots/nitro-renderer'; import { FC, useCallback, useEffect, useMemo, useState } from 'react'; import { FaCheck, FaEdit, FaFillDrip, FaPaw, FaPlus, FaTimes } from 'react-icons/fa'; import { DispatchUiEvent, GetPetAvailableColors, GetPetIndexFromLocalization, LocalizeText, SanitizeHtml, SendMessageComposer } from '../../../../../../api'; import { LayoutGridItem, LayoutPetImageView } from '../../../../../../common'; import { CatalogPurchaseFailureEvent } from '../../../../../../events'; -import { useCatalog, useMessageEvent } from '../../../../../../hooks'; +import { useCatalog, useMessageEvent, useSellablePetPalette } from '../../../../../../hooks'; import { useCatalogAdmin } from '../../../../CatalogAdminContext'; import { CatalogAddOnBadgeWidgetView } from '../../widgets/CatalogAddOnBadgeWidgetView'; import { CatalogTotalPriceWidget } from '../../widgets/CatalogTotalPriceWidget'; @@ -23,10 +23,11 @@ export const CatalogLayoutPetView: FC = props => const [ petName, setPetName ] = useState(''); const [ approvalPending, setApprovalPending ] = useState(true); const [ approvalResult, setApprovalResult ] = useState(-1); - const { currentOffer = null, setCurrentOffer = null, setPurchaseOptions = null, catalogOptions = null, roomPreviewer = null } = useCatalog(); + const { currentOffer = null, setCurrentOffer = null, setPurchaseOptions = null, roomPreviewer = null } = useCatalog(); const catalogAdmin = useCatalogAdmin(); const adminMode = catalogAdmin?.adminMode ?? false; - const { petPalettes = null } = catalogOptions; + const breed: string = (currentOffer?.product?.productData?.type as unknown as string) ?? ''; + const { data: petPalette = null } = useSellablePetPalette(breed); const getColor = useMemo(() => { @@ -129,39 +130,25 @@ export const CatalogLayoutPetView: FC = props => useEffect(() => { - if(!currentOffer) return; - - const productData = currentOffer.product.productData; - - if(!productData) return; - - if(petPalettes) + if(!currentOffer || !petPalette) { - for(const paletteData of petPalettes) - { - if(paletteData.breed !== productData.type) continue; - - const palettes: SellablePetPaletteData[] = []; - - for(const palette of paletteData.palettes) - { - if(!palette.sellable) continue; - - palettes.push(palette); - } - - setSelectedPaletteIndex((palettes.length ? 0 : -1)); - setSellablePalettes(palettes); - - return; - } + setSelectedPaletteIndex(-1); + setSellablePalettes([]); + return; } - setSelectedPaletteIndex(-1); - setSellablePalettes([]); + const palettes: SellablePetPaletteData[] = []; - SendMessageComposer(new GetSellablePetPalettesComposer(productData.type)); - }, [ currentOffer, petPalettes ]); + for(const palette of petPalette.palettes) + { + if(!palette.sellable) continue; + + palettes.push(palette); + } + + setSelectedPaletteIndex(palettes.length ? 0 : -1); + setSellablePalettes(palettes); + }, [ currentOffer, petPalette ]); useEffect(() => { diff --git a/src/hooks/catalog/index.ts b/src/hooks/catalog/index.ts index 288ef99..2995cd8 100644 --- a/src/hooks/catalog/index.ts +++ b/src/hooks/catalog/index.ts @@ -4,3 +4,4 @@ export * from './useCatalogPlaceMultipleItems'; export * from './useCatalogSkipPurchaseConfirmation'; export * from './useClubOffers'; export * from './useGiftConfiguration'; +export * from './useSellablePetPalette'; diff --git a/src/hooks/catalog/useCatalog.ts b/src/hooks/catalog/useCatalog.ts index a68c36e..b21a39a 100644 --- a/src/hooks/catalog/useCatalog.ts +++ b/src/hooks/catalog/useCatalog.ts @@ -1,7 +1,7 @@ -import { BuildersClubFurniCountMessageEvent, BuildersClubPlaceRoomItemMessageComposer, BuildersClubPlaceWallItemMessageComposer, BuildersClubQueryFurniCountMessageComposer, BuildersClubSubscriptionStatusMessageEvent, CatalogPageMessageEvent, CatalogPagesListEvent, CatalogPublishedMessageEvent, ClubGiftInfoEvent, CreateLinkEvent, FrontPageItem, FurniturePlaceComposer, FurniturePlacePaintComposer, GetCatalogIndexComposer, GetCatalogPageComposer, GetClubGiftInfo, GetRoomEngine, GetSessionDataManager, GetTickerTime, LegacyDataType, LimitedEditionSoldOutEvent, MarketplaceMakeOfferResult, NodeData, ProductOfferEvent, PurchaseErrorMessageEvent, PurchaseFromCatalogComposer, PurchaseNotAllowedMessageEvent, PurchaseOKMessageEvent, RoomControllerLevel, RoomEngineObjectPlacedEvent, RoomObjectCategory, RoomObjectPlacementSource, RoomObjectType, RoomObjectVariable, RoomPreviewer, SellablePetPalettesMessageEvent, Vector3d } from '@nitrots/nitro-renderer'; +import { BuildersClubFurniCountMessageEvent, BuildersClubPlaceRoomItemMessageComposer, BuildersClubPlaceWallItemMessageComposer, BuildersClubQueryFurniCountMessageComposer, BuildersClubSubscriptionStatusMessageEvent, CatalogPageMessageEvent, CatalogPagesListEvent, CatalogPublishedMessageEvent, ClubGiftInfoEvent, CreateLinkEvent, FrontPageItem, FurniturePlaceComposer, FurniturePlacePaintComposer, GetCatalogIndexComposer, GetCatalogPageComposer, GetClubGiftInfo, GetRoomEngine, GetSessionDataManager, GetTickerTime, LegacyDataType, LimitedEditionSoldOutEvent, MarketplaceMakeOfferResult, NodeData, ProductOfferEvent, PurchaseErrorMessageEvent, PurchaseFromCatalogComposer, PurchaseNotAllowedMessageEvent, PurchaseOKMessageEvent, RoomControllerLevel, RoomEngineObjectPlacedEvent, RoomObjectCategory, RoomObjectPlacementSource, RoomObjectType, RoomObjectVariable, RoomPreviewer, Vector3d } from '@nitrots/nitro-renderer'; import { useCallback, useEffect, useRef, useState } from 'react'; import { useBetween } from 'use-between'; -import { BuilderFurniPlaceableStatus, CatalogNode, CatalogPage, CatalogPetPalette, CatalogType, DispatchUiEvent, FurniCategory, GetFurnitureData, GetProductDataForLocalization, GetRoomSession, ICatalogNode, ICatalogOptions, ICatalogPage, IPageLocalization, IProduct, IPurchasableOffer, IPurchaseOptions, LocalizeText, NotificationAlertType, Offer, PageLocalization, PlacedObjectPurchaseData, PlaySound, Product, ProductTypeEnum, RequestedPage, SearchResult, SendMessageComposer, SoundNames } from '../../api'; +import { BuilderFurniPlaceableStatus, CatalogNode, CatalogPage, CatalogType, DispatchUiEvent, FurniCategory, GetFurnitureData, GetProductDataForLocalization, GetRoomSession, ICatalogNode, ICatalogOptions, ICatalogPage, IPageLocalization, IProduct, IPurchasableOffer, IPurchaseOptions, LocalizeText, NotificationAlertType, Offer, PageLocalization, PlacedObjectPurchaseData, PlaySound, Product, ProductTypeEnum, RequestedPage, SearchResult, SendMessageComposer, SoundNames } from '../../api'; import { CatalogPurchaseFailureEvent, CatalogPurchaseNotAllowedEvent, CatalogPurchaseSoldOutEvent, CatalogPurchasedEvent, InventoryFurniAddedEvent } from '../../events'; import { useMessageEvent, useNitroEvent, useUiEvent } from '../events'; import { useNotification } from '../notification'; @@ -710,34 +710,6 @@ const useCatalogState = () => // (this._isObjectMoverRequested) && (this._purchasableOffer) }); - useMessageEvent(SellablePetPalettesMessageEvent, event => - { - const parser = event.getParser(); - const petPalette = new CatalogPetPalette(parser.productCode, parser.palettes.slice()); - - setCatalogOptions(prevValue => - { - const petPalettes = []; - - if(prevValue.petPalettes) petPalettes.push(...prevValue.petPalettes); - - for(let i = 0; i < petPalettes.length; i++) - { - const palette = petPalettes[i]; - - if(palette.breed === petPalette.breed) - { - petPalettes.splice(i, 1); - - break; - } - } - - petPalettes.push(petPalette); - - return { ...prevValue, petPalettes }; - }); - }); diff --git a/src/hooks/catalog/useSellablePetPalette.ts b/src/hooks/catalog/useSellablePetPalette.ts new file mode 100644 index 0000000..700cffc --- /dev/null +++ b/src/hooks/catalog/useSellablePetPalette.ts @@ -0,0 +1,32 @@ +import { GetSellablePetPalettesComposer, SellablePetPalettesMessageEvent } from '@nitrots/nitro-renderer'; +import { UseQueryResult } from '@tanstack/react-query'; +import { CatalogPetPalette } from '../../api'; +import { useNitroQuery } from '../../api/nitro-query'; + +/** + * Sellable palettes for a given pet breed, as returned by + * GetSellablePetPalettesComposer(breed) → SellablePetPalettesMessageEvent. + * The renderer multiplexes one event type for every breed; accept() + * keeps each query slot listening only for the matching productCode. + * + * Replaces the per-breed accumulator that previously lived in + * useCatalog (writing to catalogOptions.petPalettes). The catalog pet + * page now reads via `useSellablePetPalette(productData.type)`. + * + * The breed identifier is the localization product code string + * (e.g. 'pet_egg', 'pet_dog', ...). Disabled while breed is empty so + * we don't spam composers at mount before the offer is known. + */ +export const useSellablePetPalette = ( + breed: string, + options: { enabled?: boolean } = {} +): UseQueryResult => + useNitroQuery({ + key: [ 'nitro', 'catalog', 'petPalette', breed ], + request: () => new GetSellablePetPalettesComposer(breed), + parser: SellablePetPalettesMessageEvent, + accept: event => (event.getParser().productCode === breed), + select: event => new CatalogPetPalette(event.getParser().productCode, event.getParser().palettes.slice()), + enabled: (options.enabled ?? true) && !!breed, + staleTime: Infinity + });