From 560a520e75d1789951ab5f49523dd822b5197d16 Mon Sep 17 00:00:00 2001 From: Bill Date: Wed, 20 Apr 2022 11:43:44 -0400 Subject: [PATCH] Update catalog state --- .../catalog/BuilderFurniPlaceableStatus.ts | 10 + .../common => api/catalog}/CatalogNode.ts | 0 .../common => api/catalog}/CatalogPage.ts | 0 .../common => api/catalog}/CatalogPageName.ts | 0 .../catalog}/CatalogPetPalette.ts | 0 .../catalog}/CatalogPurchaseState.ts | 0 .../common => api/catalog}/CatalogType.ts | 0 .../catalog}/CatalogUtilities.ts | 2 +- .../common => api/catalog}/FurnitureOffer.ts | 2 +- .../catalog}/GiftWrappingConfiguration.ts | 0 .../common => api/catalog}/ICatalogNode.ts | 0 .../common => api/catalog}/ICatalogOptions.ts | 0 .../common => api/catalog}/ICatalogPage.ts | 0 .../catalog}/IPageLocalization.ts | 0 .../common => api/catalog}/IProduct.ts | 0 .../catalog}/IPurchasableOffer.ts | 0 .../catalog}/IPurchaseOptions.ts | 0 .../catalog/common => api/catalog}/Offer.ts | 2 +- .../catalog}/PageLocalization.ts | 2 +- src/api/catalog/PlacedObjectPurchaseData.ts | 41 ++ .../catalog/common => api/catalog}/Product.ts | 3 +- .../common => api/catalog}/RequestedPage.ts | 0 .../common => api/catalog}/SearchResult.ts | 0 src/api/catalog/index.ts | 23 + src/api/inventory/FurnitureItem.ts | 12 +- src/api/inventory/IFurnitureItem.ts | 2 +- src/api/utils/LocalStorageKeys.ts | 5 + src/api/utils/index.ts | 1 + src/components/catalog/CatalogContext.tsx | 83 --- .../catalog/CatalogMessageHandler.tsx | 291 --------- src/components/catalog/CatalogView.tsx | 433 ++----------- .../catalog/common/AttemptCatalogPlacement.ts | 29 - .../catalog/common/FurniCategory.ts | 26 - src/components/catalog/common/IPurse.ts | 14 - .../catalog/common/IsCatalogOfferDraggable.ts | 7 - src/components/catalog/common/Purse.ts | 144 ----- .../catalog/common/SubscriptionInfo.ts | 18 - .../views/CatalogPurchaseConfirmView.tsx | 10 + .../catalog/views/gift/CatalogGiftView.tsx | 5 +- .../navigation/CatalogNavigationItemView.tsx | 9 +- .../navigation/CatalogNavigationSetView.tsx | 2 +- .../navigation/CatalogNavigationView.tsx | 9 +- .../page/common/CatalogGridOfferView.tsx | 34 +- .../views/page/common/CatalogSearchView.tsx | 18 +- .../views/page/layout/CatalogLayout.types.ts | 2 +- .../layout/CatalogLayoutBadgeDisplayView.tsx | 4 +- .../page/layout/CatalogLayoutDefaultView.tsx | 4 +- .../CatalogLayoutGuildCustomFurniView.tsx | 10 +- .../layout/CatalogLayoutGuildForumView.tsx | 4 +- .../page/layout/CatalogLayoutSpacesView.tsx | 10 +- .../page/layout/CatalogLayoutTrophiesView.tsx | 9 +- .../page/layout/CatalogLayoutVipBuyView.tsx | 8 +- .../views/page/layout/GetCatalogLayout.tsx | 2 +- .../CatalogLayoutFrontpage4View.tsx | 7 +- .../marketplace/MarketplacePostOfferView.tsx | 5 +- .../pets/CatalogLayoutPetPurchaseView.tsx | 4 +- .../page/layout/pets/CatalogLayoutPetView.tsx | 8 +- .../vip-gifts/CatalogLayoutVipGiftsView.tsx | 5 +- .../widgets/CatalogAddOnBadgeWidgetView.tsx | 4 +- .../CatalogBadgeSelectorWidgetView.tsx | 5 +- .../widgets/CatalogBundleGridWidgetView.tsx | 7 +- .../CatalogFirstProductSelectorWidgetView.tsx | 4 +- .../widgets/CatalogGuildBadgeWidgetView.tsx | 4 +- .../CatalogGuildSelectorWidgetView.tsx | 4 +- .../widgets/CatalogItemGridWidgetView.tsx | 9 +- .../widgets/CatalogLimitedItemWidgetView.tsx | 6 +- .../widgets/CatalogPriceDisplayWidgetView.tsx | 6 +- .../widgets/CatalogPurchaseWidgetView.tsx | 22 +- .../widgets/CatalogSimplePriceWidgetView.tsx | 6 +- .../page/widgets/CatalogSpacesWidgetView.tsx | 39 +- .../page/widgets/CatalogSpinnerWidgetView.tsx | 7 +- .../page/widgets/CatalogTotalPriceWidget.tsx | 6 +- .../widgets/CatalogViewProductWidgetView.tsx | 8 +- .../groups/views/GroupInformationView.tsx | 3 +- .../user-settings/UserSettingsView.tsx | 12 +- .../catalog/CatalogInitPurchaseEvent.ts | 26 - src/events/catalog/CatalogWidgetEvent.ts | 1 - .../catalog/SetRoomPreviewerStuffDataEvent.ts | 2 +- src/events/catalog/index.ts | 1 - src/events/index.ts | 1 + .../inventory/InventoryFurniAddedEvent.ts | 14 + src/events/inventory/index.ts | 1 + src/hooks/catalog/index.ts | 5 + src/hooks/catalog/useCatalog.ts | 611 ++++++++++++++++++ src/hooks/catalog/useCatalogBuildersClub.ts | 54 ++ src/hooks/catalog/useCatalogItemMover.ts | 321 +++++++++ .../catalog/useCatalogPlaceMultipleItems.ts | 7 + .../useCatalogSkipPurchaseConfirmation.ts | 7 + src/hooks/index.ts | 2 + src/hooks/inventory/useInventoryFurni.ts | 6 + src/hooks/useLocalStorage.ts | 43 ++ 91 files changed, 1371 insertions(+), 1202 deletions(-) create mode 100644 src/api/catalog/BuilderFurniPlaceableStatus.ts rename src/{components/catalog/common => api/catalog}/CatalogNode.ts (100%) rename src/{components/catalog/common => api/catalog}/CatalogPage.ts (100%) rename src/{components/catalog/common => api/catalog}/CatalogPageName.ts (100%) rename src/{components/catalog/common => api/catalog}/CatalogPetPalette.ts (100%) rename src/{components/catalog/common => api/catalog}/CatalogPurchaseState.ts (100%) rename src/{components/catalog/common => api/catalog}/CatalogType.ts (100%) rename src/{components/catalog/common => api/catalog}/CatalogUtilities.ts (99%) rename src/{components/catalog/common => api/catalog}/FurnitureOffer.ts (99%) rename src/{components/catalog/common => api/catalog}/GiftWrappingConfiguration.ts (100%) rename src/{components/catalog/common => api/catalog}/ICatalogNode.ts (100%) rename src/{components/catalog/common => api/catalog}/ICatalogOptions.ts (100%) rename src/{components/catalog/common => api/catalog}/ICatalogPage.ts (100%) rename src/{components/catalog/common => api/catalog}/IPageLocalization.ts (100%) rename src/{components/catalog/common => api/catalog}/IProduct.ts (100%) rename src/{components/catalog/common => api/catalog}/IPurchasableOffer.ts (100%) rename src/{components/catalog/common => api/catalog}/IPurchaseOptions.ts (100%) rename src/{components/catalog/common => api/catalog}/Offer.ts (99%) rename src/{components/catalog/common => api/catalog}/PageLocalization.ts (94%) create mode 100644 src/api/catalog/PlacedObjectPurchaseData.ts rename src/{components/catalog/common => api/catalog}/Product.ts (97%) rename src/{components/catalog/common => api/catalog}/RequestedPage.ts (100%) rename src/{components/catalog/common => api/catalog}/SearchResult.ts (100%) create mode 100644 src/api/utils/LocalStorageKeys.ts delete mode 100644 src/components/catalog/CatalogContext.tsx delete mode 100644 src/components/catalog/CatalogMessageHandler.tsx delete mode 100644 src/components/catalog/common/AttemptCatalogPlacement.ts delete mode 100644 src/components/catalog/common/FurniCategory.ts delete mode 100644 src/components/catalog/common/IPurse.ts delete mode 100644 src/components/catalog/common/IsCatalogOfferDraggable.ts delete mode 100644 src/components/catalog/common/Purse.ts delete mode 100644 src/components/catalog/common/SubscriptionInfo.ts create mode 100644 src/components/catalog/views/CatalogPurchaseConfirmView.tsx delete mode 100644 src/events/catalog/CatalogInitPurchaseEvent.ts create mode 100644 src/events/inventory/InventoryFurniAddedEvent.ts create mode 100644 src/events/inventory/index.ts create mode 100644 src/hooks/catalog/index.ts create mode 100644 src/hooks/catalog/useCatalog.ts create mode 100644 src/hooks/catalog/useCatalogBuildersClub.ts create mode 100644 src/hooks/catalog/useCatalogItemMover.ts create mode 100644 src/hooks/catalog/useCatalogPlaceMultipleItems.ts create mode 100644 src/hooks/catalog/useCatalogSkipPurchaseConfirmation.ts create mode 100644 src/hooks/useLocalStorage.ts diff --git a/src/api/catalog/BuilderFurniPlaceableStatus.ts b/src/api/catalog/BuilderFurniPlaceableStatus.ts new file mode 100644 index 00000000..40eb6f65 --- /dev/null +++ b/src/api/catalog/BuilderFurniPlaceableStatus.ts @@ -0,0 +1,10 @@ +export class BuilderFurniPlaceableStatus +{ + public static OKAY: number = 0; + public static MISSING_OFFER: number = 1; + public static FURNI_LIMIT_REACHED: number = 2; + public static NOT_IN_ROOM: number = 3; + public static NOT_ROOM_OWNER: number = 4; + public static GUILD_ROOM: number = 5; + public static VISITORS_IN_ROOM: number = 6; +} diff --git a/src/components/catalog/common/CatalogNode.ts b/src/api/catalog/CatalogNode.ts similarity index 100% rename from src/components/catalog/common/CatalogNode.ts rename to src/api/catalog/CatalogNode.ts diff --git a/src/components/catalog/common/CatalogPage.ts b/src/api/catalog/CatalogPage.ts similarity index 100% rename from src/components/catalog/common/CatalogPage.ts rename to src/api/catalog/CatalogPage.ts diff --git a/src/components/catalog/common/CatalogPageName.ts b/src/api/catalog/CatalogPageName.ts similarity index 100% rename from src/components/catalog/common/CatalogPageName.ts rename to src/api/catalog/CatalogPageName.ts diff --git a/src/components/catalog/common/CatalogPetPalette.ts b/src/api/catalog/CatalogPetPalette.ts similarity index 100% rename from src/components/catalog/common/CatalogPetPalette.ts rename to src/api/catalog/CatalogPetPalette.ts diff --git a/src/components/catalog/common/CatalogPurchaseState.ts b/src/api/catalog/CatalogPurchaseState.ts similarity index 100% rename from src/components/catalog/common/CatalogPurchaseState.ts rename to src/api/catalog/CatalogPurchaseState.ts diff --git a/src/components/catalog/common/CatalogType.ts b/src/api/catalog/CatalogType.ts similarity index 100% rename from src/components/catalog/common/CatalogType.ts rename to src/api/catalog/CatalogType.ts diff --git a/src/components/catalog/common/CatalogUtilities.ts b/src/api/catalog/CatalogUtilities.ts similarity index 99% rename from src/components/catalog/common/CatalogUtilities.ts rename to src/api/catalog/CatalogUtilities.ts index 54319610..5ca8fed5 100644 --- a/src/components/catalog/common/CatalogUtilities.ts +++ b/src/api/catalog/CatalogUtilities.ts @@ -1,5 +1,5 @@ import { SellablePetPaletteData } from '@nitrots/nitro-renderer'; -import { GetRoomEngine } from '../../../api'; +import { GetRoomEngine } from '../nitro'; import { ICatalogNode } from './ICatalogNode'; export const GetPixelEffectIcon = (id: number) => diff --git a/src/components/catalog/common/FurnitureOffer.ts b/src/api/catalog/FurnitureOffer.ts similarity index 99% rename from src/components/catalog/common/FurnitureOffer.ts rename to src/api/catalog/FurnitureOffer.ts index b25c376f..4c9c9f94 100644 --- a/src/components/catalog/common/FurnitureOffer.ts +++ b/src/api/catalog/FurnitureOffer.ts @@ -1,5 +1,5 @@ import { GetProductOfferComposer, IFurnitureData } from '@nitrots/nitro-renderer'; -import { GetProductDataForLocalization, SendMessageComposer } from '../../../api'; +import { GetProductDataForLocalization, SendMessageComposer } from '..'; import { ICatalogPage } from './ICatalogPage'; import { IProduct } from './IProduct'; import { IPurchasableOffer } from './IPurchasableOffer'; diff --git a/src/components/catalog/common/GiftWrappingConfiguration.ts b/src/api/catalog/GiftWrappingConfiguration.ts similarity index 100% rename from src/components/catalog/common/GiftWrappingConfiguration.ts rename to src/api/catalog/GiftWrappingConfiguration.ts diff --git a/src/components/catalog/common/ICatalogNode.ts b/src/api/catalog/ICatalogNode.ts similarity index 100% rename from src/components/catalog/common/ICatalogNode.ts rename to src/api/catalog/ICatalogNode.ts diff --git a/src/components/catalog/common/ICatalogOptions.ts b/src/api/catalog/ICatalogOptions.ts similarity index 100% rename from src/components/catalog/common/ICatalogOptions.ts rename to src/api/catalog/ICatalogOptions.ts diff --git a/src/components/catalog/common/ICatalogPage.ts b/src/api/catalog/ICatalogPage.ts similarity index 100% rename from src/components/catalog/common/ICatalogPage.ts rename to src/api/catalog/ICatalogPage.ts diff --git a/src/components/catalog/common/IPageLocalization.ts b/src/api/catalog/IPageLocalization.ts similarity index 100% rename from src/components/catalog/common/IPageLocalization.ts rename to src/api/catalog/IPageLocalization.ts diff --git a/src/components/catalog/common/IProduct.ts b/src/api/catalog/IProduct.ts similarity index 100% rename from src/components/catalog/common/IProduct.ts rename to src/api/catalog/IProduct.ts diff --git a/src/components/catalog/common/IPurchasableOffer.ts b/src/api/catalog/IPurchasableOffer.ts similarity index 100% rename from src/components/catalog/common/IPurchasableOffer.ts rename to src/api/catalog/IPurchasableOffer.ts diff --git a/src/components/catalog/common/IPurchaseOptions.ts b/src/api/catalog/IPurchaseOptions.ts similarity index 100% rename from src/components/catalog/common/IPurchaseOptions.ts rename to src/api/catalog/IPurchaseOptions.ts diff --git a/src/components/catalog/common/Offer.ts b/src/api/catalog/Offer.ts similarity index 99% rename from src/components/catalog/common/Offer.ts rename to src/api/catalog/Offer.ts index 4b6f4f4e..c14d6ac1 100644 --- a/src/components/catalog/common/Offer.ts +++ b/src/api/catalog/Offer.ts @@ -1,4 +1,4 @@ -import { GetFurnitureData, GetProductDataForLocalization, LocalizeText, ProductTypeEnum } from '../../../api'; +import { GetFurnitureData, GetProductDataForLocalization, LocalizeText, ProductTypeEnum } from '..'; import { ICatalogPage } from './ICatalogPage'; import { IProduct } from './IProduct'; import { IPurchasableOffer } from './IPurchasableOffer'; diff --git a/src/components/catalog/common/PageLocalization.ts b/src/api/catalog/PageLocalization.ts similarity index 94% rename from src/components/catalog/common/PageLocalization.ts rename to src/api/catalog/PageLocalization.ts index 6a51830d..91e3ce6f 100644 --- a/src/components/catalog/common/PageLocalization.ts +++ b/src/api/catalog/PageLocalization.ts @@ -1,4 +1,4 @@ -import { GetConfiguration } from '../../../api'; +import { GetConfiguration } from '../nitro'; import { IPageLocalization } from './IPageLocalization'; export class PageLocalization implements IPageLocalization diff --git a/src/api/catalog/PlacedObjectPurchaseData.ts b/src/api/catalog/PlacedObjectPurchaseData.ts new file mode 100644 index 00000000..84bad8cd --- /dev/null +++ b/src/api/catalog/PlacedObjectPurchaseData.ts @@ -0,0 +1,41 @@ +import { IFurnitureData, IProductData } from '@nitrots/nitro-renderer'; +import { IPurchasableOffer } from './IPurchasableOffer'; + +export class PlacedObjectPurchaseData +{ + constructor( + public readonly roomId: number, + public readonly objectId: number, + public readonly category: number, + public readonly wallLocation: string, + public readonly x: number, + public readonly y: number, + public readonly direction: number, + public readonly offer: IPurchasableOffer) + {} + + public get offerId(): number + { + return this.offer.offerId; + } + + public get productClassId(): number + { + return this.offer.product.productClassId; + } + + public get productData(): IProductData + { + return this.offer.product.productData; + } + + public get furniData(): IFurnitureData + { + return this.offer.product.furnitureData; + } + + public get extraParam(): string + { + return this.offer.product.extraParam; + } +} diff --git a/src/components/catalog/common/Product.ts b/src/api/catalog/Product.ts similarity index 97% rename from src/components/catalog/common/Product.ts rename to src/api/catalog/Product.ts index 52c7136c..bfb760fc 100644 --- a/src/components/catalog/common/Product.ts +++ b/src/api/catalog/Product.ts @@ -1,8 +1,9 @@ import { IFurnitureData, IObjectData, IProductData } from '@nitrots/nitro-renderer'; -import { GetConfiguration, GetRoomEngine, GetSessionDataManager, ProductTypeEnum } from '../../../api'; +import { GetConfiguration, GetRoomEngine, GetSessionDataManager } from '../nitro'; import { GetPixelEffectIcon, GetSubscriptionProductIcon } from './CatalogUtilities'; import { IProduct } from './IProduct'; import { IPurchasableOffer } from './IPurchasableOffer'; +import { ProductTypeEnum } from './ProductTypeEnum'; export class Product implements IProduct { diff --git a/src/components/catalog/common/RequestedPage.ts b/src/api/catalog/RequestedPage.ts similarity index 100% rename from src/components/catalog/common/RequestedPage.ts rename to src/api/catalog/RequestedPage.ts diff --git a/src/components/catalog/common/SearchResult.ts b/src/api/catalog/SearchResult.ts similarity index 100% rename from src/components/catalog/common/SearchResult.ts rename to src/api/catalog/SearchResult.ts diff --git a/src/api/catalog/index.ts b/src/api/catalog/index.ts index 9b5a552f..ba084bc8 100644 --- a/src/api/catalog/index.ts +++ b/src/api/catalog/index.ts @@ -1 +1,24 @@ +export * from './BuilderFurniPlaceableStatus'; +export * from './CatalogNode'; +export * from './CatalogPage'; +export * from './CatalogPageName'; +export * from './CatalogPetPalette'; +export * from './CatalogPurchaseState'; +export * from './CatalogType'; +export * from './CatalogUtilities'; +export * from './FurnitureOffer'; +export * from './GiftWrappingConfiguration'; +export * from './ICatalogNode'; +export * from './ICatalogOptions'; +export * from './ICatalogPage'; +export * from './IPageLocalization'; +export * from './IProduct'; +export * from './IPurchasableOffer'; +export * from './IPurchaseOptions'; +export * from './Offer'; +export * from './PageLocalization'; +export * from './PlacedObjectPurchaseData'; +export * from './Product'; export * from './ProductTypeEnum'; +export * from './RequestedPage'; +export * from './SearchResult'; diff --git a/src/api/inventory/FurnitureItem.ts b/src/api/inventory/FurnitureItem.ts index 4d84cab9..dc055010 100644 --- a/src/api/inventory/FurnitureItem.ts +++ b/src/api/inventory/FurnitureItem.ts @@ -95,7 +95,7 @@ export class FurnitureItem implements IFurnitureItem return this._extra; } - public get _Str_16260(): boolean + public get recyclable(): boolean { return this._recyclable; } @@ -135,17 +135,17 @@ export class FurnitureItem implements IFurnitureItem return time; } - public get _Str_8932(): number + public get creationDay(): number { return this._creationDay; } - public get _Str_9050(): number + public get creationMonth(): number { return this._creationMonth; } - public get _Str_9408(): number + public get creationYear(): number { return this._creationYear; } @@ -155,7 +155,7 @@ export class FurnitureItem implements IFurnitureItem return this._slotId; } - public get _Str_3951(): number + public get songId(): number { return this._songId; } @@ -185,7 +185,7 @@ export class FurnitureItem implements IFurnitureItem return this._hasRentPeriodStarted; } - public get _Str_10616(): number + public get expirationTimeStamp(): number { return this._expirationTimeStamp; } diff --git a/src/api/inventory/IFurnitureItem.ts b/src/api/inventory/IFurnitureItem.ts index 7e030c52..435597d2 100644 --- a/src/api/inventory/IFurnitureItem.ts +++ b/src/api/inventory/IFurnitureItem.ts @@ -8,7 +8,7 @@ export interface IFurnitureItem stuffData: IObjectData; extra: number; category: number; - _Str_16260: boolean; + recyclable: boolean; isTradable: boolean; isGroupable: boolean; sellable: boolean; diff --git a/src/api/utils/LocalStorageKeys.ts b/src/api/utils/LocalStorageKeys.ts new file mode 100644 index 00000000..6c922790 --- /dev/null +++ b/src/api/utils/LocalStorageKeys.ts @@ -0,0 +1,5 @@ +export class LocalStorageKeys +{ + public static CATALOG_PLACE_MULTIPLE_OBJECTS: string = 'catalogPlaceMultipleObjects'; + public static CATALOG_SKIP_PURCHASE_CONFIRMATION: string = 'catalogSkipPurchaseConfirmation'; +} diff --git a/src/api/utils/index.ts b/src/api/utils/index.ts index 0b5596ee..eeb74fce 100644 --- a/src/api/utils/index.ts +++ b/src/api/utils/index.ts @@ -5,6 +5,7 @@ export * from './LocalizeBageName'; export * from './LocalizeFormattedNumber'; export * from './LocalizeShortNumber'; export * from './LocalizeText'; +export * from './LocalStorageKeys'; export * from './PlaySound'; export * from './ProductImageUtility'; export * from './Randomizer'; diff --git a/src/components/catalog/CatalogContext.tsx b/src/components/catalog/CatalogContext.tsx deleted file mode 100644 index 6d6f9492..00000000 --- a/src/components/catalog/CatalogContext.tsx +++ /dev/null @@ -1,83 +0,0 @@ -import { FrontPageItem, RoomPreviewer } from '@nitrots/nitro-renderer'; -import { createContext, Dispatch, FC, ProviderProps, SetStateAction, useContext } from 'react'; -import { ICatalogNode } from './common/ICatalogNode'; -import { ICatalogOptions } from './common/ICatalogOptions'; -import { ICatalogPage } from './common/ICatalogPage'; -import { IPageLocalization } from './common/IPageLocalization'; -import { IPurchasableOffer } from './common/IPurchasableOffer'; -import { IPurchaseOptions } from './common/IPurchaseOptions'; -import { SearchResult } from './common/SearchResult'; - -interface ICatalogContext -{ - isVisible: boolean; - isBusy: boolean; - setIsBusy: Dispatch>; - pageId: number; - currentType: string; - setCurrentType: Dispatch>; - rootNode: ICatalogNode; - setRootNode: Dispatch>; - offersToNodes: Map; - setOffersToNodes: Dispatch>>; - currentPage: ICatalogPage; - setCurrentPage: Dispatch>; - currentOffer: IPurchasableOffer; - setCurrentOffer: Dispatch>; - activeNodes: ICatalogNode[]; - setActiveNodes: Dispatch>; - searchResult: SearchResult; - setSearchResult: Dispatch>; - frontPageItems: FrontPageItem[]; - setFrontPageItems: Dispatch>; - roomPreviewer: RoomPreviewer; - purchaseOptions: IPurchaseOptions; - setPurchaseOptions: Dispatch>; - catalogOptions: ICatalogOptions; - setCatalogOptions: Dispatch>; - resetState: () => void; - getNodesByOfferId: (offerId: number, flag?: boolean) => ICatalogNode[]; - loadCatalogPage: (pageId: number, offerId: number) => void; - showCatalogPage: (pageId: number, layoutCode: string, localization: IPageLocalization, offers: IPurchasableOffer[], offerId: number, acceptSeasonCurrencyAsCredits: boolean) => void; - activateNode: (targetNode: ICatalogNode) => void; -} - -const CatalogContext = createContext({ - isVisible: null, - isBusy: null, - setIsBusy: null, - pageId: null, - currentType: null, - setCurrentType: null, - rootNode: null, - setRootNode: null, - offersToNodes: null, - setOffersToNodes: null, - currentPage: null, - setCurrentPage: null, - currentOffer: null, - setCurrentOffer: null, - activeNodes: null, - setActiveNodes: null, - searchResult: null, - setSearchResult: null, - frontPageItems: null, - setFrontPageItems: null, - roomPreviewer: null, - purchaseOptions: null, - setPurchaseOptions: null, - catalogOptions: null, - setCatalogOptions: null, - resetState: null, - getNodesByOfferId: null, - loadCatalogPage: null, - showCatalogPage: null, - activateNode: null -}); - -export const CatalogContextProvider: FC> = props => -{ - return { props.children } -} - -export const useCatalogContext = () => useContext(CatalogContext); diff --git a/src/components/catalog/CatalogMessageHandler.tsx b/src/components/catalog/CatalogMessageHandler.tsx deleted file mode 100644 index b1a53941..00000000 --- a/src/components/catalog/CatalogMessageHandler.tsx +++ /dev/null @@ -1,291 +0,0 @@ -import { ApproveNameMessageEvent, CatalogPageMessageEvent, CatalogPagesListEvent, ClubGiftInfoEvent, GiftReceiverNotFoundEvent, GiftWrappingConfigurationEvent, HabboClubOffersMessageEvent, LimitedEditionSoldOutEvent, MarketplaceMakeOfferResult, NodeData, ProductOfferEvent, PurchaseErrorMessageEvent, PurchaseNotAllowedMessageEvent, PurchaseOKMessageEvent, SellablePetPalettesMessageEvent } from '@nitrots/nitro-renderer'; -import { GuildMembershipsMessageEvent } from '@nitrots/nitro-renderer/src/nitro/communication/messages/incoming/user/GuildMembershipsMessageEvent'; -import { FC, useCallback } from 'react'; -import { GetFurnitureData, GetProductDataForLocalization, LocalizeText, NotificationAlertType, NotificationUtilities, ProductTypeEnum } from '../../api'; -import { CatalogGiftReceiverNotFoundEvent, CatalogNameResultEvent, CatalogPurchasedEvent, CatalogPurchaseFailureEvent, CatalogPurchaseNotAllowedEvent, CatalogPurchaseSoldOutEvent } from '../../events'; -import { DispatchUiEvent, UseMessageEventHook } from '../../hooks'; -import { useCatalogContext } from './CatalogContext'; -import { CatalogNode } from './common/CatalogNode'; -import { CatalogPetPalette } from './common/CatalogPetPalette'; -import { CatalogType } from './common/CatalogType'; -import { GiftWrappingConfiguration } from './common/GiftWrappingConfiguration'; -import { ICatalogNode } from './common/ICatalogNode'; -import { IProduct } from './common/IProduct'; -import { IPurchasableOffer } from './common/IPurchasableOffer'; -import { Offer } from './common/Offer'; -import { PageLocalization } from './common/PageLocalization'; -import { Product } from './common/Product'; - -export const CatalogMessageHandler: FC<{}> = props => -{ - const { setIsBusy, pageId, currentType, setRootNode, setOffersToNodes, currentPage, setCurrentOffer, setFrontPageItems, resetState, showCatalogPage, setCatalogOptions, setPurchaseOptions } = useCatalogContext(); - - const onCatalogPagesListEvent = useCallback((event: CatalogPagesListEvent) => - { - const parser = event.getParser(); - const offers: Map = new Map(); - - const getCatalogNode = (node: NodeData, depth: number, parent: ICatalogNode) => - { - const catalogNode = (new CatalogNode(node, depth, parent) as ICatalogNode); - - for(const offerId of catalogNode.offerIds) - { - if(offers.has(offerId)) offers.get(offerId).push(catalogNode); - else offers.set(offerId, [ catalogNode ]); - } - - depth++; - - for(const child of node.children) catalogNode.addChild(getCatalogNode(child, depth, catalogNode)); - - return catalogNode; - } - - setRootNode(getCatalogNode(parser.root, 0, null)); - setOffersToNodes(offers); - }, [ setRootNode, setOffersToNodes ]); - - const onCatalogPageMessageEvent = useCallback((event: CatalogPageMessageEvent) => - { - const parser = event.getParser(); - - if(parser.catalogType !== currentType) return; - - const purchasableOffers: IPurchasableOffer[] = []; - - for(const offer of parser.offers) - { - const products: IProduct[] = []; - const productData = GetProductDataForLocalization(offer.localizationId); - - for(const product of offer.products) - { - const furnitureData = GetFurnitureData(product.furniClassId, product.productType); - - products.push(new Product(product.productType, product.furniClassId, product.extraParam, product.productCount, productData, furnitureData, product.uniqueLimitedItem, product.uniqueLimitedSeriesSize, product.uniqueLimitedItemsLeft)); - } - - if(!products.length) continue; - - const purchasableOffer = new Offer(offer.offerId, offer.localizationId, offer.rent, offer.priceCredits, offer.priceActivityPoints, offer.priceActivityPointsType, offer.giftable, offer.clubLevel, products, offer.bundlePurchaseAllowed); - - if((currentType === CatalogType.NORMAL) || ((purchasableOffer.pricingModel !== Offer.PRICING_MODEL_BUNDLE) && (purchasableOffer.pricingModel !== Offer.PRICING_MODEL_MULTI))) purchasableOffers.push(purchasableOffer); - } - - if(parser.frontPageItems && parser.frontPageItems.length) setFrontPageItems(parser.frontPageItems); - - setIsBusy(false); - - if(pageId === parser.pageId) - { - showCatalogPage(parser.pageId, parser.layoutCode, new PageLocalization(parser.localization.images.concat(), parser.localization.texts.concat()), purchasableOffers, parser.offerId, parser.acceptSeasonCurrencyAsCredits); - } - }, [ currentType, pageId, setFrontPageItems, setIsBusy, showCatalogPage ]); - - const onPurchaseOKMessageEvent = useCallback((event: PurchaseOKMessageEvent) => - { - const parser = event.getParser(); - - DispatchUiEvent(new CatalogPurchasedEvent(parser.offer)); - }, []); - - const onPurchaseErrorMessageEvent = useCallback((event: PurchaseErrorMessageEvent) => - { - const parser = event.getParser(); - - DispatchUiEvent(new CatalogPurchaseFailureEvent(parser.code)); - }, []); - - const onPurchaseNotAllowedMessageEvent = useCallback((event: PurchaseNotAllowedMessageEvent) => - { - const parser = event.getParser(); - - DispatchUiEvent(new CatalogPurchaseNotAllowedEvent(parser.code)); - }, []); - - const onLimitedEditionSoldOutEvent = useCallback((event: LimitedEditionSoldOutEvent) => - { - const parser = event.getParser(); - - DispatchUiEvent(new CatalogPurchaseSoldOutEvent()); - }, []); - - const onProductOfferEvent = useCallback((event: ProductOfferEvent) => - { - const parser = event.getParser(); - const offerData = parser.offer; - - if(!offerData || !offerData.products.length) return; - - const offerProductData = offerData.products[0]; - - if(offerProductData.uniqueLimitedItem) - { - // update unique - } - - const products: IProduct[] = []; - const productData = GetProductDataForLocalization(offerData.localizationId); - - for(const product of offerData.products) - { - const furnitureData = GetFurnitureData(product.furniClassId, product.productType); - - products.push(new Product(product.productType, product.furniClassId, product.extraParam, product.productCount, productData, furnitureData, product.uniqueLimitedItem, product.uniqueLimitedSeriesSize, product.uniqueLimitedItemsLeft)); - } - - const offer = new Offer(offerData.offerId, offerData.localizationId, offerData.rent, offerData.priceCredits, offerData.priceActivityPoints, offerData.priceActivityPointsType, offerData.giftable, offerData.clubLevel, products, offerData.bundlePurchaseAllowed); - - if(!((currentType === CatalogType.NORMAL) || ((offer.pricingModel !== Offer.PRICING_MODEL_BUNDLE) && (offer.pricingModel !== Offer.PRICING_MODEL_MULTI)))) return; - - offer.page = currentPage; - - setCurrentOffer(offer); - - if(offer.product && (offer.product.productType === ProductTypeEnum.WALL)) - { - if(offer.product && (offer.product.productType === ProductTypeEnum.WALL)) - { - setPurchaseOptions(prevValue => - { - const newValue = { ...prevValue }; - - newValue.extraData =( offer.product.extraParam || null); - - return newValue; - }); - } - } - - // (this._isObjectMoverRequested) && (this._purchasableOffer) - }, [ currentType, currentPage, setCurrentOffer, setPurchaseOptions ]); - - const onSellablePetPalettesMessageEvent = useCallback((event: SellablePetPalettesMessageEvent) => - { - 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 }; - }); - }, [ setCatalogOptions ]); - - const onApproveNameMessageEvent = useCallback((event: ApproveNameMessageEvent) => - { - const parser = event.getParser(); - - DispatchUiEvent(new CatalogNameResultEvent(parser.result, parser.validationInfo)); - }, []); - - const onGiftReceiverNotFoundEvent = useCallback(() => - { - DispatchUiEvent(new CatalogGiftReceiverNotFoundEvent()); - }, []); - - const onHabboClubOffersMessageEvent = useCallback((event: HabboClubOffersMessageEvent) => - { - const parser = event.getParser(); - - setCatalogOptions(prevValue => - { - const clubOffers = parser.offers; - - return { ...prevValue, clubOffers }; - }); - }, [ setCatalogOptions ]); - - const onGuildMembershipsMessageEvent = useCallback((event: GuildMembershipsMessageEvent) => - { - const parser = event.getParser(); - - setCatalogOptions(prevValue => - { - const groups = parser.groups; - - return { ...prevValue, groups }; - }); - }, [ setCatalogOptions ]); - - const onGiftWrappingConfigurationEvent = useCallback((event: GiftWrappingConfigurationEvent) => - { - const parser = event.getParser(); - - setCatalogOptions(prevValue => - { - const giftConfiguration = new GiftWrappingConfiguration(parser); - - return { ...prevValue, giftConfiguration }; - }); - }, [ setCatalogOptions ]); - - const onMarketplaceMakeOfferResult = useCallback((event: MarketplaceMakeOfferResult) => - { - const parser = event.getParser(); - - if(!parser) return; - - let title = ''; - if(parser.result === 1) - { - title = LocalizeText('inventory.marketplace.result.title.success'); - } - else - { - title = LocalizeText('inventory.marketplace.result.title.failure'); - } - - const message = LocalizeText(`inventory.marketplace.result.${ parser.result }`); - - NotificationUtilities.simpleAlert(message, NotificationAlertType.DEFAULT, null, null, title); - }, []); - - const onClubGiftInfoEvent = useCallback((event: ClubGiftInfoEvent) => - { - const parser = event.getParser(); - - setCatalogOptions(prevValue => - { - const clubGifts = parser; - - return { ...prevValue, clubGifts }; - }); - }, [ setCatalogOptions ]); - - UseMessageEventHook(CatalogPagesListEvent, onCatalogPagesListEvent); - UseMessageEventHook(CatalogPageMessageEvent, onCatalogPageMessageEvent); - UseMessageEventHook(PurchaseOKMessageEvent, onPurchaseOKMessageEvent); - UseMessageEventHook(PurchaseErrorMessageEvent, onPurchaseErrorMessageEvent); - UseMessageEventHook(PurchaseNotAllowedMessageEvent, onPurchaseNotAllowedMessageEvent); - UseMessageEventHook(LimitedEditionSoldOutEvent, onLimitedEditionSoldOutEvent); - UseMessageEventHook(ProductOfferEvent, onProductOfferEvent); - UseMessageEventHook(GuildMembershipsMessageEvent, onGuildMembershipsMessageEvent); - UseMessageEventHook(SellablePetPalettesMessageEvent, onSellablePetPalettesMessageEvent); - UseMessageEventHook(ApproveNameMessageEvent, onApproveNameMessageEvent); - UseMessageEventHook(GiftReceiverNotFoundEvent, onGiftReceiverNotFoundEvent); - UseMessageEventHook(HabboClubOffersMessageEvent, onHabboClubOffersMessageEvent); - UseMessageEventHook(GiftWrappingConfigurationEvent, onGiftWrappingConfigurationEvent); - UseMessageEventHook(ClubGiftInfoEvent, onClubGiftInfoEvent); - UseMessageEventHook(MarketplaceMakeOfferResult, onMarketplaceMakeOfferResult); - - return null; -} diff --git a/src/components/catalog/CatalogView.tsx b/src/components/catalog/CatalogView.tsx index c8645189..28b6e8de 100644 --- a/src/components/catalog/CatalogView.tsx +++ b/src/components/catalog/CatalogView.tsx @@ -1,406 +1,75 @@ -import { CatalogPublishedMessageEvent, FrontPageItem, GetCatalogIndexComposer, GetCatalogPageComposer, GetClubGiftInfo, GetGiftWrappingConfigurationComposer, ILinkEventTracker, RoomPreviewer } from '@nitrots/nitro-renderer'; -import { FC, useCallback, useEffect, useState } from 'react'; -import { AddEventLinkTracker, GetRoomEngine, LocalizeText, NotificationAlertType, NotificationUtilities, PlaySound, RemoveLinkEventTracker, SendMessageComposer, SoundNames } from '../../api'; +import { ILinkEventTracker } from '@nitrots/nitro-renderer'; +import { FC, useEffect } from 'react'; +import { AddEventLinkTracker, LocalizeText, RemoveLinkEventTracker } from '../../api'; import { Column, Grid, NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../common'; -import { CatalogPurchasedEvent } from '../../events'; -import { UseMessageEventHook, UseUiEvent } from '../../hooks'; -import { CatalogContextProvider } from './CatalogContext'; -import { CatalogMessageHandler } from './CatalogMessageHandler'; -import { CatalogPage } from './common/CatalogPage'; -import { CatalogType } from './common/CatalogType'; -import { ICatalogNode } from './common/ICatalogNode'; -import { ICatalogOptions } from './common/ICatalogOptions'; -import { ICatalogPage } from './common/ICatalogPage'; -import { IPageLocalization } from './common/IPageLocalization'; -import { IPurchasableOffer } from './common/IPurchasableOffer'; -import { IPurchaseOptions } from './common/IPurchaseOptions'; -import { RequestedPage } from './common/RequestedPage'; -import { SearchResult } from './common/SearchResult'; +import { useCatalog } from '../../hooks'; import { CatalogGiftView } from './views/gift/CatalogGiftView'; import { CatalogNavigationView } from './views/navigation/CatalogNavigationView'; import { GetCatalogLayout } from './views/page/layout/GetCatalogLayout'; import { MarketplacePostOfferView } from './views/page/layout/marketplace/MarketplacePostOfferView'; -const REQUESTED_PAGE = new RequestedPage(); - export const CatalogView: FC<{}> = props => { - const [ isVisible, setIsVisible ] = useState(false); - const [ isBusy, setIsBusy ] = useState(false); - const [ pageId, setPageId ] = useState(-1); - const [ previousPageId, setPreviousPageId ] = useState(-1); - const [ currentType, setCurrentType ] = useState(CatalogType.NORMAL); - const [ rootNode, setRootNode ] = useState(null); - const [ offersToNodes, setOffersToNodes ] = useState>(null); - const [ currentPage, setCurrentPage ] = useState(null); - const [ currentOffer, setCurrentOffer ] = useState(null); - const [ activeNodes, setActiveNodes ] = useState([]); - const [ searchResult, setSearchResult ] = useState(null); - const [ frontPageItems, setFrontPageItems ] = useState([]); - const [ roomPreviewer, setRoomPreviewer ] = useState(null); - const [ navigationHidden, setNavigationHidden ] = useState(false); - const [ purchaseOptions, setPurchaseOptions ] = useState({ quantity: 1, extraData: null, extraParamRequired: false, previewStuffData: null }); - const [ catalogOptions, setCatalogOptions ] = useState({}); - - const resetState = useCallback(() => - { - setPageId(-1); - setPreviousPageId(-1); - setRootNode(null); - setOffersToNodes(null); - setCurrentPage(null); - setCurrentOffer(null); - setActiveNodes([]); - setSearchResult(null); - setFrontPageItems([]); - setIsVisible(false); - }, []); - - const onCatalogPublishedMessageEvent = useCallback((event: CatalogPublishedMessageEvent) => - { - const wasVisible = isVisible; - - resetState(); - - if(wasVisible) NotificationUtilities.simpleAlert(LocalizeText('catalog.alert.published.description'), NotificationAlertType.ALERT, null, null, LocalizeText('catalog.alert.published.title')); - }, [ isVisible, resetState ]); - - UseMessageEventHook(CatalogPublishedMessageEvent, onCatalogPublishedMessageEvent); - - const getNodeById = useCallback((id: number, node: ICatalogNode) => - { - if((node.pageId === id) && (node !== rootNode)) return node; - - for(const child of node.children) - { - const found = (getNodeById(id, child) as ICatalogNode); - - if(found) return found; - } - - return null; - }, [ rootNode ]); - - const getNodeByName = useCallback((name: string, node: ICatalogNode) => - { - if((node.pageName === name) && (node !== rootNode)) return node; - - for(const child of node.children) - { - const found = (getNodeByName(name, child) as ICatalogNode); - - if(found) return found; - } - - return null; - }, [ rootNode ]); - - const getNodesByOfferId = useCallback((offerId: number, flag: boolean = false) => - { - if(!offersToNodes || !offersToNodes.size) return null; - - if(flag) - { - const nodes: ICatalogNode[] = []; - const offers = offersToNodes.get(offerId); - - if(offers && offers.length) for(const offer of offers) (offer.isVisible && nodes.push(offer)); - - if(nodes.length) return nodes; - } - - return offersToNodes.get(offerId); - }, [ offersToNodes ]); - - const loadCatalogPage = useCallback((pageId: number, offerId: number) => - { - if(pageId < 0) return; - - setIsBusy(true); - setPageId(pageId); - - if(pageId > -1) SendMessageComposer(new GetCatalogPageComposer(pageId, offerId, currentType)); - }, [ currentType ]); - - const showCatalogPage = useCallback((pageId: number, layoutCode: string, localization: IPageLocalization, offers: IPurchasableOffer[], offerId: number, acceptSeasonCurrencyAsCredits: boolean) => - { - const catalogPage = (new CatalogPage(pageId, layoutCode, localization, offers, acceptSeasonCurrencyAsCredits) as ICatalogPage); - - setCurrentPage(catalogPage); - setPreviousPageId(prevValue => ((pageId !== -1) ? pageId : prevValue)); - setNavigationHidden(false); - - if((offerId > -1) && catalogPage.offers.length) - { - for(const offer of catalogPage.offers) - { - if(offer.offerId !== offerId) continue; - - setCurrentOffer(offer) - - break; - } - } - }, []); - - const activateNode = useCallback((targetNode: ICatalogNode, offerId: number = -1) => - { - if(targetNode.parent.pageName === 'root') - { - if(targetNode.children.length) - { - for(const child of targetNode.children) - { - if(!child.isVisible) continue; - - targetNode = child; - - break; - } - } - } - - const nodes: ICatalogNode[] = []; - - let node = targetNode; - - while(node && (node.pageName !== 'root')) - { - nodes.push(node); - - node = node.parent; - } - - nodes.reverse(); - - setActiveNodes(prevValue => - { - const isActive = (prevValue.indexOf(targetNode) >= 0); - const isOpen = targetNode.isOpen; - - for(const existing of prevValue) - { - existing.deactivate(); - - if(nodes.indexOf(existing) === -1) existing.close(); - } - - for(const n of nodes) - { - n.activate(); - - if(n.parent) n.open(); - - if((n === targetNode.parent) && n.children.length) n.open(); - } - - if(isActive && isOpen) targetNode.close(); - else targetNode.open(); - - return nodes; - }); - - if(targetNode.pageId > -1) loadCatalogPage(targetNode.pageId, offerId); - }, [ setActiveNodes, loadCatalogPage ]); - - const openPageById = useCallback((id: number) => - { - setSearchResult(null); - - if(!isVisible) - { - REQUESTED_PAGE.requestById = id; - - setIsVisible(true); - } - else - { - const node = getNodeById(id, rootNode); - - if(node) activateNode(node); - } - }, [ isVisible, rootNode, getNodeById, activateNode ]); - - const openPageByName = useCallback((name: string) => - { - setSearchResult(null); - - if(!isVisible) - { - REQUESTED_PAGE.requestByName = name; - - setIsVisible(true); - } - else - { - const node = getNodeByName(name, rootNode); - - if(node) activateNode(node); - } - }, [ isVisible, rootNode, getNodeByName, activateNode ]); - - const openPageByOfferId = useCallback((offerId: number) => - { - setSearchResult(null); - - if(!isVisible) - { - REQUESTED_PAGE.requestedByOfferId = offerId; - - setIsVisible(true); - } - else - { - const nodes = getNodesByOfferId(offerId); - - if(!nodes || !nodes.length) return; - - activateNode(nodes[0], offerId); - } - }, [ isVisible, getNodesByOfferId, activateNode ]); - - const onCatalogPurchasedEvent = useCallback((event: CatalogPurchasedEvent) => - { - PlaySound(SoundNames.CREDITS); - }, []); - - UseUiEvent(CatalogPurchasedEvent.PURCHASE_SUCCESS, onCatalogPurchasedEvent); - - const linkReceived = useCallback((url: string) => - { - const parts = url.split('/'); - - if(parts.length < 2) return; - - switch(parts[1]) - { - case 'show': - setIsVisible(true); - return; - case 'hide': - setIsVisible(false); - return; - case 'toggle': - setIsVisible(prevValue => !prevValue); - return; - case 'open': - if(parts.length > 2) - { - if(parts.length === 4) - { - switch(parts[2]) - { - case 'offerId': - openPageByOfferId(parseInt(parts[3])); - return; - } - } - else - { - openPageByName(parts[2]); - } - } - else - { - setIsVisible(true); - } - - return; - } - }, [ openPageByOfferId, openPageByName ]); + const { isVisible = false, setIsVisible = null, rootNode = null, currentPage = null, navigationHidden = false, setNavigationHidden = null, activeNodes = [], searchResult = null, setSearchResult = null, getNodeById = null, openPageByName = null, openPageByOfferId = null, activateNode = null } = useCatalog(); useEffect(() => { const linkTracker: ILinkEventTracker = { - linkReceived, + linkReceived: (url: string) => + { + const parts = url.split('/'); + + if(parts.length < 2) return; + + switch(parts[1]) + { + case 'show': + setIsVisible(true); + return; + case 'hide': + setIsVisible(false); + return; + case 'toggle': + setIsVisible(prevValue => !prevValue); + return; + case 'open': + if(parts.length > 2) + { + if(parts.length === 4) + { + switch(parts[2]) + { + case 'offerId': + openPageByOfferId(parseInt(parts[3])); + return; + } + } + else + { + openPageByName(parts[2]); + } + } + else + { + setIsVisible(true); + } + + return; + } + }, eventUrlPrefix: 'catalog/' }; AddEventLinkTracker(linkTracker); return () => RemoveLinkEventTracker(linkTracker); - }, [ linkReceived ]); - - useEffect(() => - { - setRoomPreviewer(new RoomPreviewer(GetRoomEngine(), ++RoomPreviewer.PREVIEW_COUNTER)); - - return () => - { - setRoomPreviewer(prevValue => - { - prevValue.dispose(); - - return null; - }); - } - }, []); - - useEffect(() => - { - if(!isVisible || rootNode) return; - - SendMessageComposer(new GetGiftWrappingConfigurationComposer()); - SendMessageComposer(new GetClubGiftInfo()); - SendMessageComposer(new GetCatalogIndexComposer(currentType)); - }, [ isVisible, rootNode, currentType ]); - - useEffect(() => - { - if(!isVisible || !rootNode) return; - - switch(REQUESTED_PAGE.requestType) - { - case RequestedPage.REQUEST_TYPE_NONE: - if(activeNodes && activeNodes.length) return; - - if(rootNode.isBranch) - { - for(const child of rootNode.children) - { - if(child && child.isVisible) - { - activateNode(child); - - return; - } - } - } - return; - case RequestedPage.REQUEST_TYPE_ID: - openPageById(REQUESTED_PAGE.requestById); - REQUESTED_PAGE.resetRequest(); - return; - case RequestedPage.REQUEST_TYPE_OFFER: - openPageByOfferId(REQUESTED_PAGE.requestedByOfferId); - REQUESTED_PAGE.resetRequest(); - return; - case RequestedPage.REQUEST_TYPE_NAME: - openPageByName(REQUESTED_PAGE.requestByName); - REQUESTED_PAGE.resetRequest(); - return; - } - }, [ isVisible, rootNode, activeNodes, activateNode, openPageById, openPageByOfferId, openPageByName ]); - - useEffect(() => - { - if(!searchResult && currentPage && (currentPage.pageId === -1)) openPageById(previousPageId); - }, [ searchResult, currentPage, previousPageId, openPageById ]); - - useEffect(() => - { - return () => setCurrentOffer(null); - }, [ currentPage ]); + }, [ setIsVisible, openPageByOfferId, openPageByName ]); return ( - - + <> { isVisible && - - { - setIsVisible(false); - } } /> + setIsVisible(false) } /> { rootNode && (rootNode.children.length > 0) && rootNode.children.map(child => { @@ -433,6 +102,6 @@ export const CatalogView: FC<{}> = props => } - + ); } diff --git a/src/components/catalog/common/AttemptCatalogPlacement.ts b/src/components/catalog/common/AttemptCatalogPlacement.ts deleted file mode 100644 index 2eb418a3..00000000 --- a/src/components/catalog/common/AttemptCatalogPlacement.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { CatalogPageMessageOfferData, RoomObjectCategory, RoomObjectPlacementSource } from '@nitrots/nitro-renderer'; -import { GetRoomEngine, ProductTypeEnum } from '../../../api'; -import { IsCatalogOfferDraggable } from './IsCatalogOfferDraggable'; - -export const AttemptCatalogPlacement = (offer: CatalogPageMessageOfferData) => -{ - if(!IsCatalogOfferDraggable(offer)) return; - - const product = offer.products[0]; - - let category: number = -1; - - switch(product.productType) - { - case ProductTypeEnum.FLOOR: - category = RoomObjectCategory.FLOOR; - break; - case ProductTypeEnum.WALL: - category = RoomObjectCategory.WALL; - break; - } - - if(category === -1) return; - - if(GetRoomEngine().processRoomObjectPlacement(RoomObjectPlacementSource.CATALOG, -(offer.offerId), category, product.furniClassId, (product.extraParam) ? product.extraParam.toString() : null)) - { - - } -} diff --git a/src/components/catalog/common/FurniCategory.ts b/src/components/catalog/common/FurniCategory.ts deleted file mode 100644 index 07195cb0..00000000 --- a/src/components/catalog/common/FurniCategory.ts +++ /dev/null @@ -1,26 +0,0 @@ -export class FurniCategory -{ - public static DEFAULT: number = 1; - public static WALL_PAPER: number = 2; - public static FLOOR: number = 3; - public static LANDSCAPE: number = 4; - public static POST_IT: number = 5; - public static POSTER: number = 6; - public static SOUND_SET: number = 7; - public static TRAX_SONG: number = 8; - public static PRESENT: number = 9; - public static ECOTRON_BOX: number = 10; - public static TROPHY: number = 11; - public static CREDIT_FURNI: number = 12; - public static PET_SHAMPOO: number = 13; - public static PET_CUSTOM_PART: number = 14; - public static PET_CUSTOM_PART_SHAMPOO: number = 15; - public static PET_SADDLE: number = 16; - public static GUILD_FURNI: number = 17; - public static GAME_FURNI: number = 18; - public static MONSTERPLANT_SEED: number = 19; - public static MONSTERPLANT_REVIVAL: number = 20; - public static MONSTERPLANT_REBREED: number = 21; - public static MONSTERPLANT_FERTILIZE: number = 22; - public static FIGURE_PURCHASABLE_SET: number = 23; -} \ No newline at end of file diff --git a/src/components/catalog/common/IPurse.ts b/src/components/catalog/common/IPurse.ts deleted file mode 100644 index bd365ba6..00000000 --- a/src/components/catalog/common/IPurse.ts +++ /dev/null @@ -1,14 +0,0 @@ -export interface IPurse -{ - _Str_14389: boolean; - _Str_4458: number; - credits: number; - clubDays: number; - clubPeriods: number; - _Str_13571: boolean; - _Str_3738: boolean; - _Str_6288: number; - _Str_4605: number; - _Str_6312: number; - _Str_5590(_arg_1: number): number; -} diff --git a/src/components/catalog/common/IsCatalogOfferDraggable.ts b/src/components/catalog/common/IsCatalogOfferDraggable.ts deleted file mode 100644 index 976bd2e1..00000000 --- a/src/components/catalog/common/IsCatalogOfferDraggable.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { CatalogPageMessageOfferData, RoomControllerLevel } from '@nitrots/nitro-renderer'; -import { GetRoomSession, ProductTypeEnum } from '../../../api'; - -export const IsCatalogOfferDraggable = (offer: CatalogPageMessageOfferData) => -{ - return ((GetRoomSession().isRoomOwner || (GetRoomSession().isGuildRoom && (GetRoomSession().controllerLevel >= RoomControllerLevel.GUILD_MEMBER))) && (offer.products.length === 1) && (offer.products[0].productType !== ProductTypeEnum.EFFECT) && (offer.products[0].productType !== ProductTypeEnum.HABBO_CLUB)) -} diff --git a/src/components/catalog/common/Purse.ts b/src/components/catalog/common/Purse.ts deleted file mode 100644 index eebaacf8..00000000 --- a/src/components/catalog/common/Purse.ts +++ /dev/null @@ -1,144 +0,0 @@ -import { GetNitroInstance } from '../../../api'; -import { IPurse } from './IPurse'; - -export class Purse implements IPurse -{ - private _credits: number = 0; - private _activityPoints: Map; - private _clubDays: number = 0; - private _clubPeriods: number = 0; - private _isVIP: boolean = false; - private _pastClubDays: number = 0; - private _pastVipDays: number = 0; - private _isExpiring: boolean = false; - private _minutesUntilExpiration: number = 0; - private _minutesSinceLastModified: number; - private _lastUpdated: number; - - public get credits(): number - { - return this._credits; - } - - public set credits(k: number) - { - this._lastUpdated = GetNitroInstance().time; - this._credits = k; - } - - public get clubDays(): number - { - return this._clubDays; - } - - public set clubDays(k: number) - { - this._lastUpdated = GetNitroInstance().time; - this._clubDays = k; - } - - public get clubPeriods(): number - { - return this._clubPeriods; - } - - public set clubPeriods(k: number) - { - this._lastUpdated = GetNitroInstance().time; - this._clubPeriods = k; - } - - public get _Str_13571(): boolean - { - return (this._clubDays > 0) || (this._clubPeriods > 0); - } - - public get _Str_3738(): boolean - { - return this._isVIP; - } - - public get _Str_14389(): boolean - { - return this._isExpiring; - } - - public set _Str_14389(k: boolean) - { - this._isExpiring = k; - } - - public set _Str_3738(k: boolean) - { - this._isVIP = k; - } - - public get _Str_6288(): number - { - return this._pastClubDays; - } - - public set _Str_6288(k: number) - { - this._lastUpdated = GetNitroInstance().time; - this._pastClubDays = k; - } - - public get _Str_4605(): number - { - return this._pastVipDays; - } - - public set _Str_4605(k: number) - { - this._lastUpdated = GetNitroInstance().time; - this._pastVipDays = k; - } - - public get _Str_18527(): Map - { - return this._activityPoints; - } - - public set _Str_18527(k: Map) - { - this._lastUpdated = GetNitroInstance().time; - this._activityPoints = k; - } - - public _Str_5590(k: number): number - { - return this._activityPoints[k]; - } - - public set _Str_4458(k: number) - { - this._lastUpdated = GetNitroInstance().time; - - this._minutesUntilExpiration = k; - } - - public get _Str_4458(): number - { - const k = ((GetNitroInstance().time - this._lastUpdated) / (1000 * 60)); - const _local_2 = (this._minutesUntilExpiration - k); - - return (_local_2 > 0) ? _local_2 : 0; - } - - public set _Str_6312(k: number) - { - this._lastUpdated = GetNitroInstance().time; - this._minutesSinceLastModified = k; - } - - public get _Str_6312(): number - { - return this._minutesSinceLastModified; - } - - public get _Str_26225(): number - { - return this._lastUpdated; - } -} diff --git a/src/components/catalog/common/SubscriptionInfo.ts b/src/components/catalog/common/SubscriptionInfo.ts deleted file mode 100644 index 72d16e69..00000000 --- a/src/components/catalog/common/SubscriptionInfo.ts +++ /dev/null @@ -1,18 +0,0 @@ - -export class SubscriptionInfo -{ - private _lastUpdated: number; - - constructor( - public readonly clubDays: number = 0, - public readonly clubPeriods: number = 0, - public readonly isVip: boolean = false, - public readonly pastDays: number = 0, - public readonly pastVipDays: number = 0) - {} - - public get lastUpdated(): number - { - return this._lastUpdated; - } -} diff --git a/src/components/catalog/views/CatalogPurchaseConfirmView.tsx b/src/components/catalog/views/CatalogPurchaseConfirmView.tsx new file mode 100644 index 00000000..30dcfc3b --- /dev/null +++ b/src/components/catalog/views/CatalogPurchaseConfirmView.tsx @@ -0,0 +1,10 @@ +import { FC } from 'react'; + +export const CatalogPurchaseConfirmView: FC<{}> = props => +{ + const {} = props; + + return ( +
+ ); +} diff --git a/src/components/catalog/views/gift/CatalogGiftView.tsx b/src/components/catalog/views/gift/CatalogGiftView.tsx index d3e94506..0180eaec 100644 --- a/src/components/catalog/views/gift/CatalogGiftView.tsx +++ b/src/components/catalog/views/gift/CatalogGiftView.tsx @@ -5,8 +5,7 @@ import { FC, useCallback, useEffect, useMemo, useState } from 'react'; import { GetSessionDataManager, LocalizeText, ProductTypeEnum, SendMessageComposer } from '../../../../api'; import { Base, Button, ButtonGroup, Column, Flex, FormGroup, LayoutCurrencyIcon, LayoutFurniImageView, LayoutGiftTagView, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../../common'; import { CatalogEvent, CatalogInitGiftEvent, CatalogPurchasedEvent } from '../../../../events'; -import { UseUiEvent } from '../../../../hooks'; -import { useCatalogContext } from '../../CatalogContext'; +import { useCatalog, UseUiEvent } from '../../../../hooks'; export const CatalogGiftView: FC<{}> = props => { @@ -24,7 +23,7 @@ export const CatalogGiftView: FC<{}> = props => const [ maxBoxIndex, setMaxBoxIndex ] = useState(0); const [ maxRibbonIndex, setMaxRibbonIndex ] = useState(0); const [ receiverNotFound, setReceiverNotFound ] = useState(false); - const { catalogOptions = null } = useCatalogContext(); + const { catalogOptions = null } = useCatalog(); const { giftConfiguration = null } = catalogOptions; const close = useCallback(() => diff --git a/src/components/catalog/views/navigation/CatalogNavigationItemView.tsx b/src/components/catalog/views/navigation/CatalogNavigationItemView.tsx index d3893e86..5eb1c45c 100644 --- a/src/components/catalog/views/navigation/CatalogNavigationItemView.tsx +++ b/src/components/catalog/views/navigation/CatalogNavigationItemView.tsx @@ -1,9 +1,8 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { FC } from 'react'; -import { LayoutGridItem } from '../../../../common/layout/LayoutGridItem'; -import { Text } from '../../../../common/Text'; -import { useCatalogContext } from '../../CatalogContext'; -import { ICatalogNode } from '../../common/ICatalogNode'; +import { ICatalogNode } from '../../../../api'; +import { LayoutGridItem, Text } from '../../../../common'; +import { useCatalog } from '../../../../hooks'; import { CatalogIconView } from '../catalog-icon/CatalogIconView'; import { CatalogNavigationSetView } from './CatalogNavigationSetView'; @@ -15,7 +14,7 @@ export interface CatalogNavigationItemViewProps export const CatalogNavigationItemView: FC = props => { const { node = null } = props; - const { activateNode = null } = useCatalogContext(); + const { activateNode = null } = useCatalog(); return ( <> diff --git a/src/components/catalog/views/navigation/CatalogNavigationSetView.tsx b/src/components/catalog/views/navigation/CatalogNavigationSetView.tsx index e1553631..19f71f47 100644 --- a/src/components/catalog/views/navigation/CatalogNavigationSetView.tsx +++ b/src/components/catalog/views/navigation/CatalogNavigationSetView.tsx @@ -1,5 +1,5 @@ import { FC } from 'react'; -import { ICatalogNode } from '../../common/ICatalogNode'; +import { ICatalogNode } from '../../../../api'; import { CatalogNavigationItemView } from './CatalogNavigationItemView'; export interface CatalogNavigationSetViewProps diff --git a/src/components/catalog/views/navigation/CatalogNavigationView.tsx b/src/components/catalog/views/navigation/CatalogNavigationView.tsx index c1d187f4..3924928d 100644 --- a/src/components/catalog/views/navigation/CatalogNavigationView.tsx +++ b/src/components/catalog/views/navigation/CatalogNavigationView.tsx @@ -1,8 +1,7 @@ import { FC } from 'react'; -import { AutoGrid } from '../../../../common/AutoGrid'; -import { Column } from '../../../../common/Column'; -import { useCatalogContext } from '../../CatalogContext'; -import { ICatalogNode } from '../../common/ICatalogNode'; +import { ICatalogNode } from '../../../../api'; +import { AutoGrid, Column } from '../../../../common'; +import { useCatalog } from '../../../../hooks'; import { CatalogSearchView } from '../page/common/CatalogSearchView'; import { CatalogNavigationItemView } from './CatalogNavigationItemView'; import { CatalogNavigationSetView } from './CatalogNavigationSetView'; @@ -15,7 +14,7 @@ export interface CatalogNavigationViewProps export const CatalogNavigationView: FC = props => { const { node = null } = props; - const { searchResult = null } = useCatalogContext(); + const { searchResult = null } = useCatalog(); return ( <> diff --git a/src/components/catalog/views/page/common/CatalogGridOfferView.tsx b/src/components/catalog/views/page/common/CatalogGridOfferView.tsx index fa8d3e28..79d79d38 100644 --- a/src/components/catalog/views/page/common/CatalogGridOfferView.tsx +++ b/src/components/catalog/views/page/common/CatalogGridOfferView.tsx @@ -1,17 +1,20 @@ -import { FC, useMemo } from 'react'; -import { ProductTypeEnum } from '../../../../../api'; +import { MouseEventType } from '@nitrots/nitro-renderer'; +import { FC, MouseEvent, useMemo, useState } from 'react'; +import { IPurchasableOffer, Offer, ProductTypeEnum } from '../../../../../api'; import { LayoutAvatarImageView, LayoutGridItem, LayoutGridItemProps } from '../../../../../common'; -import { IPurchasableOffer } from '../../../common/IPurchasableOffer'; -import { Offer } from '../../../common/Offer'; +import { useCatalog } from '../../../../../hooks'; interface CatalogGridOfferViewProps extends LayoutGridItemProps { offer: IPurchasableOffer; + selectOffer: (offer: IPurchasableOffer) => void; } export const CatalogGridOfferView: FC = props => { - const { offer = null, ...rest } = props; + const { offer = null, selectOffer = null, itemActive = false, ...rest } = props; + const [ isMouseDown, setMouseDown ] = useState(false); + const { requestOfferToMover = null } = useCatalog(); const iconUrl = useMemo(() => { @@ -23,12 +26,31 @@ export const CatalogGridOfferView: FC = props => return offer.product.getIconUrl(offer); }, [ offer ]); + const onMouseEvent = (event: MouseEvent) => + { + switch(event.type) + { + case MouseEventType.MOUSE_DOWN: + selectOffer(offer); + setMouseDown(true); + return; + case MouseEventType.MOUSE_UP: + setMouseDown(false); + return; + case MouseEventType.ROLL_OUT: + if(!isMouseDown || !itemActive) return; + + requestOfferToMover(offer); + return; + } + } + const product = offer.product; if(!product) return null; return ( - + { (offer.product.productType === ProductTypeEnum.ROBOT) && } diff --git a/src/components/catalog/views/page/common/CatalogSearchView.tsx b/src/components/catalog/views/page/common/CatalogSearchView.tsx index 2a375fbf..bd0f0caf 100644 --- a/src/components/catalog/views/page/common/CatalogSearchView.tsx +++ b/src/components/catalog/views/page/common/CatalogSearchView.tsx @@ -1,25 +1,15 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { IFurnitureData } from '@nitrots/nitro-renderer'; import { FC, useCallback, useEffect, useState } from 'react'; -import { GetSessionDataManager, LocalizeText } from '../../../../../api'; -import { Button } from '../../../../../common/Button'; -import { Flex } from '../../../../../common/Flex'; -import { useCatalogContext } from '../../../CatalogContext'; -import { CatalogPage } from '../../../common/CatalogPage'; -import { CatalogType } from '../../../common/CatalogType'; -import { FilterCatalogNode, GetOfferNodes } from '../../../common/CatalogUtilities'; -import { FurnitureOffer } from '../../../common/FurnitureOffer'; -import { ICatalogNode } from '../../../common/ICatalogNode'; -import { ICatalogPage } from '../../../common/ICatalogPage'; -import { IPurchasableOffer } from '../../../common/IPurchasableOffer'; -import { PageLocalization } from '../../../common/PageLocalization'; -import { SearchResult } from '../../../common/SearchResult'; +import { CatalogPage, CatalogType, FilterCatalogNode, FurnitureOffer, GetOfferNodes, GetSessionDataManager, ICatalogNode, ICatalogPage, IPurchasableOffer, LocalizeText, PageLocalization, SearchResult } from '../../../../../api'; +import { Button, Flex } from '../../../../../common'; +import { useCatalog } from '../../../../../hooks'; export const CatalogSearchView: FC<{}> = props => { const [ searchValue, setSearchValue ] = useState(''); const [ needsProcessing, setNeedsProcessing ] = useState(false); - const { currentType = null, rootNode = null, setActiveNodes = null, offersToNodes = null, searchResult = null, setSearchResult = null, setCurrentPage = null } = useCatalogContext(); + const { currentType = null, rootNode = null, offersToNodes = null, searchResult = null, setSearchResult = null, setCurrentPage = null } = useCatalog(); const updateSearchValue = (value: string) => { diff --git a/src/components/catalog/views/page/layout/CatalogLayout.types.ts b/src/components/catalog/views/page/layout/CatalogLayout.types.ts index a64e9412..b05bccf9 100644 --- a/src/components/catalog/views/page/layout/CatalogLayout.types.ts +++ b/src/components/catalog/views/page/layout/CatalogLayout.types.ts @@ -1,4 +1,4 @@ -import { ICatalogPage } from '../../../common/ICatalogPage'; +import { ICatalogPage } from '../../../../../api'; export interface CatalogLayoutProps { diff --git a/src/components/catalog/views/page/layout/CatalogLayoutBadgeDisplayView.tsx b/src/components/catalog/views/page/layout/CatalogLayoutBadgeDisplayView.tsx index 849fff8d..b3a619f3 100644 --- a/src/components/catalog/views/page/layout/CatalogLayoutBadgeDisplayView.tsx +++ b/src/components/catalog/views/page/layout/CatalogLayoutBadgeDisplayView.tsx @@ -1,7 +1,7 @@ import { FC } from 'react'; import { LocalizeText } from '../../../../../api'; import { Base, Column, Flex, Grid, Text } from '../../../../../common'; -import { useCatalogContext } from '../../../CatalogContext'; +import { useCatalog } from '../../../../../hooks'; import { CatalogBadgeSelectorWidgetView } from '../widgets/CatalogBadgeSelectorWidgetView'; import { CatalogFirstProductSelectorWidgetView } from '../widgets/CatalogFirstProductSelectorWidgetView'; import { CatalogItemGridWidgetView } from '../widgets/CatalogItemGridWidgetView'; @@ -14,7 +14,7 @@ import { CatalogLayoutProps } from './CatalogLayout.types'; export const CatalogLayoutBadgeDisplayView: FC = props => { const { page = null } = props; - const { currentOffer = null } = useCatalogContext(); + const { currentOffer = null } = useCatalog(); return ( <> diff --git a/src/components/catalog/views/page/layout/CatalogLayoutDefaultView.tsx b/src/components/catalog/views/page/layout/CatalogLayoutDefaultView.tsx index 8aa7a913..969b536b 100644 --- a/src/components/catalog/views/page/layout/CatalogLayoutDefaultView.tsx +++ b/src/components/catalog/views/page/layout/CatalogLayoutDefaultView.tsx @@ -1,6 +1,6 @@ import { FC } from 'react'; import { Base, Column, Flex, Grid, Text } from '../../../../../common'; -import { useCatalogContext } from '../../../CatalogContext'; +import { useCatalog } from '../../../../../hooks'; import { CatalogAddOnBadgeWidgetView } from '../widgets/CatalogAddOnBadgeWidgetView'; import { CatalogItemGridWidgetView } from '../widgets/CatalogItemGridWidgetView'; import { CatalogLimitedItemWidgetView } from '../widgets/CatalogLimitedItemWidgetView'; @@ -13,7 +13,7 @@ import { CatalogLayoutProps } from './CatalogLayout.types'; export const CatalogLayoutDefaultView: FC = props => { const { page = null } = props; - const { currentOffer = null } = useCatalogContext(); + const { currentOffer = null } = useCatalog(); return ( diff --git a/src/components/catalog/views/page/layout/CatalogLayoutGuildCustomFurniView.tsx b/src/components/catalog/views/page/layout/CatalogLayoutGuildCustomFurniView.tsx index 9016f004..cf129517 100644 --- a/src/components/catalog/views/page/layout/CatalogLayoutGuildCustomFurniView.tsx +++ b/src/components/catalog/views/page/layout/CatalogLayoutGuildCustomFurniView.tsx @@ -1,10 +1,6 @@ import { FC } from 'react'; -import { Base } from '../../../../../common/Base'; -import { Column } from '../../../../../common/Column'; -import { Flex } from '../../../../../common/Flex'; -import { Grid } from '../../../../../common/Grid'; -import { Text } from '../../../../../common/Text'; -import { useCatalogContext } from '../../../CatalogContext'; +import { Base, Column, Flex, Grid, Text } from '../../../../../common'; +import { useCatalog } from '../../../../../hooks'; import { CatalogGuildBadgeWidgetView } from '../widgets/CatalogGuildBadgeWidgetView'; import { CatalogGuildSelectorWidgetView } from '../widgets/CatalogGuildSelectorWidgetView'; import { CatalogItemGridWidgetView } from '../widgets/CatalogItemGridWidgetView'; @@ -16,7 +12,7 @@ import { CatalogLayoutProps } from './CatalogLayout.types'; export const CatalogLayouGuildCustomFurniView: FC = props => { const { page = null } = props; - const { currentOffer = null } = useCatalogContext(); + const { currentOffer = null } = useCatalog(); return ( diff --git a/src/components/catalog/views/page/layout/CatalogLayoutGuildForumView.tsx b/src/components/catalog/views/page/layout/CatalogLayoutGuildForumView.tsx index 2e63e14d..b5a89ca6 100644 --- a/src/components/catalog/views/page/layout/CatalogLayoutGuildForumView.tsx +++ b/src/components/catalog/views/page/layout/CatalogLayoutGuildForumView.tsx @@ -2,7 +2,7 @@ import { CatalogGroupsComposer } from '@nitrots/nitro-renderer'; import { FC, useEffect, useState } from 'react'; import { SendMessageComposer } from '../../../../../api'; import { Base, Column, Flex, Grid, Text } from '../../../../../common'; -import { useCatalogContext } from '../../../CatalogContext'; +import { useCatalog } from '../../../../../hooks'; import { CatalogFirstProductSelectorWidgetView } from '../widgets/CatalogFirstProductSelectorWidgetView'; import { CatalogGuildSelectorWidgetView } from '../widgets/CatalogGuildSelectorWidgetView'; import { CatalogPurchaseWidgetView } from '../widgets/CatalogPurchaseWidgetView'; @@ -13,7 +13,7 @@ export const CatalogLayouGuildForumView: FC = props => { const { page = null } = props; const [ selectedGroupIndex, setSelectedGroupIndex ] = useState(0); - const { currentOffer = null, setCurrentOffer = null, catalogOptions = null } = useCatalogContext(); + const { currentOffer = null, setCurrentOffer = null, catalogOptions = null } = useCatalog(); const { groups = null } = catalogOptions; useEffect(() => diff --git a/src/components/catalog/views/page/layout/CatalogLayoutSpacesView.tsx b/src/components/catalog/views/page/layout/CatalogLayoutSpacesView.tsx index d83b2d8d..88cd30b6 100644 --- a/src/components/catalog/views/page/layout/CatalogLayoutSpacesView.tsx +++ b/src/components/catalog/views/page/layout/CatalogLayoutSpacesView.tsx @@ -1,11 +1,7 @@ import { NitroPoint } from '@nitrots/nitro-renderer'; import { FC, useEffect } from 'react'; -import { Base } from '../../../../../common/Base'; -import { Column } from '../../../../../common/Column'; -import { Flex } from '../../../../../common/Flex'; -import { Grid } from '../../../../../common/Grid'; -import { Text } from '../../../../../common/Text'; -import { useCatalogContext } from '../../../CatalogContext'; +import { Base, Column, Flex, Grid, Text } from '../../../../../common'; +import { useCatalog } from '../../../../../hooks'; import { CatalogPurchaseWidgetView } from '../widgets/CatalogPurchaseWidgetView'; import { CatalogSpacesWidgetView } from '../widgets/CatalogSpacesWidgetView'; import { CatalogTotalPriceWidget } from '../widgets/CatalogTotalPriceWidget'; @@ -15,7 +11,7 @@ import { CatalogLayoutProps } from './CatalogLayout.types'; export const CatalogLayoutSpacesView: FC = props => { const { page = null } = props; - const { currentOffer = null, roomPreviewer = null } = useCatalogContext(); + const { currentOffer = null, roomPreviewer = null } = useCatalog(); useEffect(() => { diff --git a/src/components/catalog/views/page/layout/CatalogLayoutTrophiesView.tsx b/src/components/catalog/views/page/layout/CatalogLayoutTrophiesView.tsx index 1ecb9192..5db43b78 100644 --- a/src/components/catalog/views/page/layout/CatalogLayoutTrophiesView.tsx +++ b/src/components/catalog/views/page/layout/CatalogLayoutTrophiesView.tsx @@ -1,9 +1,6 @@ import { FC, useEffect, useState } from 'react'; -import { Column } from '../../../../../common/Column'; -import { Flex } from '../../../../../common/Flex'; -import { Grid } from '../../../../../common/Grid'; -import { Text } from '../../../../../common/Text'; -import { useCatalogContext } from '../../../CatalogContext'; +import { Column, Flex, Grid, Text } from '../../../../../common'; +import { useCatalog } from '../../../../../hooks'; import { CatalogItemGridWidgetView } from '../widgets/CatalogItemGridWidgetView'; import { CatalogPurchaseWidgetView } from '../widgets/CatalogPurchaseWidgetView'; import { CatalogTotalPriceWidget } from '../widgets/CatalogTotalPriceWidget'; @@ -14,7 +11,7 @@ export const CatalogLayoutTrophiesView: FC = props => { const { page = null } = props; const [ trophyText, setTrophyText ] = useState(''); - const { currentOffer = null, setPurchaseOptions = null } = useCatalogContext(); + const { currentOffer = null, setPurchaseOptions = null } = useCatalog(); useEffect(() => { diff --git a/src/components/catalog/views/page/layout/CatalogLayoutVipBuyView.tsx b/src/components/catalog/views/page/layout/CatalogLayoutVipBuyView.tsx index 00aaad8e..36a1a72b 100644 --- a/src/components/catalog/views/page/layout/CatalogLayoutVipBuyView.tsx +++ b/src/components/catalog/views/page/layout/CatalogLayoutVipBuyView.tsx @@ -1,18 +1,16 @@ import { ClubOfferData, GetClubOffersMessageComposer, PurchaseFromCatalogComposer } from '@nitrots/nitro-renderer'; import { FC, useCallback, useEffect, useMemo, useState } from 'react'; -import { LocalizeText, SendMessageComposer } from '../../../../../api'; +import { CatalogPurchaseState, LocalizeText, SendMessageComposer } from '../../../../../api'; import { AutoGrid, Button, Column, Flex, Grid, LayoutCurrencyIcon, LayoutGridItem, LayoutLoadingSpinnerView, Text } from '../../../../../common'; import { CatalogEvent, CatalogPurchasedEvent, CatalogPurchaseFailureEvent } from '../../../../../events'; -import { usePurse, UseUiEvent } from '../../../../../hooks'; -import { useCatalogContext } from '../../../CatalogContext'; -import { CatalogPurchaseState } from '../../../common/CatalogPurchaseState'; +import { useCatalog, usePurse, UseUiEvent } from '../../../../../hooks'; import { CatalogLayoutProps } from './CatalogLayout.types'; export const CatalogLayoutVipBuyView: FC = props => { const [ pendingOffer, setPendingOffer ] = useState(null); const [ purchaseState, setPurchaseState ] = useState(CatalogPurchaseState.NONE); - const { currentPage = null, catalogOptions = null } = useCatalogContext(); + const { currentPage = null, catalogOptions = null } = useCatalog(); const { purse = null, getCurrencyAmount = null } = usePurse(); const { clubOffers = null } = catalogOptions; diff --git a/src/components/catalog/views/page/layout/GetCatalogLayout.tsx b/src/components/catalog/views/page/layout/GetCatalogLayout.tsx index 78674428..5748ef88 100644 --- a/src/components/catalog/views/page/layout/GetCatalogLayout.tsx +++ b/src/components/catalog/views/page/layout/GetCatalogLayout.tsx @@ -1,4 +1,4 @@ -import { ICatalogPage } from '../../../common/ICatalogPage'; +import { ICatalogPage } from '../../../../../api'; import { CatalogLayoutProps } from './CatalogLayout.types'; import { CatalogLayoutBadgeDisplayView } from './CatalogLayoutBadgeDisplayView'; import { CatalogLayoutDefaultView } from './CatalogLayoutDefaultView'; diff --git a/src/components/catalog/views/page/layout/frontpage4/CatalogLayoutFrontpage4View.tsx b/src/components/catalog/views/page/layout/frontpage4/CatalogLayoutFrontpage4View.tsx index 807adbf8..f2e1da6c 100644 --- a/src/components/catalog/views/page/layout/frontpage4/CatalogLayoutFrontpage4View.tsx +++ b/src/components/catalog/views/page/layout/frontpage4/CatalogLayoutFrontpage4View.tsx @@ -1,9 +1,8 @@ import { FrontPageItem } from '@nitrots/nitro-renderer'; import { FC, useCallback, useEffect } from 'react'; import { CreateLinkEvent } from '../../../../../../api'; -import { Column } from '../../../../../../common/Column'; -import { Grid } from '../../../../../../common/Grid'; -import { useCatalogContext } from '../../../../CatalogContext'; +import { Column, Grid } from '../../../../../../common'; +import { useCatalog } from '../../../../../../hooks'; import { CatalogRedeemVoucherView } from '../../common/CatalogRedeemVoucherView'; import { CatalogLayoutProps } from '../CatalogLayout.types'; import { CatalogLayoutFrontPageItemView } from './CatalogLayoutFrontPageItemView'; @@ -11,7 +10,7 @@ import { CatalogLayoutFrontPageItemView } from './CatalogLayoutFrontPageItemView export const CatalogLayoutFrontpage4View: FC = props => { const { page = null, hideNavigation = null } = props; - const { frontPageItems = [] } = useCatalogContext(); + const { frontPageItems = [] } = useCatalog(); const selectItem = useCallback((item: FrontPageItem) => { diff --git a/src/components/catalog/views/page/layout/marketplace/MarketplacePostOfferView.tsx b/src/components/catalog/views/page/layout/marketplace/MarketplacePostOfferView.tsx index 9b73be89..4ad0545f 100644 --- a/src/components/catalog/views/page/layout/marketplace/MarketplacePostOfferView.tsx +++ b/src/components/catalog/views/page/layout/marketplace/MarketplacePostOfferView.tsx @@ -3,14 +3,13 @@ import { FC, useCallback, useEffect, useState } from 'react'; import { FurnitureItem, LocalizeText, NotificationUtilities, ProductTypeEnum, SendMessageComposer } from '../../../../../../api'; import { Base, Button, Column, Grid, LayoutFurniImageView, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../../../../common'; import { CatalogPostMarketplaceOfferEvent } from '../../../../../../events'; -import { UseMessageEventHook, UseUiEvent } from '../../../../../../hooks'; -import { useCatalogContext } from '../../../../CatalogContext'; +import { useCatalog, UseMessageEventHook, UseUiEvent } from '../../../../../../hooks'; export const MarketplacePostOfferView : FC<{}> = props => { const [ item, setItem ] = useState(null); const [ askingPrice, setAskingPrice ] = useState(0); - const { catalogOptions = null, setCatalogOptions = null } = useCatalogContext(); + const { catalogOptions = null, setCatalogOptions = null } = useCatalog(); const { marketplaceConfiguration = null } = catalogOptions; const onMarketplaceConfigurationEvent = useCallback((event: MarketplaceConfigurationEvent) => diff --git a/src/components/catalog/views/page/layout/pets/CatalogLayoutPetPurchaseView.tsx b/src/components/catalog/views/page/layout/pets/CatalogLayoutPetPurchaseView.tsx index a9bd44a5..694b8e26 100644 --- a/src/components/catalog/views/page/layout/pets/CatalogLayoutPetPurchaseView.tsx +++ b/src/components/catalog/views/page/layout/pets/CatalogLayoutPetPurchaseView.tsx @@ -1,11 +1,9 @@ import { ApproveNameMessageComposer } from '@nitrots/nitro-renderer'; import { FC, useCallback, useState } from 'react'; -import { LocalizeText, SendMessageComposer } from '../../../../../../api'; +import { IPurchasableOffer, LocalizeText, Offer, SendMessageComposer } from '../../../../../../api'; import { Column, Flex, LayoutCurrencyIcon, Text } from '../../../../../../common'; import { CatalogPurchasedEvent } from '../../../../../../events'; import { UseUiEvent } from '../../../../../../hooks'; -import { IPurchasableOffer } from '../../../../common/IPurchasableOffer'; -import { Offer } from '../../../../common/Offer'; import { CatalogPurchaseWidgetView } from '../../widgets/CatalogPurchaseWidgetView'; import { CatalogPetNameApprovalView } from './CatalogPetNameApprovalView'; diff --git a/src/components/catalog/views/page/layout/pets/CatalogLayoutPetView.tsx b/src/components/catalog/views/page/layout/pets/CatalogLayoutPetView.tsx index 665a7a4a..b0f23bd7 100644 --- a/src/components/catalog/views/page/layout/pets/CatalogLayoutPetView.tsx +++ b/src/components/catalog/views/page/layout/pets/CatalogLayoutPetView.tsx @@ -1,12 +1,10 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { ApproveNameMessageComposer, ColorConverter, GetSellablePetPalettesComposer, PurchaseFromCatalogComposer, SellablePetPaletteData } from '@nitrots/nitro-renderer'; import { FC, useCallback, useEffect, useMemo, useState } from 'react'; -import { LocalizeText, SendMessageComposer } from '../../../../../../api'; +import { GetPetAvailableColors, GetPetIndexFromLocalization, LocalizeText, SendMessageComposer } from '../../../../../../api'; import { AutoGrid, Base, Button, Column, Flex, Grid, LayoutGridItem, LayoutPetImageView, Text } from '../../../../../../common'; import { CatalogNameResultEvent, CatalogPurchaseFailureEvent, CatalogWidgetEvent } from '../../../../../../events'; -import { DispatchUiEvent, UseUiEvent } from '../../../../../../hooks'; -import { useCatalogContext } from '../../../../CatalogContext'; -import { GetPetAvailableColors, GetPetIndexFromLocalization } from '../../../../common/CatalogUtilities'; +import { DispatchUiEvent, useCatalog, UseUiEvent } from '../../../../../../hooks'; import { CatalogAddOnBadgeWidgetView } from '../../widgets/CatalogAddOnBadgeWidgetView'; import { CatalogPurchaseWidgetView } from '../../widgets/CatalogPurchaseWidgetView'; import { CatalogTotalPriceWidget } from '../../widgets/CatalogTotalPriceWidget'; @@ -25,7 +23,7 @@ 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 } = useCatalogContext(); + const { currentOffer = null, setCurrentOffer = null, setPurchaseOptions = null, catalogOptions = null, roomPreviewer = null } = useCatalog(); const { petPalettes = null } = catalogOptions; const getColor = useMemo(() => diff --git a/src/components/catalog/views/page/layout/vip-gifts/CatalogLayoutVipGiftsView.tsx b/src/components/catalog/views/page/layout/vip-gifts/CatalogLayoutVipGiftsView.tsx index 3b760d27..e339ec80 100644 --- a/src/components/catalog/views/page/layout/vip-gifts/CatalogLayoutVipGiftsView.tsx +++ b/src/components/catalog/views/page/layout/vip-gifts/CatalogLayoutVipGiftsView.tsx @@ -2,15 +2,14 @@ import { SelectClubGiftComposer } from '@nitrots/nitro-renderer'; import { FC, useCallback } from 'react'; import { LocalizeText, NotificationUtilities, SendMessageComposer } from '../../../../../../api'; import { AutoGrid, Text } from '../../../../../../common'; -import { usePurse } from '../../../../../../hooks'; -import { useCatalogContext } from '../../../../CatalogContext'; +import { useCatalog, usePurse } from '../../../../../../hooks'; import { CatalogLayoutProps } from '../CatalogLayout.types'; import { VipGiftItem } from './VipGiftItemView'; export const CatalogLayoutVipGiftsView: FC = props => { const { purse = null } = usePurse(); - const { catalogOptions = null, setCatalogOptions = null } = useCatalogContext(); + const { catalogOptions = null, setCatalogOptions = null } = useCatalog(); const { clubGifts = null } = catalogOptions; const giftsAvailable = useCallback(() => diff --git a/src/components/catalog/views/page/widgets/CatalogAddOnBadgeWidgetView.tsx b/src/components/catalog/views/page/widgets/CatalogAddOnBadgeWidgetView.tsx index 0b041536..38892cea 100644 --- a/src/components/catalog/views/page/widgets/CatalogAddOnBadgeWidgetView.tsx +++ b/src/components/catalog/views/page/widgets/CatalogAddOnBadgeWidgetView.tsx @@ -1,6 +1,6 @@ import { FC } from 'react'; import { BaseProps, LayoutBadgeImageView } from '../../../../../common'; -import { useCatalogContext } from '../../../CatalogContext'; +import { useCatalog } from '../../../../../hooks'; interface CatalogAddOnBadgeWidgetViewProps extends BaseProps { @@ -10,7 +10,7 @@ interface CatalogAddOnBadgeWidgetViewProps extends BaseProps export const CatalogAddOnBadgeWidgetView: FC = props => { const { ...rest } = props; - const { currentOffer = null } = useCatalogContext(); + const { currentOffer = null } = useCatalog(); if(!currentOffer || !currentOffer.badgeCode || !currentOffer.badgeCode.length) return null; diff --git a/src/components/catalog/views/page/widgets/CatalogBadgeSelectorWidgetView.tsx b/src/components/catalog/views/page/widgets/CatalogBadgeSelectorWidgetView.tsx index b3c6c028..04891dde 100644 --- a/src/components/catalog/views/page/widgets/CatalogBadgeSelectorWidgetView.tsx +++ b/src/components/catalog/views/page/widgets/CatalogBadgeSelectorWidgetView.tsx @@ -1,8 +1,7 @@ import { StringDataType } from '@nitrots/nitro-renderer'; import { FC, useEffect, useMemo, useState } from 'react'; import { AutoGrid, AutoGridProps, LayoutBadgeImageView, LayoutGridItem } from '../../../../../common'; -import { useInventoryBadges } from '../../../../../hooks'; -import { useCatalogContext } from '../../../CatalogContext'; +import { useCatalog, useInventoryBadges } from '../../../../../hooks'; const EXCLUDED_BADGE_CODES: string[] = []; @@ -16,7 +15,7 @@ export const CatalogBadgeSelectorWidgetView: FC(null); - const { currentOffer = null, setPurchaseOptions = null } = useCatalogContext(); + const { currentOffer = null, setPurchaseOptions = null } = useCatalog(); const { badgeCodes = [], activate = null, deactivate = null } = useInventoryBadges(); const previewStuffData = useMemo(() => diff --git a/src/components/catalog/views/page/widgets/CatalogBundleGridWidgetView.tsx b/src/components/catalog/views/page/widgets/CatalogBundleGridWidgetView.tsx index e684387b..d98ff1dd 100644 --- a/src/components/catalog/views/page/widgets/CatalogBundleGridWidgetView.tsx +++ b/src/components/catalog/views/page/widgets/CatalogBundleGridWidgetView.tsx @@ -1,7 +1,6 @@ import { FC } from 'react'; -import { AutoGrid, AutoGridProps } from '../../../../../common/AutoGrid'; -import { LayoutGridItem } from '../../../../../common/layout/LayoutGridItem'; -import { useCatalogContext } from '../../../CatalogContext'; +import { AutoGrid, AutoGridProps, LayoutGridItem } from '../../../../../common'; +import { useCatalog } from '../../../../../hooks'; interface CatalogBundleGridWidgetViewProps extends AutoGridProps { @@ -11,7 +10,7 @@ interface CatalogBundleGridWidgetViewProps extends AutoGridProps export const CatalogBundleGridWidgetView: FC = props => { const { columnCount = 5, children = null, ...rest } = props; - const { currentOffer = null } = useCatalogContext(); + const { currentOffer = null } = useCatalog(); if(!currentOffer) return null; diff --git a/src/components/catalog/views/page/widgets/CatalogFirstProductSelectorWidgetView.tsx b/src/components/catalog/views/page/widgets/CatalogFirstProductSelectorWidgetView.tsx index dfab4d85..a0d71033 100644 --- a/src/components/catalog/views/page/widgets/CatalogFirstProductSelectorWidgetView.tsx +++ b/src/components/catalog/views/page/widgets/CatalogFirstProductSelectorWidgetView.tsx @@ -1,9 +1,9 @@ import { FC, useEffect } from 'react'; -import { useCatalogContext } from '../../../CatalogContext'; +import { useCatalog } from '../../../../../hooks'; export const CatalogFirstProductSelectorWidgetView: FC<{}> = props => { - const { currentPage = null, setCurrentOffer = null } = useCatalogContext(); + const { currentPage = null, setCurrentOffer = null } = useCatalog(); useEffect(() => { diff --git a/src/components/catalog/views/page/widgets/CatalogGuildBadgeWidgetView.tsx b/src/components/catalog/views/page/widgets/CatalogGuildBadgeWidgetView.tsx index ae7deb55..db893ad3 100644 --- a/src/components/catalog/views/page/widgets/CatalogGuildBadgeWidgetView.tsx +++ b/src/components/catalog/views/page/widgets/CatalogGuildBadgeWidgetView.tsx @@ -1,7 +1,7 @@ import { StringDataType } from '@nitrots/nitro-renderer'; import { FC, useMemo } from 'react'; import { BaseProps, LayoutBadgeImageView } from '../../../../../common'; -import { useCatalogContext } from '../../../CatalogContext'; +import { useCatalog } from '../../../../../hooks'; interface CatalogGuildBadgeWidgetViewProps extends BaseProps { @@ -11,7 +11,7 @@ interface CatalogGuildBadgeWidgetViewProps extends BaseProps export const CatalogGuildBadgeWidgetView: FC = props => { const { ...rest } = props; - const { currentOffer = null, purchaseOptions = null } = useCatalogContext(); + const { currentOffer = null, purchaseOptions = null } = useCatalog(); const { previewStuffData = null } = purchaseOptions; const badgeCode = useMemo(() => diff --git a/src/components/catalog/views/page/widgets/CatalogGuildSelectorWidgetView.tsx b/src/components/catalog/views/page/widgets/CatalogGuildSelectorWidgetView.tsx index 919fa038..d097bd36 100644 --- a/src/components/catalog/views/page/widgets/CatalogGuildSelectorWidgetView.tsx +++ b/src/components/catalog/views/page/widgets/CatalogGuildSelectorWidgetView.tsx @@ -2,12 +2,12 @@ import { CatalogGroupsComposer, StringDataType } from '@nitrots/nitro-renderer'; import { FC, useEffect, useMemo, useState } from 'react'; import { LocalizeText, SendMessageComposer } from '../../../../../api'; import { Base, Button, Flex } from '../../../../../common'; -import { useCatalogContext } from '../../../CatalogContext'; +import { useCatalog } from '../../../../../hooks'; export const CatalogGuildSelectorWidgetView: FC<{}> = props => { const [ selectedGroupIndex, setSelectedGroupIndex ] = useState(0); - const { currentOffer = null, catalogOptions = null, setPurchaseOptions = null } = useCatalogContext(); + const { currentOffer = null, catalogOptions = null, setPurchaseOptions = null } = useCatalog(); const { groups = null } = catalogOptions; const previewStuffData = useMemo(() => diff --git a/src/components/catalog/views/page/widgets/CatalogItemGridWidgetView.tsx b/src/components/catalog/views/page/widgets/CatalogItemGridWidgetView.tsx index d5e941ca..933dede6 100644 --- a/src/components/catalog/views/page/widgets/CatalogItemGridWidgetView.tsx +++ b/src/components/catalog/views/page/widgets/CatalogItemGridWidgetView.tsx @@ -1,8 +1,7 @@ import { FC } from 'react'; -import { ProductTypeEnum } from '../../../../../api'; +import { IPurchasableOffer, ProductTypeEnum } from '../../../../../api'; import { AutoGrid, AutoGridProps } from '../../../../../common'; -import { useCatalogContext } from '../../../CatalogContext'; -import { IPurchasableOffer } from '../../../common/IPurchasableOffer'; +import { useCatalog } from '../../../../../hooks'; import { CatalogGridOfferView } from '../common/CatalogGridOfferView'; interface CatalogItemGridWidgetViewProps extends AutoGridProps @@ -13,7 +12,7 @@ interface CatalogItemGridWidgetViewProps extends AutoGridProps export const CatalogItemGridWidgetView: FC = props => { const { columnCount = 5, children = null, ...rest } = props; - const { currentOffer = null, setCurrentOffer = null, currentPage = null, setPurchaseOptions = null } = useCatalogContext(); + const { currentOffer = null, setCurrentOffer = null, currentPage = null, setPurchaseOptions = null } = useCatalog(); if(!currentPage) return null; @@ -40,7 +39,7 @@ export const CatalogItemGridWidgetView: FC = pro return ( - { currentPage.offers && (currentPage.offers.length > 0) && currentPage.offers.map((offer, index) => selectOffer(offer) } />) } + { currentPage.offers && (currentPage.offers.length > 0) && currentPage.offers.map((offer, index) => ) } { children } ); diff --git a/src/components/catalog/views/page/widgets/CatalogLimitedItemWidgetView.tsx b/src/components/catalog/views/page/widgets/CatalogLimitedItemWidgetView.tsx index 035d7d44..70b52cbd 100644 --- a/src/components/catalog/views/page/widgets/CatalogLimitedItemWidgetView.tsx +++ b/src/components/catalog/views/page/widgets/CatalogLimitedItemWidgetView.tsx @@ -1,12 +1,12 @@ import { FC } from 'react'; +import { Offer } from '../../../../../api'; import { Base, BaseProps, LayoutLimitedEditionCompletePlateView } from '../../../../../common'; -import { useCatalogContext } from '../../../CatalogContext'; -import { Offer } from '../../../common/Offer'; +import { useCatalog } from '../../../../../hooks'; export const CatalogLimitedItemWidgetView: FC> = props => { const { children = null, ...rest } = props; - const { currentOffer = null } = useCatalogContext(); + const { currentOffer = null } = useCatalog(); if(!currentOffer || (currentOffer.pricingModel !== Offer.PRICING_MODEL_SINGLE) || !currentOffer.product.isUniqueLimitedItem) return null; diff --git a/src/components/catalog/views/page/widgets/CatalogPriceDisplayWidgetView.tsx b/src/components/catalog/views/page/widgets/CatalogPriceDisplayWidgetView.tsx index 7cf8c76b..0ca15604 100644 --- a/src/components/catalog/views/page/widgets/CatalogPriceDisplayWidgetView.tsx +++ b/src/components/catalog/views/page/widgets/CatalogPriceDisplayWidgetView.tsx @@ -1,8 +1,8 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { FC } from 'react'; +import { IPurchasableOffer } from '../../../../../api'; import { Flex, LayoutCurrencyIcon, Text } from '../../../../../common'; -import { useCatalogContext } from '../../../CatalogContext'; -import { IPurchasableOffer } from '../../../common/IPurchasableOffer'; +import { useCatalog } from '../../../../../hooks'; interface CatalogPriceDisplayWidgetViewProps { @@ -13,7 +13,7 @@ interface CatalogPriceDisplayWidgetViewProps export const CatalogPriceDisplayWidgetView: FC = props => { const { offer = null, separator = false } = props; - const { purchaseOptions = null } = useCatalogContext(); + const { purchaseOptions = null } = useCatalog(); const { quantity = 1 } = purchaseOptions; if(!offer) return null; diff --git a/src/components/catalog/views/page/widgets/CatalogPurchaseWidgetView.tsx b/src/components/catalog/views/page/widgets/CatalogPurchaseWidgetView.tsx index 7a874acc..93637305 100644 --- a/src/components/catalog/views/page/widgets/CatalogPurchaseWidgetView.tsx +++ b/src/components/catalog/views/page/widgets/CatalogPurchaseWidgetView.tsx @@ -1,12 +1,9 @@ import { PurchaseFromCatalogComposer } from '@nitrots/nitro-renderer'; import { FC, useCallback, useEffect, useMemo, useState } from 'react'; -import { CreateLinkEvent, GetClubMemberLevel, LocalizeText, SendMessageComposer } from '../../../../../api'; +import { CatalogPurchaseState, CreateLinkEvent, GetClubMemberLevel, LocalizeText, LocalStorageKeys, Offer, SendMessageComposer } from '../../../../../api'; import { Button, LayoutLoadingSpinnerView } from '../../../../../common'; -import { CatalogEvent, CatalogInitGiftEvent, CatalogInitPurchaseEvent, CatalogPurchasedEvent, CatalogPurchaseFailureEvent, CatalogPurchaseNotAllowedEvent, CatalogPurchaseSoldOutEvent, CatalogWidgetEvent } from '../../../../../events'; -import { DispatchUiEvent, usePurse, UseUiEvent } from '../../../../../hooks'; -import { useCatalogContext } from '../../../CatalogContext'; -import { CatalogPurchaseState } from '../../../common/CatalogPurchaseState'; -import { Offer } from '../../../common/Offer'; +import { CatalogEvent, CatalogInitGiftEvent, CatalogPurchasedEvent, CatalogPurchaseFailureEvent, CatalogPurchaseNotAllowedEvent, CatalogPurchaseSoldOutEvent } from '../../../../../events'; +import { DispatchUiEvent, useCatalog, useLocalStorage, usePurse, UseUiEvent } from '../../../../../hooks'; interface CatalogPurchaseWidgetViewProps { @@ -19,19 +16,10 @@ export const CatalogPurchaseWidgetView: FC = pro const { noGiftOption = false, purchaseCallback = null } = props; const [ purchaseWillBeGift, setPurchaseWillBeGift ] = useState(false); const [ purchaseState, setPurchaseState ] = useState(CatalogPurchaseState.NONE); - const { currentOffer = null, currentPage = null, purchaseOptions = null, setPurchaseOptions = null } = useCatalogContext(); + const [ catalogSkipPurchaseConfirmation, setCatalogSkipPurchaseConfirmation ] = useLocalStorage(LocalStorageKeys.CATALOG_SKIP_PURCHASE_CONFIRMATION, false); + const { currentOffer = null, currentPage = null, purchaseOptions = null, setPurchaseOptions = null } = useCatalog(); const { getCurrencyAmount = null } = usePurse(); - const onCatalogInitPurchaseEvent = useCallback((event: CatalogInitPurchaseEvent) => - { - if(!currentOffer) return; - - // show purchase confirmation - // offer, page.pageId, extraData, quantity, previewStuffData, null, true, null - }, [ currentOffer ]); - - UseUiEvent(CatalogWidgetEvent.INIT_PURCHASE, onCatalogInitPurchaseEvent); - const onCatalogEvent = useCallback((event: CatalogEvent) => { switch(event.type) diff --git a/src/components/catalog/views/page/widgets/CatalogSimplePriceWidgetView.tsx b/src/components/catalog/views/page/widgets/CatalogSimplePriceWidgetView.tsx index 80b5dafb..694507df 100644 --- a/src/components/catalog/views/page/widgets/CatalogSimplePriceWidgetView.tsx +++ b/src/components/catalog/views/page/widgets/CatalogSimplePriceWidgetView.tsx @@ -1,6 +1,6 @@ import { FC } from 'react'; -import { Flex, FlexProps } from '../../../../../common/Flex'; -import { useCatalogContext } from '../../../CatalogContext'; +import { Flex, FlexProps } from '../../../../../common'; +import { useCatalog } from '../../../../../hooks'; import { CatalogPriceDisplayWidgetView } from './CatalogPriceDisplayWidgetView'; interface CatalogSimplePriceWidgetViewProps extends FlexProps @@ -11,7 +11,7 @@ interface CatalogSimplePriceWidgetViewProps extends FlexProps export const CatalogSimplePriceWidgetView: FC = props => { const { gap = 1, ...rest } = props; - const { currentOffer = null } = useCatalogContext(); + const { currentOffer = null } = useCatalog(); return ( diff --git a/src/components/catalog/views/page/widgets/CatalogSpacesWidgetView.tsx b/src/components/catalog/views/page/widgets/CatalogSpacesWidgetView.tsx index d2dc9550..fdc3f5f4 100644 --- a/src/components/catalog/views/page/widgets/CatalogSpacesWidgetView.tsx +++ b/src/components/catalog/views/page/widgets/CatalogSpacesWidgetView.tsx @@ -1,9 +1,7 @@ import { FC, useEffect, useState } from 'react'; -import { LocalizeText, ProductTypeEnum } from '../../../../../api'; +import { IPurchasableOffer, LocalizeText, Offer, ProductTypeEnum } from '../../../../../api'; import { AutoGrid, AutoGridProps, Button, ButtonGroup } from '../../../../../common'; -import { useCatalogContext } from '../../../CatalogContext'; -import { IPurchasableOffer } from '../../../common/IPurchasableOffer'; -import { Offer } from '../../../common/Offer'; +import { useCatalog } from '../../../../../hooks'; import { CatalogGridOfferView } from '../common/CatalogGridOfferView'; interface CatalogSpacesWidgetViewProps extends AutoGridProps @@ -19,7 +17,21 @@ export const CatalogSpacesWidgetView: FC = props = const [ groupedOffers, setGroupedOffers ] = useState(null); const [ selectedGroupIndex, setSelectedGroupIndex ] = useState(-1); const [ selectedOfferForGroup, setSelectedOfferForGroup ] = useState(null); - const { currentPage = null, currentOffer = null, setCurrentOffer = null, setPurchaseOptions = null } = useCatalogContext(); + const { currentPage = null, currentOffer = null, setCurrentOffer = null, setPurchaseOptions = null } = useCatalog(); + + const setSelectedOffer = (offer: IPurchasableOffer) => + { + if(!offer) return; + + setSelectedOfferForGroup(prevValue => + { + const newValue = [ ...prevValue ]; + + newValue[selectedGroupIndex] = offer; + + return newValue; + }); + } useEffect(() => { @@ -89,22 +101,7 @@ export const CatalogSpacesWidgetView: FC = props = { SPACES_GROUP_NAMES.map((name, index) => ) } - { offers && (offers.length > 0) && offers.map((offer, index) => - { - const setSelectedOffer = () => - { - setSelectedOfferForGroup(prevValue => - { - const newValue = [ ...prevValue ]; - - newValue[selectedGroupIndex] = offer; - - return newValue; - }); - } - - return ; - }) } + { offers && (offers.length > 0) && offers.map((offer, index) => setSelectedOffer(offer) } />) } { children } diff --git a/src/components/catalog/views/page/widgets/CatalogSpinnerWidgetView.tsx b/src/components/catalog/views/page/widgets/CatalogSpinnerWidgetView.tsx index df50e347..2749fa7b 100644 --- a/src/components/catalog/views/page/widgets/CatalogSpinnerWidgetView.tsx +++ b/src/components/catalog/views/page/widgets/CatalogSpinnerWidgetView.tsx @@ -1,16 +1,15 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { FC } from 'react'; import { LocalizeText } from '../../../../../api'; -import { Flex } from '../../../../../common/Flex'; -import { Text } from '../../../../../common/Text'; -import { useCatalogContext } from '../../../CatalogContext'; +import { Flex, Text } from '../../../../../common'; +import { useCatalog } from '../../../../../hooks'; const MIN_VALUE: number = 1; const MAX_VALUE: number = 100; export const CatalogSpinnerWidgetView: FC<{}> = props => { - const { currentOffer = null, purchaseOptions = null, setPurchaseOptions = null } = useCatalogContext(); + const { currentOffer = null, purchaseOptions = null, setPurchaseOptions = null } = useCatalog(); const { quantity = 1 } = purchaseOptions; const updateQuantity = (value: number) => diff --git a/src/components/catalog/views/page/widgets/CatalogTotalPriceWidget.tsx b/src/components/catalog/views/page/widgets/CatalogTotalPriceWidget.tsx index ae10d810..b3f935ae 100644 --- a/src/components/catalog/views/page/widgets/CatalogTotalPriceWidget.tsx +++ b/src/components/catalog/views/page/widgets/CatalogTotalPriceWidget.tsx @@ -1,6 +1,6 @@ import { FC } from 'react'; -import { Column, ColumnProps } from '../../../../../common/Column'; -import { useCatalogContext } from '../../../CatalogContext'; +import { Column, ColumnProps } from '../../../../../common'; +import { useCatalog } from '../../../../../hooks'; import { CatalogPriceDisplayWidgetView } from './CatalogPriceDisplayWidgetView'; interface CatalogSimplePriceWidgetViewProps extends ColumnProps @@ -10,7 +10,7 @@ interface CatalogSimplePriceWidgetViewProps extends ColumnProps export const CatalogTotalPriceWidget: FC = props => { const { gap = 1, ...rest } = props; - const { currentOffer = null } = useCatalogContext(); + const { currentOffer = null } = useCatalog(); return ( diff --git a/src/components/catalog/views/page/widgets/CatalogViewProductWidgetView.tsx b/src/components/catalog/views/page/widgets/CatalogViewProductWidgetView.tsx index 27e21c23..620ece15 100644 --- a/src/components/catalog/views/page/widgets/CatalogViewProductWidgetView.tsx +++ b/src/components/catalog/views/page/widgets/CatalogViewProductWidgetView.tsx @@ -1,14 +1,12 @@ import { Vector3d } from '@nitrots/nitro-renderer'; import { FC, useEffect } from 'react'; -import { GetAvatarRenderManager, GetSessionDataManager, ProductTypeEnum } from '../../../../../api'; +import { FurniCategory, GetAvatarRenderManager, GetSessionDataManager, Offer, ProductTypeEnum } from '../../../../../api'; import { AutoGrid, Column, LayoutGridItem, LayoutRoomPreviewerView } from '../../../../../common'; -import { useCatalogContext } from '../../../CatalogContext'; -import { FurniCategory } from '../../../common/FurniCategory'; -import { Offer } from '../../../common/Offer'; +import { useCatalog } from '../../../../../hooks'; export const CatalogViewProductWidgetView: FC<{}> = props => { - const { currentOffer = null, roomPreviewer = null, purchaseOptions = null } = useCatalogContext(); + const { currentOffer = null, roomPreviewer = null, purchaseOptions = null } = useCatalog(); const { previewStuffData = null } = purchaseOptions; useEffect(() => diff --git a/src/components/groups/views/GroupInformationView.tsx b/src/components/groups/views/GroupInformationView.tsx index 1021bf4b..e330898a 100644 --- a/src/components/groups/views/GroupInformationView.tsx +++ b/src/components/groups/views/GroupInformationView.tsx @@ -1,8 +1,7 @@ import { GroupInformationParser, GroupRemoveMemberComposer } from '@nitrots/nitro-renderer'; import { FC, useCallback } from 'react'; -import { CreateLinkEvent, GetGroupManager, GetGroupMembers, GetSessionDataManager, LocalizeText, NotificationUtilities, SendMessageComposer, TryJoinGroup, TryVisitRoom } from '../../../api'; +import { CatalogPageName, CreateLinkEvent, GetGroupManager, GetGroupMembers, GetSessionDataManager, LocalizeText, NotificationUtilities, SendMessageComposer, TryJoinGroup, TryVisitRoom } from '../../../api'; import { Button, Column, Flex, Grid, GridProps, LayoutBadgeImageView, Text } from '../../../common'; -import { CatalogPageName } from '../../catalog/common/CatalogPageName'; import { GroupMembershipType } from '../common/GroupMembershipType'; import { GroupType } from '../common/GroupType'; diff --git a/src/components/user-settings/UserSettingsView.tsx b/src/components/user-settings/UserSettingsView.tsx index 6768c898..3564203b 100644 --- a/src/components/user-settings/UserSettingsView.tsx +++ b/src/components/user-settings/UserSettingsView.tsx @@ -3,12 +3,14 @@ import { ILinkEventTracker, NitroSettingsEvent, UserSettingsCameraFollowComposer import { FC, useCallback, useEffect, useState } from 'react'; import { AddEventLinkTracker, LocalizeText, RemoveLinkEventTracker, SendMessageComposer } from '../../api'; import { Column, Flex, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../common'; -import { DispatchMainEvent, DispatchUiEvent, UseMessageEventHook } from '../../hooks'; +import { DispatchMainEvent, DispatchUiEvent, useCatalogPlaceMultipleItems, useCatalogSkipPurchaseConfirmation, UseMessageEventHook } from '../../hooks'; export const UserSettingsView: FC<{}> = props => { const [ isVisible, setIsVisible ] = useState(false); const [ userSettings, setUserSettings ] = useState(null); + const [ catalogPlaceMultipleObjects, setCatalogPlaceMultipleObjects ] = useCatalogPlaceMultipleItems(); + const [ catalogSkipPurchaseConfirmation, setCatalogSkipPurchaseConfirmation ] = useCatalogSkipPurchaseConfirmation(); const onUserSettingsEvent = useCallback((event: UserSettingsEvent) => { @@ -141,6 +143,14 @@ export const UserSettingsView: FC<{}> = props => processAction('camera_follow', event.target.checked) } /> { LocalizeText('memenu.settings.other.disable.room.camera.follow') } + + setCatalogPlaceMultipleObjects(event.target.checked) } /> + { LocalizeText('memenu.settings.other.place.multiple.objects') } + + + setCatalogSkipPurchaseConfirmation(event.target.checked) } /> + { LocalizeText('memenu.settings.other.skip.purchase.confirmation') } + { LocalizeText('widget.memenu.settings.volume') } diff --git a/src/events/catalog/CatalogInitPurchaseEvent.ts b/src/events/catalog/CatalogInitPurchaseEvent.ts deleted file mode 100644 index 2b2661fa..00000000 --- a/src/events/catalog/CatalogInitPurchaseEvent.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { NitroEvent } from '@nitrots/nitro-renderer'; -import { CatalogWidgetEvent } from './CatalogWidgetEvent'; - -export class CatalogInitPurchaseEvent extends NitroEvent -{ - private _enableBuyAsGift: boolean = true; - private _userName: string; - - constructor(enableBuyAsGift: boolean = true, userName: string = null) - { - super(CatalogWidgetEvent.INIT_PURCHASE); - - this._enableBuyAsGift = enableBuyAsGift; - this._userName = userName; - } - - public get enableBuyAsGift(): boolean - { - return this._enableBuyAsGift; - } - - public get userName(): string - { - return this._userName; - } -} diff --git a/src/events/catalog/CatalogWidgetEvent.ts b/src/events/catalog/CatalogWidgetEvent.ts index 57df2d7b..9f3f5a41 100644 --- a/src/events/catalog/CatalogWidgetEvent.ts +++ b/src/events/catalog/CatalogWidgetEvent.ts @@ -14,7 +14,6 @@ export class CatalogWidgetEvent extends NitroEvent public static APPROVE_RESULT: string = 'CWE_CWE_APPROVE_RESULT'; public static PURCHASE_OVERRIDE: string = 'CWE_PURCHASE_OVERRIDE'; public static SELLABLE_PET_PALETTES: string = 'CWE_SELLABLE_PET_PALETTES'; - public static INIT_PURCHASE: string = 'CWE_INIT_PURCHASE'; public static UPDATE_ROOM_PREVIEW: string = 'CWE_UPDATE_ROOM_PREVIEW'; public static GUILD_SELECTED: string = 'CWE_GUILD_SELECTED'; public static TOTAL_PRICE_WIDGET_INITIALIZED: string = 'CWE_TOTAL_PRICE_WIDGET_INITIALIZED'; diff --git a/src/events/catalog/SetRoomPreviewerStuffDataEvent.ts b/src/events/catalog/SetRoomPreviewerStuffDataEvent.ts index 03e11862..5332dfd9 100644 --- a/src/events/catalog/SetRoomPreviewerStuffDataEvent.ts +++ b/src/events/catalog/SetRoomPreviewerStuffDataEvent.ts @@ -1,5 +1,5 @@ import { IObjectData, NitroEvent } from '@nitrots/nitro-renderer'; -import { IPurchasableOffer } from '../../components/catalog/common/IPurchasableOffer'; +import { IPurchasableOffer } from '../../api'; export class SetRoomPreviewerStuffDataEvent extends NitroEvent { diff --git a/src/events/catalog/index.ts b/src/events/catalog/index.ts index 1e2cd919..d8bc3f33 100644 --- a/src/events/catalog/index.ts +++ b/src/events/catalog/index.ts @@ -1,7 +1,6 @@ export * from './CatalogEvent'; export * from './CatalogGiftReceiverNotFoundEvent'; export * from './CatalogInitGiftEvent'; -export * from './CatalogInitPurchaseEvent'; export * from './CatalogNameResultEvent'; export * from './CatalogPostMarketplaceOfferEvent'; export * from './CatalogPurchasedEvent'; diff --git a/src/events/index.ts b/src/events/index.ts index 288b2364..40e7a162 100644 --- a/src/events/index.ts +++ b/src/events/index.ts @@ -1,6 +1,7 @@ export * from './catalog'; export * from './guide-tool'; export * from './help'; +export * from './inventory'; export * from './mod-tools'; export * from './notification-center'; export * from './room-widgets'; diff --git a/src/events/inventory/InventoryFurniAddedEvent.ts b/src/events/inventory/InventoryFurniAddedEvent.ts new file mode 100644 index 00000000..409f0be8 --- /dev/null +++ b/src/events/inventory/InventoryFurniAddedEvent.ts @@ -0,0 +1,14 @@ +import { NitroEvent } from '@nitrots/nitro-renderer'; + +export class InventoryFurniAddedEvent extends NitroEvent +{ + public static FURNI_ADDED: string = 'IFAE_FURNI_ADDED'; + + constructor( + public readonly id: number, + public readonly spriteId: number, + public readonly category: number) + { + super(InventoryFurniAddedEvent.FURNI_ADDED); + } +} diff --git a/src/events/inventory/index.ts b/src/events/inventory/index.ts new file mode 100644 index 00000000..58503ead --- /dev/null +++ b/src/events/inventory/index.ts @@ -0,0 +1 @@ +export * from './InventoryFurniAddedEvent'; diff --git a/src/hooks/catalog/index.ts b/src/hooks/catalog/index.ts new file mode 100644 index 00000000..9798d048 --- /dev/null +++ b/src/hooks/catalog/index.ts @@ -0,0 +1,5 @@ +export * from './useCatalog'; +export * from './useCatalogBuildersClub'; +export * from './useCatalogItemMover'; +export * from './useCatalogPlaceMultipleItems'; +export * from './useCatalogSkipPurchaseConfirmation'; diff --git a/src/hooks/catalog/useCatalog.ts b/src/hooks/catalog/useCatalog.ts new file mode 100644 index 00000000..ca2d4701 --- /dev/null +++ b/src/hooks/catalog/useCatalog.ts @@ -0,0 +1,611 @@ +import { ApproveNameMessageEvent, CatalogPageMessageEvent, CatalogPagesListEvent, CatalogPublishedMessageEvent, ClubGiftInfoEvent, FrontPageItem, GetCatalogIndexComposer, GetCatalogPageComposer, GetClubGiftInfo, GetGiftWrappingConfigurationComposer, GiftReceiverNotFoundEvent, GiftWrappingConfigurationEvent, GuildMembershipsMessageEvent, HabboClubOffersMessageEvent, LimitedEditionSoldOutEvent, MarketplaceMakeOfferResult, NodeData, ProductOfferEvent, PurchaseErrorMessageEvent, PurchaseNotAllowedMessageEvent, PurchaseOKMessageEvent, RoomPreviewer, SellablePetPalettesMessageEvent } from '@nitrots/nitro-renderer'; +import { useCallback, useEffect, useRef, useState } from 'react'; +import { useBetween } from 'use-between'; +import { CatalogNode, CatalogPage, CatalogPetPalette, CatalogType, GetFurnitureData, GetProductDataForLocalization, GetRoomEngine, GiftWrappingConfiguration, ICatalogNode, ICatalogOptions, ICatalogPage, IPageLocalization, IProduct, IPurchasableOffer, IPurchaseOptions, LocalizeText, NotificationAlertType, NotificationUtilities, Offer, PageLocalization, PlaySound, Product, ProductTypeEnum, RequestedPage, SearchResult, SendMessageComposer, SoundNames } from '../../api'; +import { CatalogGiftReceiverNotFoundEvent, CatalogNameResultEvent, CatalogPurchasedEvent, CatalogPurchaseFailureEvent, CatalogPurchaseNotAllowedEvent, CatalogPurchaseSoldOutEvent } from '../../events'; +import { DispatchUiEvent, UseUiEvent } from '../events'; +import { UseMessageEventHook } from '../messages'; +import { useCatalogBuildersClub } from './useCatalogBuildersClub'; +import { useCatalogItemMover } from './useCatalogItemMover'; + +const useCatalogState = () => +{ + const [ isVisible, setIsVisible ] = useState(false); + const [ isBusy, setIsBusy ] = useState(false); + const [ pageId, setPageId ] = useState(-1); + const [ previousPageId, setPreviousPageId ] = useState(-1); + const [ currentType, setCurrentType ] = useState(CatalogType.NORMAL); + const [ rootNode, setRootNode ] = useState(null); + const [ offersToNodes, setOffersToNodes ] = useState>(null); + const [ currentPage, setCurrentPage ] = useState(null); + const [ currentOffer, setCurrentOffer ] = useState(null); + const [ activeNodes, setActiveNodes ] = useState([]); + const [ searchResult, setSearchResult ] = useState(null); + const [ frontPageItems, setFrontPageItems ] = useState([]); + const [ roomPreviewer, setRoomPreviewer ] = useState(null); + const [ navigationHidden, setNavigationHidden ] = useState(false); + const [ purchaseOptions, setPurchaseOptions ] = useState({ quantity: 1, extraData: null, extraParamRequired: false, previewStuffData: null }); + const [ catalogOptions, setCatalogOptions ] = useState({}); + const { furniCount = 0, furniLimit = 0, secondsLeft = 0 } = useCatalogBuildersClub(); + const { requestOfferToMover = null, cancelObjectMover = null } = useCatalogItemMover({ currentType, pageId, currentOffer, purchaseOptions }, { furniCount, furniLimit, secondsLeft }); + const requestedPage = useRef(new RequestedPage()); + + const resetState = useCallback(() => + { + setPageId(-1); + setPreviousPageId(-1); + setRootNode(null); + setOffersToNodes(null); + setCurrentPage(null); + setCurrentOffer(null); + setActiveNodes([]); + setSearchResult(null); + setFrontPageItems([]); + setIsVisible(false); + }, []); + + const getNodeById = useCallback((id: number, node: ICatalogNode) => + { + if((node.pageId === id) && (node !== rootNode)) return node; + + for(const child of node.children) + { + const found = (getNodeById(id, child) as ICatalogNode); + + if(found) return found; + } + + return null; + }, [ rootNode ]); + + const getNodeByName = useCallback((name: string, node: ICatalogNode) => + { + if((node.pageName === name) && (node !== rootNode)) return node; + + for(const child of node.children) + { + const found = (getNodeByName(name, child) as ICatalogNode); + + if(found) return found; + } + + return null; + }, [ rootNode ]); + + const getNodesByOfferId = useCallback((offerId: number, flag: boolean = false) => + { + if(!offersToNodes || !offersToNodes.size) return null; + + if(flag) + { + const nodes: ICatalogNode[] = []; + const offers = offersToNodes.get(offerId); + + if(offers && offers.length) for(const offer of offers) (offer.isVisible && nodes.push(offer)); + + if(nodes.length) return nodes; + } + + return offersToNodes.get(offerId); + }, [ offersToNodes ]); + + const loadCatalogPage = useCallback((pageId: number, offerId: number) => + { + if(pageId < 0) return; + + setIsBusy(true); + setPageId(pageId); + + if(pageId > -1) SendMessageComposer(new GetCatalogPageComposer(pageId, offerId, currentType)); + }, [ currentType ]); + + const showCatalogPage = useCallback((pageId: number, layoutCode: string, localization: IPageLocalization, offers: IPurchasableOffer[], offerId: number, acceptSeasonCurrencyAsCredits: boolean) => + { + const catalogPage = (new CatalogPage(pageId, layoutCode, localization, offers, acceptSeasonCurrencyAsCredits) as ICatalogPage); + + setCurrentPage(catalogPage); + setPreviousPageId(prevValue => ((pageId !== -1) ? pageId : prevValue)); + setNavigationHidden(false); + + if((offerId > -1) && catalogPage.offers.length) + { + for(const offer of catalogPage.offers) + { + if(offer.offerId !== offerId) continue; + + setCurrentOffer(offer) + + break; + } + } + }, []); + + const activateNode = useCallback((targetNode: ICatalogNode, offerId: number = -1) => + { + cancelObjectMover(); + + if(targetNode.parent.pageName === 'root') + { + if(targetNode.children.length) + { + for(const child of targetNode.children) + { + if(!child.isVisible) continue; + + targetNode = child; + + break; + } + } + } + + const nodes: ICatalogNode[] = []; + + let node = targetNode; + + while(node && (node.pageName !== 'root')) + { + nodes.push(node); + + node = node.parent; + } + + nodes.reverse(); + + setActiveNodes(prevValue => + { + const isActive = (prevValue.indexOf(targetNode) >= 0); + const isOpen = targetNode.isOpen; + + for(const existing of prevValue) + { + existing.deactivate(); + + if(nodes.indexOf(existing) === -1) existing.close(); + } + + for(const n of nodes) + { + n.activate(); + + if(n.parent) n.open(); + + if((n === targetNode.parent) && n.children.length) n.open(); + } + + if(isActive && isOpen) targetNode.close(); + else targetNode.open(); + + return nodes; + }); + + if(targetNode.pageId > -1) loadCatalogPage(targetNode.pageId, offerId); + }, [ setActiveNodes, loadCatalogPage, cancelObjectMover ]); + + const openPageById = useCallback((id: number) => + { + setSearchResult(null); + + if(!isVisible) + { + requestedPage.current.requestById = id; + + setIsVisible(true); + } + else + { + const node = getNodeById(id, rootNode); + + if(node) activateNode(node); + } + }, [ isVisible, rootNode, getNodeById, activateNode ]); + + const openPageByName = useCallback((name: string) => + { + setSearchResult(null); + + if(!isVisible) + { + requestedPage.current.requestByName = name; + + setIsVisible(true); + } + else + { + const node = getNodeByName(name, rootNode); + + if(node) activateNode(node); + } + }, [ isVisible, rootNode, getNodeByName, activateNode ]); + + const openPageByOfferId = useCallback((offerId: number) => + { + setSearchResult(null); + + if(!isVisible) + { + requestedPage.current.requestedByOfferId = offerId; + + setIsVisible(true); + } + else + { + const nodes = getNodesByOfferId(offerId); + + if(!nodes || !nodes.length) return; + + activateNode(nodes[0], offerId); + } + }, [ isVisible, getNodesByOfferId, activateNode ]); + + const onCatalogPagesListEvent = useCallback((event: CatalogPagesListEvent) => + { + const parser = event.getParser(); + const offers: Map = new Map(); + + const getCatalogNode = (node: NodeData, depth: number, parent: ICatalogNode) => + { + const catalogNode = (new CatalogNode(node, depth, parent) as ICatalogNode); + + for(const offerId of catalogNode.offerIds) + { + if(offers.has(offerId)) offers.get(offerId).push(catalogNode); + else offers.set(offerId, [ catalogNode ]); + } + + depth++; + + for(const child of node.children) catalogNode.addChild(getCatalogNode(child, depth, catalogNode)); + + return catalogNode; + } + + setRootNode(getCatalogNode(parser.root, 0, null)); + setOffersToNodes(offers); + }, [ setRootNode, setOffersToNodes ]); + + UseMessageEventHook(CatalogPagesListEvent, onCatalogPagesListEvent); + + const onCatalogPageMessageEvent = useCallback((event: CatalogPageMessageEvent) => + { + const parser = event.getParser(); + + if(parser.catalogType !== currentType) return; + + const purchasableOffers: IPurchasableOffer[] = []; + + for(const offer of parser.offers) + { + const products: IProduct[] = []; + const productData = GetProductDataForLocalization(offer.localizationId); + + for(const product of offer.products) + { + const furnitureData = GetFurnitureData(product.furniClassId, product.productType); + + products.push(new Product(product.productType, product.furniClassId, product.extraParam, product.productCount, productData, furnitureData, product.uniqueLimitedItem, product.uniqueLimitedSeriesSize, product.uniqueLimitedItemsLeft)); + } + + if(!products.length) continue; + + const purchasableOffer = new Offer(offer.offerId, offer.localizationId, offer.rent, offer.priceCredits, offer.priceActivityPoints, offer.priceActivityPointsType, offer.giftable, offer.clubLevel, products, offer.bundlePurchaseAllowed); + + if((currentType === CatalogType.NORMAL) || ((purchasableOffer.pricingModel !== Offer.PRICING_MODEL_BUNDLE) && (purchasableOffer.pricingModel !== Offer.PRICING_MODEL_MULTI))) purchasableOffers.push(purchasableOffer); + } + + if(parser.frontPageItems && parser.frontPageItems.length) setFrontPageItems(parser.frontPageItems); + + setIsBusy(false); + + if(pageId === parser.pageId) + { + showCatalogPage(parser.pageId, parser.layoutCode, new PageLocalization(parser.localization.images.concat(), parser.localization.texts.concat()), purchasableOffers, parser.offerId, parser.acceptSeasonCurrencyAsCredits); + } + }, [ currentType, pageId, setFrontPageItems, setIsBusy, showCatalogPage ]); + + UseMessageEventHook(CatalogPageMessageEvent, onCatalogPageMessageEvent); + + const onPurchaseOKMessageEvent = useCallback((event: PurchaseOKMessageEvent) => + { + const parser = event.getParser(); + + DispatchUiEvent(new CatalogPurchasedEvent(parser.offer)); + }, []); + + UseMessageEventHook(PurchaseOKMessageEvent, onPurchaseOKMessageEvent); + + const onPurchaseErrorMessageEvent = useCallback((event: PurchaseErrorMessageEvent) => + { + const parser = event.getParser(); + + DispatchUiEvent(new CatalogPurchaseFailureEvent(parser.code)); + }, []); + + UseMessageEventHook(PurchaseErrorMessageEvent, onPurchaseErrorMessageEvent); + + const onPurchaseNotAllowedMessageEvent = useCallback((event: PurchaseNotAllowedMessageEvent) => + { + const parser = event.getParser(); + + DispatchUiEvent(new CatalogPurchaseNotAllowedEvent(parser.code)); + }, []); + + UseMessageEventHook(PurchaseNotAllowedMessageEvent, onPurchaseNotAllowedMessageEvent); + + const onLimitedEditionSoldOutEvent = useCallback((event: LimitedEditionSoldOutEvent) => + { + const parser = event.getParser(); + + DispatchUiEvent(new CatalogPurchaseSoldOutEvent()); + }, []); + + UseMessageEventHook(LimitedEditionSoldOutEvent, onLimitedEditionSoldOutEvent); + + const onProductOfferEvent = useCallback((event: ProductOfferEvent) => + { + const parser = event.getParser(); + const offerData = parser.offer; + + if(!offerData || !offerData.products.length) return; + + const offerProductData = offerData.products[0]; + + if(offerProductData.uniqueLimitedItem) + { + // update unique + } + + const products: IProduct[] = []; + const productData = GetProductDataForLocalization(offerData.localizationId); + + for(const product of offerData.products) + { + const furnitureData = GetFurnitureData(product.furniClassId, product.productType); + + products.push(new Product(product.productType, product.furniClassId, product.extraParam, product.productCount, productData, furnitureData, product.uniqueLimitedItem, product.uniqueLimitedSeriesSize, product.uniqueLimitedItemsLeft)); + } + + const offer = new Offer(offerData.offerId, offerData.localizationId, offerData.rent, offerData.priceCredits, offerData.priceActivityPoints, offerData.priceActivityPointsType, offerData.giftable, offerData.clubLevel, products, offerData.bundlePurchaseAllowed); + + if(!((currentType === CatalogType.NORMAL) || ((offer.pricingModel !== Offer.PRICING_MODEL_BUNDLE) && (offer.pricingModel !== Offer.PRICING_MODEL_MULTI)))) return; + + offer.page = currentPage; + + setCurrentOffer(offer); + + if(offer.product && (offer.product.productType === ProductTypeEnum.WALL)) + { + setPurchaseOptions(prevValue => + { + const newValue = { ...prevValue }; + + newValue.extraData =( offer.product.extraParam || null); + + return newValue; + }); + } + + // (this._isObjectMoverRequested) && (this._purchasableOffer) + }, [ currentType, currentPage, setCurrentOffer, setPurchaseOptions ]); + + UseMessageEventHook(ProductOfferEvent, onProductOfferEvent); + + const onSellablePetPalettesMessageEvent = useCallback((event: SellablePetPalettesMessageEvent) => + { + 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 }; + }); + }, [ setCatalogOptions ]); + + UseMessageEventHook(SellablePetPalettesMessageEvent, onSellablePetPalettesMessageEvent); + + const onApproveNameMessageEvent = useCallback((event: ApproveNameMessageEvent) => + { + const parser = event.getParser(); + + DispatchUiEvent(new CatalogNameResultEvent(parser.result, parser.validationInfo)); + }, []); + + UseMessageEventHook(ApproveNameMessageEvent, onApproveNameMessageEvent); + + const onGiftReceiverNotFoundEvent = useCallback(() => + { + DispatchUiEvent(new CatalogGiftReceiverNotFoundEvent()); + }, []); + + UseMessageEventHook(GiftReceiverNotFoundEvent, onGiftReceiverNotFoundEvent); + + const onHabboClubOffersMessageEvent = useCallback((event: HabboClubOffersMessageEvent) => + { + const parser = event.getParser(); + + setCatalogOptions(prevValue => + { + const clubOffers = parser.offers; + + return { ...prevValue, clubOffers }; + }); + }, [ setCatalogOptions ]); + + UseMessageEventHook(HabboClubOffersMessageEvent, onHabboClubOffersMessageEvent); + + const onGuildMembershipsMessageEvent = useCallback((event: GuildMembershipsMessageEvent) => + { + const parser = event.getParser(); + + setCatalogOptions(prevValue => + { + const groups = parser.groups; + + return { ...prevValue, groups }; + }); + }, [ setCatalogOptions ]); + + UseMessageEventHook(GuildMembershipsMessageEvent, onGuildMembershipsMessageEvent); + + const onGiftWrappingConfigurationEvent = useCallback((event: GiftWrappingConfigurationEvent) => + { + const parser = event.getParser(); + + setCatalogOptions(prevValue => + { + const giftConfiguration = new GiftWrappingConfiguration(parser); + + return { ...prevValue, giftConfiguration }; + }); + }, [ setCatalogOptions ]); + + UseMessageEventHook(GiftWrappingConfigurationEvent, onGiftWrappingConfigurationEvent); + + const onMarketplaceMakeOfferResult = useCallback((event: MarketplaceMakeOfferResult) => + { + const parser = event.getParser(); + + if(!parser) return; + + let title = ''; + if(parser.result === 1) + { + title = LocalizeText('inventory.marketplace.result.title.success'); + } + else + { + title = LocalizeText('inventory.marketplace.result.title.failure'); + } + + const message = LocalizeText(`inventory.marketplace.result.${ parser.result }`); + + NotificationUtilities.simpleAlert(message, NotificationAlertType.DEFAULT, null, null, title); + }, []); + + UseMessageEventHook(MarketplaceMakeOfferResult, onMarketplaceMakeOfferResult); + + const onClubGiftInfoEvent = useCallback((event: ClubGiftInfoEvent) => + { + const parser = event.getParser(); + + setCatalogOptions(prevValue => + { + const clubGifts = parser; + + return { ...prevValue, clubGifts }; + }); + }, [ setCatalogOptions ]); + + UseMessageEventHook(ClubGiftInfoEvent, onClubGiftInfoEvent); + + const onCatalogPublishedMessageEvent = useCallback((event: CatalogPublishedMessageEvent) => + { + const wasVisible = isVisible; + + resetState(); + + if(wasVisible) NotificationUtilities.simpleAlert(LocalizeText('catalog.alert.published.description'), NotificationAlertType.ALERT, null, null, LocalizeText('catalog.alert.published.title')); + }, [ isVisible, resetState ]); + + UseMessageEventHook(CatalogPublishedMessageEvent, onCatalogPublishedMessageEvent); + + const onCatalogPurchasedEvent = useCallback((event: CatalogPurchasedEvent) => + { + PlaySound(SoundNames.CREDITS); + }, []); + + UseUiEvent(CatalogPurchasedEvent.PURCHASE_SUCCESS, onCatalogPurchasedEvent); + + useEffect(() => + { + return () => setCurrentOffer(null); + }, [ currentPage ]); + + useEffect(() => + { + if(!isVisible || !rootNode || !requestedPage.current) return; + + switch(requestedPage.current.requestType) + { + case RequestedPage.REQUEST_TYPE_NONE: + if(activeNodes && activeNodes.length) return; + + if(rootNode.isBranch) + { + for(const child of rootNode.children) + { + if(child && child.isVisible) + { + activateNode(child); + + return; + } + } + } + return; + case RequestedPage.REQUEST_TYPE_ID: + openPageById(requestedPage.current.requestById); + requestedPage.current.resetRequest(); + return; + case RequestedPage.REQUEST_TYPE_OFFER: + openPageByOfferId(requestedPage.current.requestedByOfferId); + requestedPage.current.resetRequest(); + return; + case RequestedPage.REQUEST_TYPE_NAME: + openPageByName(requestedPage.current.requestByName); + requestedPage.current.resetRequest(); + return; + } + }, [ isVisible, rootNode, activeNodes, activateNode, openPageById, openPageByOfferId, openPageByName ]); + + useEffect(() => + { + if(!searchResult && currentPage && (currentPage.pageId === -1)) openPageById(previousPageId); + }, [ searchResult, currentPage, previousPageId, openPageById ]); + + useEffect(() => + { + if(!isVisible || rootNode) return; + + SendMessageComposer(new GetGiftWrappingConfigurationComposer()); + SendMessageComposer(new GetClubGiftInfo()); + SendMessageComposer(new GetCatalogIndexComposer(currentType)); + }, [ isVisible, rootNode, currentType ]); + + useEffect(() => + { + setRoomPreviewer(new RoomPreviewer(GetRoomEngine(), ++RoomPreviewer.PREVIEW_COUNTER)); + + return () => + { + setRoomPreviewer(prevValue => + { + prevValue.dispose(); + + return null; + }); + } + }, []); + + return { isVisible, setIsVisible, isBusy, pageId, previousPageId, currentType, rootNode, offersToNodes, currentPage, setCurrentPage, currentOffer, setCurrentOffer, activeNodes, searchResult, setSearchResult, frontPageItems, roomPreviewer, navigationHidden, setNavigationHidden, purchaseOptions, setPurchaseOptions, catalogOptions, setCatalogOptions, getNodeById, getNodeByName, activateNode, openPageById, openPageByName, openPageByOfferId, requestOfferToMover }; +} + +export const useCatalog = () => useBetween(useCatalogState); diff --git a/src/hooks/catalog/useCatalogBuildersClub.ts b/src/hooks/catalog/useCatalogBuildersClub.ts new file mode 100644 index 00000000..538277a1 --- /dev/null +++ b/src/hooks/catalog/useCatalogBuildersClub.ts @@ -0,0 +1,54 @@ +import { BuildersClubFurniCountMessageEvent, BuildersClubQueryFurniCountMessageComposer, BuildersClubSubscriptionStatusMessageEvent } from '@nitrots/nitro-renderer'; +import { useCallback, useEffect, useState } from 'react'; +import { GetNitroInstance, SendMessageComposer } from '../../api'; +import { UseMessageEventHook } from '../messages'; + +const useCatalogBuildersClubState = () => +{ + const [ furniCount, setFurniCount ] = useState(0); + const [ furniLimit, setFurniLimit ] = useState(0); + const [ maxFurniLimit, setMaxFurniLimit ] = useState(0); + const [ secondsLeft, setSecondsLeft ] = useState(0); + const [ updateTime, setUpdateTime ] = useState(0); + const [ secondsLeftWithGrace, setSecondsLeftWithGrace ] = useState(0); + + const refreshBuilderStatus = useCallback(() => + { + + }, []); + + const onBuildersClubFurniCountMessageEvent = useCallback((event: BuildersClubFurniCountMessageEvent) => + { + const parser = event.getParser(); + + setFurniCount(parser.furniCount); + + refreshBuilderStatus(); + }, [ refreshBuilderStatus ]); + + UseMessageEventHook(BuildersClubFurniCountMessageEvent, onBuildersClubFurniCountMessageEvent); + + const onBuildersClubSubscriptionStatusMessageEvent = useCallback((event: BuildersClubSubscriptionStatusMessageEvent) => + { + const parser = event.getParser(); + + setFurniLimit(parser._Str_15864); + setMaxFurniLimit(parser._Str_24094); + setSecondsLeft(parser._Str_3709); + setUpdateTime(GetNitroInstance().time); + setSecondsLeftWithGrace(parser._Str_24379); + + refreshBuilderStatus(); + }, [ refreshBuilderStatus ]); + + UseMessageEventHook(BuildersClubSubscriptionStatusMessageEvent, onBuildersClubSubscriptionStatusMessageEvent); + + useEffect(() => + { + SendMessageComposer(new BuildersClubQueryFurniCountMessageComposer()); + }, []); + + return { furniCount, furniLimit, maxFurniLimit, secondsLeft, updateTime, secondsLeftWithGrace }; +} + +export const useCatalogBuildersClub = useCatalogBuildersClubState; diff --git a/src/hooks/catalog/useCatalogItemMover.ts b/src/hooks/catalog/useCatalogItemMover.ts new file mode 100644 index 00000000..e6b8960d --- /dev/null +++ b/src/hooks/catalog/useCatalogItemMover.ts @@ -0,0 +1,321 @@ +import { BuildersClubPlaceRoomItemMessageComposer, BuildersClubPlaceWallItemMessageComposer, FurniturePlaceComposer, FurniturePlacePaintComposer, LegacyDataType, PurchaseFromCatalogComposer, RoomControllerLevel, RoomEngineObjectPlacedEvent, RoomObjectCategory, RoomObjectPlacementSource, RoomObjectType, RoomObjectVariable, Vector3d } from '@nitrots/nitro-renderer'; +import { useCallback, useState } from 'react'; +import { BuilderFurniPlaceableStatus, CatalogType, CreateLinkEvent, FurniCategory, GetRoomEngine, GetRoomSession, IPurchasableOffer, IPurchaseOptions, Offer, PlacedObjectPurchaseData, ProductTypeEnum, SendMessageComposer } from '../../api'; +import { InventoryFurniAddedEvent } from '../../events'; +import { UseRoomEngineEvent, UseUiEvent } from '../events'; +import { useCatalogPlaceMultipleItems } from './useCatalogPlaceMultipleItems'; +import { useCatalogSkipPurchaseConfirmation } from './useCatalogSkipPurchaseConfirmation'; + +const DUMMY_PAGE_ID_FOR_OFFER_SEARCH = -12345678; +const DRAG_AND_DROP_ENABLED = true; + +const useCatalogItemMoverState = (catalog: { currentType: string, pageId: number, currentOffer: IPurchasableOffer, purchaseOptions: IPurchaseOptions }, buildersClub: { furniCount: number, furniLimit: number, secondsLeft: number }) => +{ + const [ objectMoverRequested, setObjectMoverRequested ] = useState(false); + const [ catalogPlaceMultipleObjects, setCatalogPlaceMultipleObjects ] = useCatalogPlaceMultipleItems(); + const [ catalogSkipPurchaseConfirmation, setCatalogSkipPurchaseConfirmation ] = useCatalogSkipPurchaseConfirmation(); + const [ purchasableOffer, setPurchaseableOffer ] = useState(null); + const [ placedObjectPurchaseData, setPlacedObjectPurchaseData ] = useState(null); + + const getBuilderFurniPlaceableStatus = useCallback((offer: IPurchasableOffer) => + { + if(!offer) return BuilderFurniPlaceableStatus.MISSING_OFFER; + + if((buildersClub.furniCount < 0) || (buildersClub.furniCount >= buildersClub.furniLimit)) return BuilderFurniPlaceableStatus.FURNI_LIMIT_REACHED; + + const roomSession = GetRoomSession(); + + if(!roomSession) return BuilderFurniPlaceableStatus.NOT_IN_ROOM; + + if(!roomSession.isRoomOwner) return BuilderFurniPlaceableStatus.NOT_ROOM_OWNER; + + if(buildersClub.secondsLeft <= 0) + { + const roomEngine = GetRoomEngine(); + + let objectCount = roomEngine.getRoomObjectCount(roomSession.roomId, RoomObjectCategory.UNIT); + + while(objectCount > 0) + { + const roomObject = roomEngine.getRoomObjectByIndex(roomSession.roomId, objectCount, RoomObjectCategory.UNIT); + const userData = roomSession.userDataManager.getUserDataByIndex(roomObject.id); + + if(userData && (userData.type === RoomObjectType.USER) && (userData.roomIndex !== roomSession.ownRoomIndex) && !userData.isModerator) return BuilderFurniPlaceableStatus.VISITORS_IN_ROOM; + + objectCount--; + } + } + + return BuilderFurniPlaceableStatus.OKAY; + }, [ buildersClub.furniCount, buildersClub.furniLimit, buildersClub.secondsLeft ]); + + const isDraggable = useCallback((offer: IPurchasableOffer) => + { + const roomSession = GetRoomSession(); + + if(((DRAG_AND_DROP_ENABLED && roomSession && offer.page && (offer.page.layoutCode !== 'sold_ltd_items') && (catalog.currentType === CatalogType.NORMAL) && (roomSession.isRoomOwner || (roomSession.isGuildRoom && (roomSession.controllerLevel >= RoomControllerLevel.GUILD_MEMBER)))) || ((catalog.currentType === CatalogType.BUILDER) && (getBuilderFurniPlaceableStatus(offer) === BuilderFurniPlaceableStatus.OKAY))) && (offer.pricingModel !== Offer.PRICING_MODEL_BUNDLE) && (offer.product.productType !== ProductTypeEnum.EFFECT) && (offer.product.productType !== ProductTypeEnum.HABBO_CLUB)) return true; + + return false; + }, [ catalog.currentType, getBuilderFurniPlaceableStatus ]); + + const requestOfferToMover = useCallback((offer: IPurchasableOffer) => + { + if(!isDraggable(offer)) return; + + const product = offer.product; + + if(!product) return; + + let category = 0; + + switch(product.productType) + { + case ProductTypeEnum.FLOOR: + category = RoomObjectCategory.FLOOR; + break; + case ProductTypeEnum.WALL: + category = RoomObjectCategory.WALL; + break; + } + + if(GetRoomEngine().processRoomObjectPlacement(RoomObjectPlacementSource.CATALOG, -(offer.offerId), category, product.productClassId, product.extraParam)) + { + setPurchaseableOffer(offer); + setObjectMoverRequested(true); + + CreateLinkEvent('catalog/hide'); + } + }, [ isDraggable ]); + + const resetRoomPaint = useCallback((planeType: string, type: string) => + { + const roomEngine = GetRoomEngine(); + + let wallType = roomEngine.getRoomInstanceVariable(roomEngine.activeRoomId, RoomObjectVariable.ROOM_WALL_TYPE); + let floorType = roomEngine.getRoomInstanceVariable(roomEngine.activeRoomId, RoomObjectVariable.ROOM_FLOOR_TYPE); + let landscapeType = roomEngine.getRoomInstanceVariable(roomEngine.activeRoomId, RoomObjectVariable.ROOM_LANDSCAPE_TYPE); + + wallType = (wallType && wallType.length) ? wallType : '101'; + floorType = (floorType && floorType.length) ? floorType : '101'; + landscapeType = (landscapeType && landscapeType.length) ? landscapeType : '1.1'; + + switch(planeType) + { + case 'floor': + roomEngine.updateRoomInstancePlaneType(roomEngine.activeRoomId, type, wallType, landscapeType, true); + return; + case 'wallpaper': + roomEngine.updateRoomInstancePlaneType(roomEngine.activeRoomId, floorType, type, landscapeType, true); + return; + case 'landscape': + roomEngine.updateRoomInstancePlaneType(roomEngine.activeRoomId, floorType, wallType, type, true); + return; + default: + roomEngine.updateRoomInstancePlaneType(roomEngine.activeRoomId, floorType, wallType, landscapeType, true); + return; + } + }, []); + + const cancelObjectMover = useCallback(() => + { + if(!purchasableOffer) return; + + GetRoomEngine().cancelRoomObjectInsert(); + + setObjectMoverRequested(false); + setPurchaseableOffer(null); + }, [ purchasableOffer ]); + + const resetObjectMover = useCallback((flag: boolean = true) => + { + setObjectMoverRequested(prevValue => + { + if(prevValue && flag) + { + CreateLinkEvent('catalog/open'); + } + + return false; + }); + }, []); + + const resetPlacedOfferData = useCallback((flag: boolean = false) => + { + if(!flag) resetObjectMover(); + + setPlacedObjectPurchaseData(prevValue => + { + if(prevValue) + { + switch(prevValue.category) + { + case RoomObjectCategory.FLOOR: + GetRoomEngine().removeRoomObjectFloor(prevValue.roomId, prevValue.objectId); + break; + case RoomObjectCategory.WALL: { + + switch(prevValue.furniData.className) + { + case 'floor': + case 'wallpaper': + case 'landscape': + resetRoomPaint('reset', ''); + break; + default: + GetRoomEngine().removeRoomObjectWall(prevValue.roomId, prevValue.objectId); + break; + } + break; + } + default: + GetRoomEngine().deleteRoomObject(prevValue.objectId, prevValue.category); + break; + } + } + + return null; + }); + }, [ resetObjectMover, resetRoomPaint ]); + + const onRoomEngineObjectPlacedEvent = useCallback((event: RoomEngineObjectPlacedEvent) => + { + if(!objectMoverRequested || (event.type !== RoomEngineObjectPlacedEvent.PLACED)) return; + + resetPlacedOfferData(true); + + if(!purchasableOffer) + { + resetObjectMover(); + + return; + } + + let placed = false; + + const product = purchasableOffer.product; + + if(event.category === RoomObjectCategory.WALL) + { + switch(product.furnitureData.className) + { + case 'floor': + case 'wallpaper': + case 'landscape': + placed = (event.placedOnFloor || event.placedOnWall); + break; + default: + placed = event.placedInRoom; + break; + } + } + else + { + placed = event.placedInRoom; + } + + if(!placed) + { + resetObjectMover(); + + return; + } + + setPlacedObjectPurchaseData(new PlacedObjectPurchaseData(event.roomId, event.objectId, event.category, event.wallLocation, event.x, event.y, event.direction, purchasableOffer)); + + switch(catalog.currentType) + { + case CatalogType.NORMAL: { + switch(event.category) + { + case RoomObjectCategory.FLOOR: + GetRoomEngine().addFurnitureFloor(event.roomId, event.objectId, product.productClassId, new Vector3d(event.x, event.y, event.z), new Vector3d(event.direction), 0, new LegacyDataType()); + break; + case RoomObjectCategory.WALL: { + switch(product.furnitureData.className) + { + case 'floor': + case 'wallpaper': + case 'landscape': + resetRoomPaint(product.furnitureData.className, product.extraParam); + break; + default: + GetRoomEngine().addFurnitureWall(event.roomId, event.objectId, product.productClassId, new Vector3d(event.x, event.y, event.z), new Vector3d(event.direction * 45), 0, event.instanceData, 0); + break; + } + } + } + + const roomObject = GetRoomEngine().getRoomObject(event.roomId, event.objectId, event.category); + + if(roomObject) roomObject.model.setValue(RoomObjectVariable.FURNITURE_ALPHA_MULTIPLIER, 0.5); + + SendMessageComposer(new PurchaseFromCatalogComposer(catalog.pageId, purchasableOffer.offerId, product.extraParam, 1)); + + if(catalogPlaceMultipleObjects) requestOfferToMover(purchasableOffer); + break; + } + case CatalogType.BUILDER: { + let pageId = purchasableOffer.page.pageId; + + if(pageId === DUMMY_PAGE_ID_FOR_OFFER_SEARCH) + { + pageId = -1; + } + + switch(event.category) + { + case RoomObjectCategory.FLOOR: + SendMessageComposer(new BuildersClubPlaceRoomItemMessageComposer(pageId, purchasableOffer.offerId, product.extraParam, event.x, event.y, event.direction)); + break; + case RoomObjectCategory.WALL: + SendMessageComposer(new BuildersClubPlaceWallItemMessageComposer(pageId, purchasableOffer.offerId, product.extraParam, event.wallLocation)); + break; + } + + if(catalogPlaceMultipleObjects) requestOfferToMover(purchasableOffer); + break; + } + } + }, [ objectMoverRequested, purchasableOffer, catalogPlaceMultipleObjects, catalog, resetPlacedOfferData, resetObjectMover, resetRoomPaint, requestOfferToMover ]); + + UseRoomEngineEvent(RoomEngineObjectPlacedEvent.PLACED, onRoomEngineObjectPlacedEvent); + + const onInventoryFurniAddedEvent = useCallback((event: InventoryFurniAddedEvent) => + { + const roomEngine = GetRoomEngine(); + + if(!placedObjectPurchaseData || (placedObjectPurchaseData.productClassId !== event.spriteId) || (placedObjectPurchaseData.roomId !== roomEngine.activeRoomId)) return; + + switch(event.category) + { + case FurniCategory.FLOOR: { + const floorType = roomEngine.getRoomInstanceVariable(roomEngine.activeRoomId, RoomObjectVariable.ROOM_FLOOR_TYPE); + + if(placedObjectPurchaseData.extraParam !== floorType) SendMessageComposer(new FurniturePlacePaintComposer(event.id)); + break; + } + case FurniCategory.WALL_PAPER: { + const wallType = roomEngine.getRoomInstanceVariable(roomEngine.activeRoomId, RoomObjectVariable.ROOM_WALL_TYPE); + + if(placedObjectPurchaseData.extraParam !== wallType) SendMessageComposer(new FurniturePlacePaintComposer(event.id)); + break; + } + case FurniCategory.LANDSCAPE: { + const landscapeType = roomEngine.getRoomInstanceVariable(roomEngine.activeRoomId, RoomObjectVariable.ROOM_LANDSCAPE_TYPE); + + if(placedObjectPurchaseData.extraParam !== landscapeType) SendMessageComposer(new FurniturePlacePaintComposer(event.id)); + break; + } + default: + SendMessageComposer(new FurniturePlaceComposer(event.id, placedObjectPurchaseData.category, placedObjectPurchaseData.wallLocation, placedObjectPurchaseData.x, placedObjectPurchaseData.y, placedObjectPurchaseData.direction)); + } + + if(!catalogPlaceMultipleObjects) resetPlacedOfferData(); + }, [ placedObjectPurchaseData, catalogPlaceMultipleObjects, resetPlacedOfferData ]); + + UseUiEvent(InventoryFurniAddedEvent.FURNI_ADDED, onInventoryFurniAddedEvent); + + return { requestOfferToMover, cancelObjectMover }; +} + +export const useCatalogItemMover = useCatalogItemMoverState; diff --git a/src/hooks/catalog/useCatalogPlaceMultipleItems.ts b/src/hooks/catalog/useCatalogPlaceMultipleItems.ts new file mode 100644 index 00000000..39cfd28c --- /dev/null +++ b/src/hooks/catalog/useCatalogPlaceMultipleItems.ts @@ -0,0 +1,7 @@ +import { useBetween } from 'use-between'; +import { LocalStorageKeys } from '../../api'; +import { useLocalStorage } from '../useLocalStorage'; + +const useCatalogPlaceMultipleItemsState = () => useLocalStorage(LocalStorageKeys.CATALOG_PLACE_MULTIPLE_OBJECTS, false); + +export const useCatalogPlaceMultipleItems = () => useBetween(useCatalogPlaceMultipleItemsState); diff --git a/src/hooks/catalog/useCatalogSkipPurchaseConfirmation.ts b/src/hooks/catalog/useCatalogSkipPurchaseConfirmation.ts new file mode 100644 index 00000000..b2d69a2a --- /dev/null +++ b/src/hooks/catalog/useCatalogSkipPurchaseConfirmation.ts @@ -0,0 +1,7 @@ +import { useBetween } from 'use-between'; +import { LocalStorageKeys } from '../../api'; +import { useLocalStorage } from '../useLocalStorage'; + +const useCatalogSkipPurchaseConfirmationState = () => useLocalStorage(LocalStorageKeys.CATALOG_SKIP_PURCHASE_CONFIRMATION, false); + +export const useCatalogSkipPurchaseConfirmation = () => useBetween(useCatalogSkipPurchaseConfirmationState); diff --git a/src/hooks/index.ts b/src/hooks/index.ts index 8713e5db..44d7ec57 100644 --- a/src/hooks/index.ts +++ b/src/hooks/index.ts @@ -1,4 +1,5 @@ export * from './achievements'; +export * from './catalog'; export * from './events'; export * from './events/core'; export * from './events/nitro'; @@ -10,5 +11,6 @@ export * from './navigator'; export * from './purse'; export * from './rooms'; export * from './session'; +export * from './useLocalStorage'; export * from './UseMountEffect'; export * from './useSharedVisibility'; diff --git a/src/hooks/inventory/useInventoryFurni.ts b/src/hooks/inventory/useInventoryFurni.ts index 8ce8379d..13d19463 100644 --- a/src/hooks/inventory/useInventoryFurni.ts +++ b/src/hooks/inventory/useInventoryFurni.ts @@ -4,6 +4,8 @@ import { useBetween } from 'use-between'; import { useInventoryUnseenTracker } from '.'; import { UseMessageEventHook } from '..'; import { addFurnitureItem, attemptItemPlacement, cancelRoomObjectPlacement, CloneObject, CreateLinkEvent, FurnitureItem, getAllItemIds, getPlacingItemId, GroupItem, mergeFurniFragments, SendMessageComposer, UnseenItemCategory } from '../../api'; +import { InventoryFurniAddedEvent } from '../../events'; +import { DispatchUiEvent } from '../events'; import { useSharedVisibility } from '../useSharedVisibility'; let furniMsgFragments: Map[] = null; @@ -73,6 +75,8 @@ const useInventoryFurniState = () => const furniture = new FurnitureItem(item); addFurnitureItem(newValue, furniture, isUnseen(UnseenItemCategory.FURNI, item.itemId)); + + DispatchUiEvent(new InventoryFurniAddedEvent(furniture.id, furniture.type, furniture.category)); } } @@ -148,6 +152,8 @@ const useInventoryFurniState = () => addFurnitureItem(newValue, item, isUnseen(UnseenItemCategory.FURNI, itemId)); + DispatchUiEvent(new InventoryFurniAddedEvent(item.id, item.type, item.category)); + } return newValue; diff --git a/src/hooks/useLocalStorage.ts b/src/hooks/useLocalStorage.ts new file mode 100644 index 00000000..e231cc29 --- /dev/null +++ b/src/hooks/useLocalStorage.ts @@ -0,0 +1,43 @@ +import { NitroLogger } from '@nitrots/nitro-renderer'; +import { Dispatch, SetStateAction, useState } from 'react'; + +const useLocalStorageState = (key: string, initialValue: T): [ T, Dispatch>] => +{ + const [ storedValue, setStoredValuie ] = useState(() => + { + if(typeof window === 'undefined') return initialValue; + + try + { + const item = window.localStorage.getItem(key); + + return item ? JSON.parse(item) : initialValue; + } + + catch(error) + { + return initialValue; + } + }); + + const setValue = (value: T) => + { + try + { + const valueToStore = value instanceof Function ? value(storedValue) : value; + + setStoredValuie(valueToStore); + + if(typeof window !== 'undefined') window.localStorage.setItem(key, JSON.stringify(valueToStore)); + } + + catch(error) + { + NitroLogger.error(error); + } + } + + return [ storedValue, setValue ]; +} + +export const useLocalStorage = useLocalStorageState;