From 8129bd33935698b711926083f3780e860096b4b9 Mon Sep 17 00:00:00 2001 From: Bill Date: Tue, 1 Feb 2022 01:58:19 -0500 Subject: [PATCH] More catalog changes --- .../catalog/CatalogMessageHandler.tsx | 130 +++++++------ src/components/catalog/CatalogView.scss | 5 + src/components/catalog/CatalogView.tsx | 134 ++++++++------ .../catalog/common/CatalogUtilities.ts | 35 ---- .../catalog/common/ICatalogOptions.ts | 15 ++ src/components/catalog/common/IProduct.ts | 16 +- .../catalog/common/IPurchasableOffer.ts | 32 ++-- .../catalog/common/IPurchaseOptions.ts | 10 + .../catalog/context/CatalogContext.tsx | 26 +-- .../catalog/reducers/CatalogReducer.tsx | 117 ------------ .../CatalogRoomPreviewerView.tsx | 27 +-- .../catalog/views/gift/CatalogGiftView.tsx | 10 +- .../navigation/CatalogNavigationItemView.tsx | 2 +- .../catalog/views/page/CatalogPageView.tsx | 121 ------------ .../views/page/layout/CatalogLayout.types.ts | 2 - .../layout/CatalogLayoutBadgeDisplayView.tsx | 106 +++++------ .../page/layout/CatalogLayoutDefaultView.tsx | 40 +++- .../CatalogLayoutGuildCustomFurniView.tsx | 88 ++++----- .../layout/CatalogLayoutGuildForumView.tsx | 7 +- .../layout/CatalogLayoutRoomBundleView.tsx | 48 +++-- .../layout/CatalogLayoutSingleBundleView.tsx | 32 ++-- .../page/layout/CatalogLayoutSpacesView.tsx | 88 ++++----- .../page/layout/CatalogLayoutTrophiesView.tsx | 48 ++++- .../page/layout/CatalogLayoutVipBuyView.tsx | 19 +- .../views/page/layout/GetCatalogLayout.tsx | 13 +- .../marketplace/MarketplacePostOfferView.tsx | 19 +- .../pets/CatalogLayoutPetPurchaseView.tsx | 21 +-- .../page/layout/pets/CatalogLayoutPetView.tsx | 99 +++++++--- .../vip-gifts/CatalogLayoutVipGiftsView.tsx | 40 ++-- .../page/offers/CatalogGridOfferView.tsx | 6 +- .../offers/CatalogPageOfferPreviewView.tsx | 4 - .../page/offers/CatalogPageOfferView.tsx | 52 ------ .../page/offers/CatalogPageOffersView.tsx | 23 --- .../purchase/CatalogPurchaseButtonView.tsx | 123 ------------- .../CatalogPurchaseGiftButtonView.tsx | 25 --- .../page/purchase/CatalogPurchaseView.tsx | 7 - .../widgets/CatalogAddOnBadgeWidgetView.tsx | 19 +- .../CatalogBadgeSelectorWidgetView.tsx | 73 ++++++++ .../widgets/CatalogBundleGridWidgetView.tsx | 36 +--- .../CatalogFirstProductSelectorWidgetView.tsx | 14 +- .../widgets/CatalogGuildBadgeWidgetView.tsx | 32 ++++ .../CatalogGuildSelectorWidgetView.tsx | 75 ++++++++ .../widgets/CatalogItemGridWidgetView.tsx | 6 +- .../widgets/CatalogLimitedItemWidgetView.tsx | 20 ++ .../widgets/CatalogPriceDisplayWidgetView.tsx | 22 ++- .../widgets/CatalogPurchaseWidgetView.tsx | 172 +++++++++++------- .../widgets/CatalogSimplePriceWidgetView.tsx | 28 ++- .../page/widgets/CatalogSpacesWidgetView.tsx | 117 ++++++++++++ .../page/widgets/CatalogSpinnerWidgetView.tsx | 43 +++++ .../page/widgets/CatalogTotalPriceWidget.tsx | 20 ++ .../widgets/CatalogViewProductWidgetView.tsx | 122 ++++++++++--- .../views/search/CatalogSearchView.tsx | 52 ++++-- .../select-group/CatalogSelectGroupView.tsx | 44 ----- .../catalog/views/tabs/CatalogTabsView.tsx | 30 --- src/events/catalog/CatalogEvent.ts | 2 - src/events/catalog/CatalogNameResultEvent.ts | 7 +- src/events/catalog/CatalogPageOpenedEvent.ts | 27 --- src/events/catalog/CatalogPageReadyEvent.ts | 11 -- .../catalog/CatalogPurchaseFailureEvent.ts | 8 +- .../catalog/CatalogPurchaseNotAllowedEvent.ts | 20 ++ .../catalog/CatalogPurchaseSoldOutEvent.ts | 8 +- src/events/catalog/CatalogPurchasedEvent.ts | 9 +- .../catalog/CatalogSelectProductEvent.ts | 20 -- src/events/catalog/index.ts | 4 +- 64 files changed, 1285 insertions(+), 1346 deletions(-) create mode 100644 src/components/catalog/common/ICatalogOptions.ts create mode 100644 src/components/catalog/common/IPurchaseOptions.ts delete mode 100644 src/components/catalog/reducers/CatalogReducer.tsx delete mode 100644 src/components/catalog/views/page/CatalogPageView.tsx delete mode 100644 src/components/catalog/views/page/offers/CatalogPageOfferView.tsx delete mode 100644 src/components/catalog/views/page/offers/CatalogPageOffersView.tsx delete mode 100644 src/components/catalog/views/page/purchase/CatalogPurchaseButtonView.tsx delete mode 100644 src/components/catalog/views/page/purchase/CatalogPurchaseGiftButtonView.tsx create mode 100644 src/components/catalog/views/page/widgets/CatalogBadgeSelectorWidgetView.tsx create mode 100644 src/components/catalog/views/page/widgets/CatalogGuildBadgeWidgetView.tsx create mode 100644 src/components/catalog/views/page/widgets/CatalogGuildSelectorWidgetView.tsx create mode 100644 src/components/catalog/views/page/widgets/CatalogLimitedItemWidgetView.tsx create mode 100644 src/components/catalog/views/page/widgets/CatalogSpacesWidgetView.tsx create mode 100644 src/components/catalog/views/page/widgets/CatalogSpinnerWidgetView.tsx create mode 100644 src/components/catalog/views/page/widgets/CatalogTotalPriceWidget.tsx delete mode 100644 src/components/catalog/views/select-group/CatalogSelectGroupView.tsx delete mode 100644 src/components/catalog/views/tabs/CatalogTabsView.tsx delete mode 100644 src/events/catalog/CatalogPageOpenedEvent.ts delete mode 100644 src/events/catalog/CatalogPageReadyEvent.ts create mode 100644 src/events/catalog/CatalogPurchaseNotAllowedEvent.ts delete mode 100644 src/events/catalog/CatalogSelectProductEvent.ts diff --git a/src/components/catalog/CatalogMessageHandler.tsx b/src/components/catalog/CatalogMessageHandler.tsx index eda934d6..5400d3e2 100644 --- a/src/components/catalog/CatalogMessageHandler.tsx +++ b/src/components/catalog/CatalogMessageHandler.tsx @@ -2,7 +2,7 @@ import { ApproveNameMessageEvent, CatalogPageMessageEvent, CatalogPagesListEvent import { GuildMembershipsMessageEvent } from '@nitrots/nitro-renderer/src/nitro/communication/messages/incoming/user/GuildMembershipsMessageEvent'; import { FC, useCallback } from 'react'; import { GetFurnitureData, GetProductDataForLocalization, LocalizeText } from '../../api'; -import { CatalogNameResultEvent, CatalogPurchaseFailureEvent, CatalogSelectProductEvent, CatalogSetExtraPurchaseParameterEvent } from '../../events'; +import { CatalogNameResultEvent, CatalogPurchaseFailureEvent, CatalogPurchaseNotAllowedEvent, CatalogSetExtraPurchaseParameterEvent } from '../../events'; import { CatalogGiftReceiverNotFoundEvent } from '../../events/catalog/CatalogGiftReceiverNotFoundEvent'; import { CatalogPurchasedEvent } from '../../events/catalog/CatalogPurchasedEvent'; import { CatalogPurchaseSoldOutEvent } from '../../events/catalog/CatalogPurchaseSoldOutEvent'; @@ -14,6 +14,7 @@ import { NotificationUtilities } from '../../views/notification-center/common/No 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'; @@ -23,11 +24,10 @@ import { Product } from './common/Product'; import { ProductTypeEnum } from './common/ProductTypeEnum'; import { SubscriptionInfo } from './common/SubscriptionInfo'; import { useCatalogContext } from './context/CatalogContext'; -import { CatalogActions } from './reducers/CatalogReducer'; export const CatalogMessageHandler: FC<{}> = props => { - const { setIsBusy, pageId, currentType, setRootNode, setOffersToNodes, currentPage, setCurrentOffer, setPurchasableOffer, setFrontPageItems, resetState, showCatalogPage, catalogState, dispatchCatalogState } = useCatalogContext(); + const { setIsBusy, pageId, currentType, setRootNode, setOffersToNodes, currentPage, setCurrentOffer, setFrontPageItems, resetState, showCatalogPage, setCatalogOptions = null } = useCatalogContext(); const onCatalogPagesListEvent = useCallback((event: CatalogPagesListEvent) => { @@ -115,6 +115,8 @@ export const CatalogMessageHandler: FC<{}> = props => const onPurchaseNotAllowedMessageEvent = useCallback((event: PurchaseNotAllowedMessageEvent) => { const parser = event.getParser(); + + dispatchUiEvent(new CatalogPurchaseNotAllowedEvent(parser.code)); }, []); const onLimitedEditionSoldOutEvent = useCallback((event: LimitedEditionSoldOutEvent) => @@ -154,7 +156,7 @@ export const CatalogMessageHandler: FC<{}> = props => offer.page = currentPage; - dispatchUiEvent(new CatalogSelectProductEvent(offer)); + setCurrentOffer(offer); if(offer.product && (offer.product.productType === ProductTypeEnum.WALL)) { @@ -162,19 +164,36 @@ export const CatalogMessageHandler: FC<{}> = props => } // (this._isObjectMoverRequested) && (this._purchasableOffer) - // setPurchasableOffer(offer); - }, [ currentType, currentPage ]); + }, [ currentType, currentPage, setCurrentOffer ]); const onSellablePetPalettesMessageEvent = useCallback((event: SellablePetPalettesMessageEvent) => { const parser = event.getParser(); const petPalette = new CatalogPetPalette(parser.productCode, parser.palettes.slice()); - dispatchCatalogState({ - type: CatalogActions.SET_PET_PALETTE, - payload: { petPalette } - }); - }, [ dispatchCatalogState ]); + 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) => { @@ -192,43 +211,42 @@ export const CatalogMessageHandler: FC<{}> = props => { const parser = event.getParser(); - dispatchCatalogState({ - type: CatalogActions.SET_CLUB_OFFERS, - payload: { - clubOffers: parser.offers - } - }); - }, [ dispatchCatalogState ]); + setCatalogOptions(prevValue => + { + const clubOffers = parser.offers; + + return { ...prevValue, clubOffers }; + }); + }, [ setCatalogOptions ]); const onGuildMembershipsMessageEvent = useCallback((event: GuildMembershipsMessageEvent) => { const parser = event.getParser(); - dispatchCatalogState({ - type: CatalogActions.SET_GROUPS, - payload: { - groups: parser.groups - } - }); - }, [ dispatchCatalogState ]); + setCatalogOptions(prevValue => + { + const groups = parser.groups; + + return { ...prevValue, groups }; + }); + }, [ setCatalogOptions ]); const onUserSubscriptionEvent = useCallback((event: UserSubscriptionEvent) => { const parser = event.getParser(); - dispatchCatalogState({ - type: CatalogActions.SET_SUBSCRIPTION_INFO, - payload: { - subscriptionInfo: new SubscriptionInfo( + setCatalogOptions(prevValue => + { + const subscriptionInfo = new SubscriptionInfo( Math.max(0, parser.daysToPeriodEnd), Math.max(0, parser.periodsSubscribedAhead), parser.isVip, parser.pastClubDays, - parser.pastVipDays - ) - } - }); - }, [ dispatchCatalogState ]); + parser.pastVipDays); + + return { ...prevValue, subscriptionInfo }; + }); + }, [ setCatalogOptions ]); const onCatalogPublishedMessageEvent = useCallback((event: CatalogPublishedMessageEvent) => { @@ -239,13 +257,13 @@ export const CatalogMessageHandler: FC<{}> = props => { const parser = event.getParser(); - dispatchCatalogState({ - type: CatalogActions.SET_GIFT_CONFIGURATION, - payload: { - giftConfiguration: parser - } - }); - }, [ dispatchCatalogState ]); + setCatalogOptions(prevValue => + { + const giftConfiguration = new GiftWrappingConfiguration(parser); + + return { ...prevValue, giftConfiguration }; + }); + }, [ setCatalogOptions ]); const onMarketplaceMakeOfferResult = useCallback((event: MarketplaceMakeOfferResult) => { @@ -272,29 +290,25 @@ export const CatalogMessageHandler: FC<{}> = props => { const parser = event.getParser(); - if(!parser) return; - - dispatchCatalogState({ - type: CatalogActions.SET_MARKETPLACE_CONFIGURATION, - payload: { - marketplaceConfiguration: parser - } - }); - }, [dispatchCatalogState]); + setCatalogOptions(prevValue => + { + const marketplaceConfiguration = parser; + + return { ...prevValue, marketplaceConfiguration }; + }); + }, [ setCatalogOptions ]); const onClubGiftInfoEvent = useCallback((event: ClubGiftInfoEvent) => { const parser = event.getParser(); - if(!parser) return; + setCatalogOptions(prevValue => + { + const clubGifts = parser; - dispatchCatalogState({ - type: CatalogActions.SET_CLUB_GIFTS, - payload: { - clubGifts: parser - } - }); - }, [dispatchCatalogState]); + return { ...prevValue, clubGifts }; + }); + }, [ setCatalogOptions ]); CreateMessageHook(CatalogPagesListEvent, onCatalogPagesListEvent); CreateMessageHook(CatalogPageMessageEvent, onCatalogPageMessageEvent); diff --git a/src/components/catalog/CatalogView.scss b/src/components/catalog/CatalogView.scss index c5273544..15c8ead1 100644 --- a/src/components/catalog/CatalogView.scss +++ b/src/components/catalog/CatalogView.scss @@ -5,6 +5,11 @@ font[size="16"] { font-size: 20px; } + + .catalog-search-button { + min-width: 30px; + width: 30px; + } } .nitro-catalog-navigation-grid-container { diff --git a/src/components/catalog/CatalogView.tsx b/src/components/catalog/CatalogView.tsx index 0b203ce9..296cdd26 100644 --- a/src/components/catalog/CatalogView.tsx +++ b/src/components/catalog/CatalogView.tsx @@ -1,10 +1,10 @@ import { FrontPageItem, GetCatalogIndexComposer, GetCatalogPageComposer, GetClubGiftInfo, GetGiftWrappingConfigurationComposer, GetMarketplaceConfigurationMessageComposer, ILinkEventTracker, RoomPreviewer } from '@nitrots/nitro-renderer'; -import { FC, useCallback, useEffect, useReducer, useState } from 'react'; +import { FC, useCallback, useEffect, useState } from 'react'; import { AddEventLinkTracker, GetRoomEngine, LocalizeText, RemoveLinkEventTracker } from '../../api'; import { CREDITS, PlaySound } from '../../api/utils/PlaySound'; import { Column } from '../../common/Column'; import { Grid } from '../../common/Grid'; -import { CatalogEvent } from '../../events'; +import { CatalogPurchasedEvent } from '../../events'; import { BatchUpdates } from '../../hooks'; import { useUiEvent } from '../../hooks/events/ui/ui-event'; import { SendMessageHook } from '../../hooks/messages/message-event'; @@ -13,27 +13,25 @@ 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 { CatalogContextProvider } from './context/CatalogContext'; -import { CatalogReducer, initialCatalog } from './reducers/CatalogReducer'; import { CatalogGiftView } from './views/gift/CatalogGiftView'; import { CatalogNavigationView } from './views/navigation/CatalogNavigationView'; -import { CatalogPageView } from './views/page/CatalogPageView'; +import { GetCatalogLayout } from './views/page/layout/GetCatalogLayout'; import { MarketplacePostOfferView } from './views/page/layout/marketplace/MarketplacePostOfferView'; -const DUMMY_PAGE_ID_FOR_OFFER_SEARCH: number = -12345678; const REQUESTED_PAGE = new RequestedPage(); export const CatalogView: FC<{}> = props => { const [ isVisible, setIsVisible ] = useState(false); - const [ isBusy, setIsBusy ] = useState(false); - const [ forceRefresh, setForceRefresh ] = useState(false); const [ pageId, setPageId ] = useState(-1); const [ previousPageId, setPreviousPageId ] = useState(-1); const [ currentType, setCurrentType ] = useState(CatalogType.NORMAL); @@ -41,12 +39,12 @@ export const CatalogView: FC<{}> = props => const [ offersToNodes, setOffersToNodes ] = useState>(null); const [ currentPage, setCurrentPage ] = useState(null); const [ currentOffer, setCurrentOffer ] = useState(null); - const [ purchasableOffer, setPurchasableOffer ] = useState(null); const [ activeNodes, setActiveNodes ] = useState([]); const [ searchResult, setSearchResult ] = useState(null); const [ frontPageItems, setFrontPageItems ] = useState([]); const [ roomPreviewer, setRoomPreviewer ] = useState(null); - const [ catalogState, dispatchCatalogState ] = useReducer(CatalogReducer, initialCatalog); + const [ purchaseOptions, setPurchaseOptions ] = useState({}); + const [ catalogOptions, setCatalogOptions ] = useState({}); const resetState = useCallback(() => { @@ -58,7 +56,6 @@ export const CatalogView: FC<{}> = props => setOffersToNodes(null); setCurrentPage(null); setCurrentOffer(null); - setPurchasableOffer(null); setActiveNodes([]); setSearchResult(null); setFrontPageItems([]); @@ -66,13 +63,27 @@ export const CatalogView: FC<{}> = props => }); }, []); - const getFirstNodeByName = useCallback((name: string, node: ICatalogNode) => + 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 = (getFirstNodeByName(name, child) as ICatalogNode); + const found = (getNodeByName(name, child) as ICatalogNode); if(found) return found; } @@ -110,43 +121,28 @@ export const CatalogView: FC<{}> = props => if(pageId > -1) SendMessageHook(new GetCatalogPageComposer(pageId, offerId, currentType)); }, [ currentType ]); - const selectOffer = useCallback((offerId: number) => - { - if(!currentPage || !currentPage.offers || offerId < 0) return; - - for(const offer of currentPage.offers) - { - if(offer.offerId !== offerId) continue; - - setCurrentOffer(offer) - - return; - } - }, [ currentPage ]); - const showCatalogPage = useCallback((pageId: number, layoutCode: string, localization: IPageLocalization, offers: IPurchasableOffer[], offerId: number, acceptSeasonCurrencyAsCredits: boolean) => { - if(currentPage) - { - if(!forceRefresh && (currentPage.pageId === pageId)) - { - if(offerId > -1) selectOffer(offerId); - - return; - } - } - const catalogPage = (new CatalogPage(pageId, layoutCode, localization, offers, acceptSeasonCurrencyAsCredits) as ICatalogPage); BatchUpdates(() => { setCurrentPage(catalogPage); - setPreviousPageId(prevValue => ((pageId > DUMMY_PAGE_ID_FOR_OFFER_SEARCH) ? pageId : prevValue)); - setForceRefresh(false); + setPreviousPageId(prevValue => ((pageId !== -1) ? pageId : prevValue)); - selectOffer(offerId); + if((offerId > -1) && catalogPage.offers.length) + { + for(const offer of catalogPage.offers) + { + if(offer.offerId !== offerId) continue; + + setCurrentOffer(offer) + + break; + } + } }); - }, [ currentPage, forceRefresh, selectOffer ]); + }, []); const activateNode = useCallback((targetNode: ICatalogNode, offerId: number = -1) => { @@ -169,7 +165,7 @@ export const CatalogView: FC<{}> = props => let node = targetNode; - while(node && node.pageName !== 'root') + while(node && (node.pageName !== 'root')) { nodes.push(node); @@ -194,7 +190,9 @@ export const CatalogView: FC<{}> = props => { n.activate(); - if(n === targetNode.parent) n.open(); + if(n.parent) n.open(); + + if((n === targetNode.parent) && n.children.length) n.open(); } if(isActive && isOpen) targetNode.close(); @@ -206,6 +204,27 @@ export const CatalogView: FC<{}> = props => if(targetNode.pageId > -1) loadCatalogPage(targetNode.pageId, offerId); }, [ setActiveNodes, loadCatalogPage ]); + const openPageById = useCallback((id: number) => + { + BatchUpdates(() => + { + 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) => { BatchUpdates(() => @@ -220,12 +239,12 @@ export const CatalogView: FC<{}> = props => } else { - const node = getFirstNodeByName(name, rootNode); + const node = getNodeByName(name, rootNode); if(node) activateNode(node); } }); - }, [ isVisible, rootNode, getFirstNodeByName, activateNode ]); + }, [ isVisible, rootNode, getNodeByName, activateNode ]); const openPageByOfferId = useCallback((offerId: number) => { @@ -250,17 +269,12 @@ export const CatalogView: FC<{}> = props => }); }, [ isVisible, getNodesByOfferId, activateNode ]); - const onCatalogEvent = useCallback((event: CatalogEvent) => + const onCatalogPurchasedEvent = useCallback((event: CatalogPurchasedEvent) => { - switch(event.type) - { - case CatalogEvent.PURCHASE_SUCCESS: - PlaySound(CREDITS); - return; - } + PlaySound(CREDITS); }, []); - useUiEvent(CatalogEvent.PURCHASE_SUCCESS, onCatalogEvent); + useUiEvent(CatalogPurchasedEvent.PURCHASE_SUCCESS, onCatalogPurchasedEvent); const linkReceived = useCallback((url: string) => { @@ -294,8 +308,6 @@ export const CatalogView: FC<{}> = props => else { openPageByName(parts[2]); - - return; } } else @@ -367,6 +379,7 @@ export const CatalogView: FC<{}> = props => } return; case RequestedPage.REQUEST_TYPE_ID: + openPageById(REQUESTED_PAGE.requestById); REQUESTED_PAGE.resetRequest(); return; case RequestedPage.REQUEST_TYPE_OFFER: @@ -378,17 +391,20 @@ export const CatalogView: FC<{}> = props => REQUESTED_PAGE.resetRequest(); return; } - }, [ isVisible, rootNode, activeNodes, activateNode, openPageByOfferId, openPageByName ]); + }, [ isVisible, rootNode, activeNodes, activateNode, openPageById, openPageByOfferId, openPageByName ]); useEffect(() => { - if(!currentPage) return; + if(!searchResult && currentPage && (currentPage.pageId === -1)) openPageById(previousPageId); + }, [ searchResult, currentPage, previousPageId, openPageById ]); - setCurrentOffer(null); + useEffect(() => + { + return () => setCurrentOffer(null); }, [ currentPage ]); return ( - + { isVisible && @@ -417,7 +433,7 @@ export const CatalogView: FC<{}> = props => } - + { GetCatalogLayout(currentPage) } diff --git a/src/components/catalog/common/CatalogUtilities.ts b/src/components/catalog/common/CatalogUtilities.ts index 58719a10..f2655688 100644 --- a/src/components/catalog/common/CatalogUtilities.ts +++ b/src/components/catalog/common/CatalogUtilities.ts @@ -12,41 +12,6 @@ export const GetSubscriptionProductIcon = (id: number) => return ''; } -export const GetNodeById = (id: number, searchNode: ICatalogNode = null, rootNode: ICatalogNode) => -{ - if(!searchNode) searchNode = rootNode; - - if(!searchNode) return null; - - if((searchNode.pageId === id) && (searchNode !== rootNode)) return searchNode; - - for(const child of searchNode.children) - { - const node = (GetNodeById(id, child, rootNode) as ICatalogNode); - - if(node) return node; - } - - return null; -} - -export const GetNodesByOfferId = (offerId: number, flag: boolean = false, currentOffers: Map) => -{ - if(!currentOffers || !currentOffers.size) return null; - - if(flag) - { - const nodes: ICatalogNode[] = []; - const offers = currentOffers.get(offerId); - - if(offers && offers.length) for(const offer of offers) (offer.isVisible && nodes.push(offer)); - - if(nodes.length) return nodes; - } - - return currentOffers.get(offerId); -} - export const GetOfferNodes = (offerNodes: Map, offerId: number) => { const nodes = offerNodes.get(offerId); diff --git a/src/components/catalog/common/ICatalogOptions.ts b/src/components/catalog/common/ICatalogOptions.ts new file mode 100644 index 00000000..49ed1737 --- /dev/null +++ b/src/components/catalog/common/ICatalogOptions.ts @@ -0,0 +1,15 @@ +import { ClubGiftInfoParser, ClubOfferData, HabboGroupEntryData, MarketplaceConfigurationMessageParser } from '@nitrots/nitro-renderer'; +import { CatalogPetPalette } from './CatalogPetPalette'; +import { GiftWrappingConfiguration } from './GiftWrappingConfiguration'; +import { SubscriptionInfo } from './SubscriptionInfo'; + +export interface ICatalogOptions +{ + groups?: HabboGroupEntryData[]; + petPalettes?: CatalogPetPalette[]; + clubOffers?: ClubOfferData[]; + clubGifts?: ClubGiftInfoParser; + subscriptionInfo?: SubscriptionInfo; + giftConfiguration?: GiftWrappingConfiguration; + marketplaceConfiguration?: MarketplaceConfigurationMessageParser; +} diff --git a/src/components/catalog/common/IProduct.ts b/src/components/catalog/common/IProduct.ts index ec00a428..4a1a392d 100644 --- a/src/components/catalog/common/IProduct.ts +++ b/src/components/catalog/common/IProduct.ts @@ -4,13 +4,13 @@ import { IPurchasableOffer } from './IPurchasableOffer'; export interface IProduct { getIconUrl(offer?: IPurchasableOffer): string; - readonly productType: string; - readonly productClassId: number; - readonly extraParam: string; - readonly productCount: number; - readonly productData: IProductData; - readonly furnitureData: IFurnitureData; - readonly isUniqueLimitedItem: boolean; - readonly uniqueLimitedItemSeriesSize: number; + productType: string; + productClassId: number; + extraParam: string; + productCount: number; + productData: IProductData; + furnitureData: IFurnitureData; + isUniqueLimitedItem: boolean; + uniqueLimitedItemSeriesSize: number; uniqueLimitedItemsLeft: number; } diff --git a/src/components/catalog/common/IPurchasableOffer.ts b/src/components/catalog/common/IPurchasableOffer.ts index d3198bfa..cc2693f7 100644 --- a/src/components/catalog/common/IPurchasableOffer.ts +++ b/src/components/catalog/common/IPurchasableOffer.ts @@ -3,21 +3,21 @@ import { IProduct } from './IProduct'; export interface IPurchasableOffer { - readonly clubLevel: number; + clubLevel: number; page: ICatalogPage; - readonly offerId: number; - readonly localizationId: string; - readonly priceInCredits: number; - readonly priceInActivityPoints: number; - readonly activityPointType: number; - readonly giftable: boolean; - readonly product: IProduct; - readonly pricingModel: string; - readonly priceType: string; - readonly bundlePurchaseAllowed: boolean; - readonly isRentOffer: boolean; - readonly badgeCode: string; - readonly localizationName: string; - readonly localizationDescription: string; - readonly products: IProduct[]; + offerId: number; + localizationId: string; + priceInCredits: number; + priceInActivityPoints: number; + activityPointType: number; + giftable: boolean; + product: IProduct; + pricingModel: string; + priceType: string; + bundlePurchaseAllowed: boolean; + isRentOffer: boolean; + badgeCode: string; + localizationName: string; + localizationDescription: string; + products: IProduct[]; } diff --git a/src/components/catalog/common/IPurchaseOptions.ts b/src/components/catalog/common/IPurchaseOptions.ts new file mode 100644 index 00000000..30492a9d --- /dev/null +++ b/src/components/catalog/common/IPurchaseOptions.ts @@ -0,0 +1,10 @@ +import { IObjectData } from '@nitrots/nitro-renderer'; + +export interface IPurchaseOptions +{ + quantity?: number; + extraData?: string; + extraParamRequired?: boolean; + purchaseCallback?: Function; + previewStuffData?: IObjectData; +} diff --git a/src/components/catalog/context/CatalogContext.tsx b/src/components/catalog/context/CatalogContext.tsx index 14be5819..787fb08f 100644 --- a/src/components/catalog/context/CatalogContext.tsx +++ b/src/components/catalog/context/CatalogContext.tsx @@ -1,13 +1,14 @@ 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'; -import { ICatalogAction, ICatalogState } from '../reducers/CatalogReducer'; -export interface ICatalogContext +interface ICatalogContext { isVisible: boolean; isBusy: boolean; @@ -23,8 +24,6 @@ export interface ICatalogContext setCurrentPage: Dispatch>; currentOffer: IPurchasableOffer; setCurrentOffer: Dispatch>; - purchasableOffer: IPurchasableOffer; - setPurchasableOffer: Dispatch>; activeNodes: ICatalogNode[]; setActiveNodes: Dispatch>; searchResult: SearchResult; @@ -32,13 +31,15 @@ export interface ICatalogContext 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; - - catalogState: ICatalogState; - dispatchCatalogState: Dispatch; } const CatalogContext = createContext({ @@ -56,8 +57,6 @@ const CatalogContext = createContext({ setCurrentPage: null, currentOffer: null, setCurrentOffer: null, - purchasableOffer: null, - setPurchasableOffer: null, activeNodes: null, setActiveNodes: null, searchResult: null, @@ -65,12 +64,15 @@ const CatalogContext = createContext({ frontPageItems: null, setFrontPageItems: null, roomPreviewer: null, + purchaseOptions: null, + setPurchaseOptions: null, + catalogOptions: null, + setCatalogOptions: null, resetState: null, + getNodesByOfferId: null, loadCatalogPage: null, showCatalogPage: null, - activateNode: null, - catalogState: null, - dispatchCatalogState: null + activateNode: null }); export const CatalogContextProvider: FC> = props => diff --git a/src/components/catalog/reducers/CatalogReducer.tsx b/src/components/catalog/reducers/CatalogReducer.tsx deleted file mode 100644 index d7380e85..00000000 --- a/src/components/catalog/reducers/CatalogReducer.tsx +++ /dev/null @@ -1,117 +0,0 @@ -import { ClubGiftInfoParser, ClubOfferData, GiftWrappingConfigurationParser, MarketplaceConfigurationMessageParser } from '@nitrots/nitro-renderer'; -import { HabboGroupEntryData } from '@nitrots/nitro-renderer/src/nitro/communication/messages/parser/user/HabboGroupEntryData'; -import { Reducer } from 'react'; -import { CatalogPetPalette } from '../common/CatalogPetPalette'; -import { GiftWrappingConfiguration } from '../common/GiftWrappingConfiguration'; -import { SubscriptionInfo } from '../common/SubscriptionInfo'; - -export interface ICatalogState -{ - groups: HabboGroupEntryData[]; - petPalettes: CatalogPetPalette[]; - clubOffers: ClubOfferData[]; - clubGifts: ClubGiftInfoParser; - subscriptionInfo: SubscriptionInfo; - giftConfiguration: GiftWrappingConfiguration; - marketplaceConfiguration: MarketplaceConfigurationMessageParser; -} - -export interface ICatalogAction -{ - type: string; - payload: { - groups?: HabboGroupEntryData[]; - petPalette?: CatalogPetPalette; - clubOffers?: ClubOfferData[]; - clubGifts?: ClubGiftInfoParser; - subscriptionInfo?: SubscriptionInfo; - giftConfiguration?: GiftWrappingConfigurationParser; - marketplaceConfiguration?: MarketplaceConfigurationMessageParser; - } -} - -export class CatalogActions -{ - public static RESET_STATE: string = 'CA_RESET_STATE'; - public static SET_CLUB_OFFERS: string = 'CA_SET_CLUB_OFFERS'; - public static SET_GROUPS: string = 'CA_SET_GROUPS'; - public static SET_PET_PALETTE: string = 'CA_SET_PET_PALETTE'; - public static SET_SEARCH_RESULT: string = 'CA_SET_SEARCH_RESULT'; - public static SET_SUBSCRIPTION_INFO: string = 'CA_SET_SUBSCRIPTION_INFO'; - public static SET_GIFT_CONFIGURATION: string = 'CA_SET_GIFT_CONFIGURATION'; - public static SET_CLUB_GIFTS: string = 'CA_SET_CLUB_GIFTS'; - public static SET_MARKETPLACE_CONFIGURATION: string = 'CA_SET_MARKETPLACE_CONFIGURATION'; -} - -export const initialCatalog: ICatalogState = { - groups: [], - petPalettes: [], - clubOffers: null, - clubGifts: null, - subscriptionInfo: new SubscriptionInfo(), - giftConfiguration: null, - marketplaceConfiguration: null -} - -export const CatalogReducer: Reducer = (state, action) => -{ - switch(action.type) - { - case CatalogActions.SET_GROUPS: { - const groups = (action.payload.groups || null); - - return { ...state, groups }; - } - case CatalogActions.SET_PET_PALETTE: { - const petPalette = (action.payload.petPalette || null); - - let petPalettes = [ ...state.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 { ...state, petPalettes }; - } - case CatalogActions.SET_CLUB_OFFERS: { - const clubOffers = (action.payload.clubOffers || null); - - return { ...state, clubOffers }; - } - case CatalogActions.SET_SUBSCRIPTION_INFO: { - const subscriptionInfo = (action.payload.subscriptionInfo || null); - - return { ...state, subscriptionInfo }; - } - case CatalogActions.RESET_STATE: { - return { ...initialCatalog }; - } - case CatalogActions.SET_GIFT_CONFIGURATION: { - const giftConfiguration = new GiftWrappingConfiguration((action.payload.giftConfiguration || null)); - - return { ...state, giftConfiguration }; - } - case CatalogActions.SET_CLUB_GIFTS: { - const clubGifts = (action.payload.clubGifts || state.clubGifts || null); - - return { ...state, clubGifts }; - } - case CatalogActions.SET_MARKETPLACE_CONFIGURATION: { - const marketplaceConfiguration = (action.payload.marketplaceConfiguration || state.marketplaceConfiguration || null); - - return { ...state, marketplaceConfiguration } - } - default: - return state; - } -} diff --git a/src/components/catalog/views/catalog-room-previewer/CatalogRoomPreviewerView.tsx b/src/components/catalog/views/catalog-room-previewer/CatalogRoomPreviewerView.tsx index 6d2318d4..a5257112 100644 --- a/src/components/catalog/views/catalog-room-previewer/CatalogRoomPreviewerView.tsx +++ b/src/components/catalog/views/catalog-room-previewer/CatalogRoomPreviewerView.tsx @@ -1,26 +1,16 @@ import { NitroToolbarAnimateIconEvent, TextureUtils, ToolbarIconEnum } from '@nitrots/nitro-renderer'; -import { FC, useCallback, useRef, useState } from 'react'; +import { FC, useCallback, useRef } from 'react'; import { GetRoomEngine } from '../../../../api'; -import { CatalogEvent, CatalogSelectProductEvent } from '../../../../events'; -import { CatalogWidgetEvent } from '../../../../events/catalog/CatalogWidgetEvent'; +import { CatalogPurchasedEvent } from '../../../../events'; import { useUiEvent } from '../../../../hooks'; import { RoomPreviewerView } from '../../../../views/shared/room-previewer/RoomPreviewerView'; import { RoomPreviewerViewProps } from '../../../../views/shared/room-previewer/RoomPreviewerView.types'; -import { IPurchasableOffer } from '../../common/IPurchasableOffer'; export const CatalogRoomPreviewerView: FC = props => { const { roomPreviewer = null } = props; - const [ offer, setOffer ] = useState(null); const elementRef = useRef(null); - const onCatalogSelectProductEvent = useCallback((event: CatalogSelectProductEvent) => - { - setOffer(event.offer); - }, []); - - useUiEvent(CatalogWidgetEvent.SELECT_PRODUCT, onCatalogSelectProductEvent) - const animatePurchase = useCallback(() => { if(!elementRef) return; @@ -44,18 +34,13 @@ export const CatalogRoomPreviewerView: FC = props => GetRoomEngine().events.dispatchEvent(event); }, [ roomPreviewer ]); - - const onCatalogEvent = useCallback((event: CatalogEvent) => + + const onCatalogPurchasedEvent = useCallback((event: CatalogPurchasedEvent) => { - switch(event.type) - { - case CatalogEvent.PURCHASE_SUCCESS: - animatePurchase(); - return; - } + animatePurchase(); }, [ animatePurchase ]); - useUiEvent(CatalogEvent.PURCHASE_SUCCESS, onCatalogEvent); + useUiEvent(CatalogPurchasedEvent.PURCHASE_SUCCESS, onCatalogPurchasedEvent); return (
diff --git a/src/components/catalog/views/gift/CatalogGiftView.tsx b/src/components/catalog/views/gift/CatalogGiftView.tsx index 53e65d89..05fa23c6 100644 --- a/src/components/catalog/views/gift/CatalogGiftView.tsx +++ b/src/components/catalog/views/gift/CatalogGiftView.tsx @@ -9,7 +9,7 @@ import { Column } from '../../../../common/Column'; import { Flex } from '../../../../common/Flex'; import { FormGroup } from '../../../../common/FormGroup'; import { Text } from '../../../../common/Text'; -import { CatalogEvent } from '../../../../events'; +import { CatalogEvent, CatalogPurchasedEvent } from '../../../../events'; import { CatalogInitGiftEvent } from '../../../../events/catalog/CatalogInitGiftEvent'; import { BatchUpdates, SendMessageHook, useUiEvent } from '../../../../hooks'; import { NitroCardContentView, NitroCardHeaderView, NitroCardView, NitroLayoutGiftCardView } from '../../../../layout'; @@ -32,8 +32,8 @@ export const CatalogGiftView: FC<{}> = props => const [ maxBoxIndex, setMaxBoxIndex ] = useState(0); const [ maxRibbonIndex, setMaxRibbonIndex ] = useState(0); const [ receiverNotFound, setReceiverNotFound ] = useState(false); - const { catalogState = null } = useCatalogContext(); - const { giftConfiguration = null } = catalogState; + const { catalogOptions = null } = useCatalogContext(); + const { giftConfiguration = null } = catalogOptions; const close = useCallback(() => { @@ -56,7 +56,7 @@ export const CatalogGiftView: FC<{}> = props => { switch(event.type) { - case CatalogEvent.PURCHASE_SUCCESS: + case CatalogPurchasedEvent.PURCHASE_SUCCESS: close(); return; case CatalogEvent.INIT_GIFT: @@ -77,7 +77,7 @@ export const CatalogGiftView: FC<{}> = props => } }, [ close ]); - useUiEvent(CatalogEvent.PURCHASE_SUCCESS, onCatalogEvent); + useUiEvent(CatalogPurchasedEvent.PURCHASE_SUCCESS, onCatalogEvent); useUiEvent(CatalogEvent.INIT_GIFT, onCatalogEvent); useUiEvent(CatalogEvent.GIFT_RECEIVER_NOT_FOUND, onCatalogEvent); diff --git a/src/components/catalog/views/navigation/CatalogNavigationItemView.tsx b/src/components/catalog/views/navigation/CatalogNavigationItemView.tsx index 1d40bc01..088b253a 100644 --- a/src/components/catalog/views/navigation/CatalogNavigationItemView.tsx +++ b/src/components/catalog/views/navigation/CatalogNavigationItemView.tsx @@ -19,7 +19,7 @@ export const CatalogNavigationItemView: FC = pro return ( <> - activateNode(node) }> + activateNode(node) }> { node.localization } { node.isBranch && diff --git a/src/components/catalog/views/page/CatalogPageView.tsx b/src/components/catalog/views/page/CatalogPageView.tsx deleted file mode 100644 index 635d3f89..00000000 --- a/src/components/catalog/views/page/CatalogPageView.tsx +++ /dev/null @@ -1,121 +0,0 @@ -import { IObjectData, RoomPreviewer, Vector3d } from '@nitrots/nitro-renderer'; -import { FC, useCallback, useEffect } from 'react'; -import { GetAvatarRenderManager, GetSessionDataManager } from '../../../../api'; -import { CatalogPageReadyEvent, SetRoomPreviewerStuffDataEvent } from '../../../../events'; -import { dispatchUiEvent, useUiEvent } from '../../../../hooks'; -import { FurniCategory } from '../../common/FurniCategory'; -import { ICatalogPage } from '../../common/ICatalogPage'; -import { IPurchasableOffer } from '../../common/IPurchasableOffer'; -import { ProductTypeEnum } from '../../common/ProductTypeEnum'; -import { useCatalogContext } from '../../context/CatalogContext'; -import { GetCatalogLayout } from './layout/GetCatalogLayout'; - -export interface CatalogPageViewProps -{ - page: ICatalogPage; - roomPreviewer: RoomPreviewer; -} - -export const CatalogPageView: FC = props => -{ - const { page = null, roomPreviewer = null } = props; - const { currentOffer = null } = useCatalogContext(); - - const updatePreviewerForOffer = useCallback((offer: IPurchasableOffer, stuffData: IObjectData = null) => - { - if(!offer || !roomPreviewer) return; - - const product = offer.product; - - if(!product && !product.furnitureData && (product.productType !== ProductTypeEnum.ROBOT)) return; - - switch(product.productType.toLowerCase()) - { - case ProductTypeEnum.ROBOT: { - roomPreviewer.updateObjectRoom('default', 'default', 'default'); - const figure = GetAvatarRenderManager().getFigureStringWithFigureIds(product.extraParam, 'm', []); - - roomPreviewer.addAvatarIntoRoom(figure, 0); - - return; - } - case ProductTypeEnum.FLOOR: { - roomPreviewer.updateObjectRoom('default', 'default', 'default'); - - if(product.furnitureData.specialType === FurniCategory.FIGURE_PURCHASABLE_SET) - { - const setIds: number[] = []; - const sets = product.furnitureData.customParams.split(','); - - for(const set of sets) - { - const setId = parseInt(set); - - if(GetAvatarRenderManager().isValidFigureSetForGender(setId, GetSessionDataManager().gender)) setIds.push(setId); - } - - const figure = GetAvatarRenderManager().getFigureStringWithFigureIds(GetSessionDataManager().figure, GetSessionDataManager().gender, setIds); - - roomPreviewer.addAvatarIntoRoom(figure, 0); - } - else - { - roomPreviewer.addFurnitureIntoRoom(product.productClassId, new Vector3d(90), stuffData); - } - return; - } - case ProductTypeEnum.WALL: { - switch(product.furnitureData.className) - { - case 'floor': - roomPreviewer.reset(false); - roomPreviewer.updateObjectRoom(product.extraParam); - break; - case 'wallpaper': - roomPreviewer.reset(false); - roomPreviewer.updateObjectRoom(null, product.extraParam); - break; - case 'landscape': - roomPreviewer.reset(false); - roomPreviewer.updateObjectRoom(null, null, product.extraParam); - break; - default: - roomPreviewer.updateObjectRoom('default', 'default', 'default'); - roomPreviewer.addWallItemIntoRoom(product.productClassId, new Vector3d(90), product.extraParam); - return; - } - - const windowData = GetSessionDataManager().getWallItemDataByName('noob_window_double'); - - if(windowData) roomPreviewer.addWallItemIntoRoom(windowData.id, new Vector3d(90, 0, 0), windowData.customParams); - - return; - } - } - }, [ roomPreviewer ]); - - const onSetRoomPreviewerStuffDataEvent = useCallback((event: SetRoomPreviewerStuffDataEvent) => - { - if(roomPreviewer) roomPreviewer.reset(false); - - updatePreviewerForOffer(event.offer, event.stuffData); - }, [ roomPreviewer, updatePreviewerForOffer ]); - - useUiEvent(SetRoomPreviewerStuffDataEvent.UPDATE_STUFF_DATA, onSetRoomPreviewerStuffDataEvent); - - useEffect(() => - { - if(!currentOffer) return; - - updatePreviewerForOffer(currentOffer); - }, [ currentOffer, updatePreviewerForOffer ]); - - useEffect(() => - { - dispatchUiEvent(new CatalogPageReadyEvent()); - }, [ page ]); - - if(!page) return null; - - return GetCatalogLayout(page, roomPreviewer); -} diff --git a/src/components/catalog/views/page/layout/CatalogLayout.types.ts b/src/components/catalog/views/page/layout/CatalogLayout.types.ts index ba9be2bb..e9f608fc 100644 --- a/src/components/catalog/views/page/layout/CatalogLayout.types.ts +++ b/src/components/catalog/views/page/layout/CatalogLayout.types.ts @@ -1,8 +1,6 @@ -import { RoomPreviewer } from '@nitrots/nitro-renderer'; import { ICatalogPage } from '../../../common/ICatalogPage'; export interface CatalogLayoutProps { page: ICatalogPage; - roomPreviewer: RoomPreviewer; } diff --git a/src/components/catalog/views/page/layout/CatalogLayoutBadgeDisplayView.tsx b/src/components/catalog/views/page/layout/CatalogLayoutBadgeDisplayView.tsx index b90b60e1..59706505 100644 --- a/src/components/catalog/views/page/layout/CatalogLayoutBadgeDisplayView.tsx +++ b/src/components/catalog/views/page/layout/CatalogLayoutBadgeDisplayView.tsx @@ -1,78 +1,58 @@ -import { StringDataType } from '@nitrots/nitro-renderer'; -import { FC, useCallback, useEffect, useState } from 'react'; +import { FC } from 'react'; import { LocalizeText } from '../../../../../api'; +import { Base } from '../../../../../common/Base'; import { Column } from '../../../../../common/Column'; +import { Flex } from '../../../../../common/Flex'; import { Grid } from '../../../../../common/Grid'; -import { LayoutGridItem } from '../../../../../common/layout/LayoutGridItem'; import { Text } from '../../../../../common/Text'; -import { InventoryBadgesUpdatedEvent, SetRoomPreviewerStuffDataEvent } from '../../../../../events'; -import { InventoryBadgesRequestEvent } from '../../../../../events/inventory/InventoryBadgesRequestEvent'; -import { dispatchUiEvent, useUiEvent } from '../../../../../hooks'; -import { BadgeImageView } from '../../../../../views/shared/badge-image/BadgeImageView'; import { useCatalogContext } from '../../../context/CatalogContext'; -import { CatalogProductPreviewView } from '../offers/CatalogPageOfferPreviewView'; -import { CatalogPageOffersView } from '../offers/CatalogPageOffersView'; +import { CatalogBadgeSelectorWidgetView } from '../widgets/CatalogBadgeSelectorWidgetView'; +import { CatalogFirstProductSelectorWidgetView } from '../widgets/CatalogFirstProductSelectorWidgetView'; +import { CatalogItemGridWidgetView } from '../widgets/CatalogItemGridWidgetView'; +import { CatalogLimitedItemWidgetView } from '../widgets/CatalogLimitedItemWidgetView'; +import { CatalogPurchaseWidgetView } from '../widgets/CatalogPurchaseWidgetView'; +import { CatalogTotalPriceWidget } from '../widgets/CatalogTotalPriceWidget'; +import { CatalogViewProductWidgetView } from '../widgets/CatalogViewProductWidgetView'; import { CatalogLayoutProps } from './CatalogLayout.types'; export const CatalogLayoutBadgeDisplayView: FC = props => { - const { page = null, roomPreviewer = null } = props; - const [ badges, setBadges ] = useState([]); - const [ currentBadge, setCurrentBadge ] = useState(null); + const { page = null } = props; const { currentOffer = null } = useCatalogContext(); - const onInventoryBadgesUpdatedEvent = useCallback((event: InventoryBadgesUpdatedEvent) => - { - setBadges(event.badges); - }, []); - - useUiEvent(InventoryBadgesUpdatedEvent.BADGES_UPDATED, onInventoryBadgesUpdatedEvent); - - useEffect(() => - { - dispatchUiEvent(new InventoryBadgesRequestEvent(InventoryBadgesRequestEvent.REQUEST_BADGES)); - }, []); - - useEffect(() => - { - if(!currentBadge || !currentOffer) return; - - const productData = []; - - productData.push('0'); - productData.push(currentBadge); - productData.push(''); - productData.push(''); - productData.push(''); - - const stringDataType = new StringDataType(); - stringDataType.setValue(productData); - - dispatchUiEvent(new SetRoomPreviewerStuffDataEvent(currentOffer, stringDataType)); - }, [ currentBadge, currentOffer, roomPreviewer ]); - return ( - - - - - { LocalizeText('catalog_selectbadge') } - - { badges && (badges.length > 0) && badges.map(code => - { - return ( - setCurrentBadge(code) }> - - - ); - }) } - + <> + + + + + + { LocalizeText('catalog_selectbadge') } + + - - - { !!currentOffer && - } - - + + { !currentOffer && + <> + { !!page.localization.getImage(1) && } + + } + { currentOffer && + <> + + + + + + { currentOffer.localizationName } + + + + + + } + + + ); } diff --git a/src/components/catalog/views/page/layout/CatalogLayoutDefaultView.tsx b/src/components/catalog/views/page/layout/CatalogLayoutDefaultView.tsx index 77c9be0b..f6f37e0c 100644 --- a/src/components/catalog/views/page/layout/CatalogLayoutDefaultView.tsx +++ b/src/components/catalog/views/page/layout/CatalogLayoutDefaultView.tsx @@ -1,15 +1,22 @@ 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 '../../../context/CatalogContext'; -import { CatalogPageDetailsView } from '../../page-details/CatalogPageDetailsView'; -import { CatalogProductPreviewView } from '../offers/CatalogPageOfferPreviewView'; +import { CatalogAddOnBadgeWidgetView } from '../widgets/CatalogAddOnBadgeWidgetView'; import { CatalogItemGridWidgetView } from '../widgets/CatalogItemGridWidgetView'; +import { CatalogLimitedItemWidgetView } from '../widgets/CatalogLimitedItemWidgetView'; +import { CatalogPurchaseWidgetView } from '../widgets/CatalogPurchaseWidgetView'; +import { CatalogSpinnerWidgetView } from '../widgets/CatalogSpinnerWidgetView'; +import { CatalogTotalPriceWidget } from '../widgets/CatalogTotalPriceWidget'; +import { CatalogViewProductWidgetView } from '../widgets/CatalogViewProductWidgetView'; import { CatalogLayoutProps } from './CatalogLayout.types'; export const CatalogLayoutDefaultView: FC = props => { - const { page = null, roomPreviewer = null } = props; + const { page = null } = props; const { currentOffer = null } = useCatalogContext(); return ( @@ -17,11 +24,30 @@ export const CatalogLayoutDefaultView: FC = props => - + { !currentOffer && - } - { !!currentOffer && - } + <> + { !!page.localization.getImage(1) && } + + } + { currentOffer && + <> + + + + + + + { currentOffer.localizationName } + + + + + + + + + } ); diff --git a/src/components/catalog/views/page/layout/CatalogLayoutGuildCustomFurniView.tsx b/src/components/catalog/views/page/layout/CatalogLayoutGuildCustomFurniView.tsx index 07d3cf4e..82b0e6b5 100644 --- a/src/components/catalog/views/page/layout/CatalogLayoutGuildCustomFurniView.tsx +++ b/src/components/catalog/views/page/layout/CatalogLayoutGuildCustomFurniView.tsx @@ -1,67 +1,51 @@ -import { CatalogGroupsComposer, StringDataType } from '@nitrots/nitro-renderer'; -import { FC, useEffect, useMemo, useState } from 'react'; +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 { SetRoomPreviewerStuffDataEvent } from '../../../../../events'; -import { dispatchUiEvent } from '../../../../../hooks'; -import { SendMessageHook } from '../../../../../hooks/messages'; +import { Text } from '../../../../../common/Text'; import { useCatalogContext } from '../../../context/CatalogContext'; -import { CatalogSelectGroupView } from '../../select-group/CatalogSelectGroupView'; -import { CatalogProductPreviewView } from '../offers/CatalogPageOfferPreviewView'; -import { CatalogPageOffersView } from '../offers/CatalogPageOffersView'; +import { CatalogGuildBadgeWidgetView } from '../widgets/CatalogGuildBadgeWidgetView'; +import { CatalogGuildSelectorWidgetView } from '../widgets/CatalogGuildSelectorWidgetView'; +import { CatalogItemGridWidgetView } from '../widgets/CatalogItemGridWidgetView'; +import { CatalogPurchaseWidgetView } from '../widgets/CatalogPurchaseWidgetView'; +import { CatalogTotalPriceWidget } from '../widgets/CatalogTotalPriceWidget'; +import { CatalogViewProductWidgetView } from '../widgets/CatalogViewProductWidgetView'; import { CatalogLayoutProps } from './CatalogLayout.types'; export const CatalogLayouGuildCustomFurniView: FC = props => { - const { page = null, roomPreviewer = null } = props; - const [ selectedGroupIndex, setSelectedGroupIndex ] = useState(0); - const { currentOffer = null, catalogState = null } = useCatalogContext(); - const { groups = null } = catalogState; - - const selectedGroup = useMemo(() => - { - if(!groups || !groups.length) return; - - return groups[selectedGroupIndex]; - }, [ groups, selectedGroupIndex ]); - - useEffect(() => - { - if(!page) return; - - SendMessageHook(new CatalogGroupsComposer()); - }, [ page ]); - - useEffect(() => - { - if(!currentOffer || !groups[selectedGroupIndex]) return; - - const productData = []; - - productData.push('0'); - productData.push(groups[selectedGroupIndex].groupId); - productData.push(groups[selectedGroupIndex].badgeCode); - productData.push(groups[selectedGroupIndex].colorA); - productData.push(groups[selectedGroupIndex].colorB); - - const stringDataType = new StringDataType(); - stringDataType.setValue(productData); - - dispatchUiEvent(new SetRoomPreviewerStuffDataEvent(currentOffer, stringDataType)); - }, [ groups, currentOffer, selectedGroupIndex ]); - - if(!groups) return null; + const { page = null } = props; + const { currentOffer = null } = useCatalogContext(); return ( - + - - { !!currentOffer && - - - } + + { !currentOffer && + <> + { !!page.localization.getImage(1) && } + + } + { currentOffer && + <> + + + + + + { currentOffer.localizationName } + + + + + + + + + } ); diff --git a/src/components/catalog/views/page/layout/CatalogLayoutGuildForumView.tsx b/src/components/catalog/views/page/layout/CatalogLayoutGuildForumView.tsx index 48beda8f..1f00328b 100644 --- a/src/components/catalog/views/page/layout/CatalogLayoutGuildForumView.tsx +++ b/src/components/catalog/views/page/layout/CatalogLayoutGuildForumView.tsx @@ -5,7 +5,6 @@ import { Column } from '../../../../../common/Column'; import { Grid } from '../../../../../common/Grid'; import { SendMessageHook } from '../../../../../hooks/messages'; import { useCatalogContext } from '../../../context/CatalogContext'; -import { CatalogSelectGroupView } from '../../select-group/CatalogSelectGroupView'; import { CatalogProductPreviewView } from '../offers/CatalogPageOfferPreviewView'; import { CatalogLayoutProps } from './CatalogLayout.types'; @@ -13,8 +12,8 @@ export const CatalogLayouGuildForumView: FC = props => { const { page = null } = props; const [ selectedGroupIndex, setSelectedGroupIndex ] = useState(0); - const { currentOffer = null, setCurrentOffer = null, catalogState = null, dispatchCatalogState = null } = useCatalogContext(); - const { groups = null } = catalogState; + const { currentOffer = null, setCurrentOffer = null, catalogOptions = null } = useCatalogContext(); + const { groups = null } = catalogOptions; useEffect(() => { @@ -31,7 +30,7 @@ export const CatalogLayouGuildForumView: FC = props => { !!currentOffer && - + {/* */} } diff --git a/src/components/catalog/views/page/layout/CatalogLayoutRoomBundleView.tsx b/src/components/catalog/views/page/layout/CatalogLayoutRoomBundleView.tsx index 50c2494f..1d0d905f 100644 --- a/src/components/catalog/views/page/layout/CatalogLayoutRoomBundleView.tsx +++ b/src/components/catalog/views/page/layout/CatalogLayoutRoomBundleView.tsx @@ -1,27 +1,43 @@ import { FC } from 'react'; import { Column } from '../../../../../common/Column'; import { Grid } from '../../../../../common/Grid'; -import { useCatalogContext } from '../../../context/CatalogContext'; -import { CatalogPageDetailsView } from '../../page-details/CatalogPageDetailsView'; -import { CatalogPurchaseView } from '../purchase/CatalogPurchaseView'; +import { Text } from '../../../../../common/Text'; +import { CatalogAddOnBadgeWidgetView } from '../widgets/CatalogAddOnBadgeWidgetView'; +import { CatalogBundleGridWidgetView } from '../widgets/CatalogBundleGridWidgetView'; +import { CatalogFirstProductSelectorWidgetView } from '../widgets/CatalogFirstProductSelectorWidgetView'; +import { CatalogPurchaseWidgetView } from '../widgets/CatalogPurchaseWidgetView'; +import { CatalogSimplePriceWidgetView } from '../widgets/CatalogSimplePriceWidgetView'; import { CatalogLayoutProps } from './CatalogLayout.types'; export const CatalogLayoutRoomBundleView: FC = props => { - const { page = null, roomPreviewer = null } = props; - const { currentOffer = null } = useCatalogContext(); + const { page = null } = props; return ( - - - - {/* { currentOffer && currentOffer.products && (activeOffer.products.length > 0) && activeOffer.products.map((product, index) => )} */} - - - - - { currentOffer && } - - + <> + + + + { !!page.localization.getText(2) && + } + + + + + + { !!page.localization.getText(1) && + { page.localization.getText(1) } } + + { !!page.localization.getImage(1) && + } + + + + + + + + + ); } diff --git a/src/components/catalog/views/page/layout/CatalogLayoutSingleBundleView.tsx b/src/components/catalog/views/page/layout/CatalogLayoutSingleBundleView.tsx index d6d64f64..01f3c98d 100644 --- a/src/components/catalog/views/page/layout/CatalogLayoutSingleBundleView.tsx +++ b/src/components/catalog/views/page/layout/CatalogLayoutSingleBundleView.tsx @@ -1,10 +1,10 @@ import { FC } from 'react'; import { Column } from '../../../../../common/Column'; -import { Flex } from '../../../../../common/Flex'; import { Grid } from '../../../../../common/Grid'; import { Text } from '../../../../../common/Text'; import { CatalogAddOnBadgeWidgetView } from '../widgets/CatalogAddOnBadgeWidgetView'; import { CatalogBundleGridWidgetView } from '../widgets/CatalogBundleGridWidgetView'; +import { CatalogFirstProductSelectorWidgetView } from '../widgets/CatalogFirstProductSelectorWidgetView'; import { CatalogPurchaseWidgetView } from '../widgets/CatalogPurchaseWidgetView'; import { CatalogSimplePriceWidgetView } from '../widgets/CatalogSimplePriceWidgetView'; import { CatalogLayoutProps } from './CatalogLayout.types'; @@ -13,27 +13,27 @@ export const CatalogLayoutSingleBundleView: FC = props => { const { page = null } = props; - const imageUrl = page.localization.getImage(1); - return ( <> + - - - - + + { !!page.localization.getText(2) && + } + + - { page.localization.getText(1) } - - { imageUrl && } - - - - - - + { !!page.localization.getText(1) && + { page.localization.getText(1) } } + + { !!page.localization.getImage(1) && + } + + + + diff --git a/src/components/catalog/views/page/layout/CatalogLayoutSpacesView.tsx b/src/components/catalog/views/page/layout/CatalogLayoutSpacesView.tsx index 70650f64..a1ea0c1a 100644 --- a/src/components/catalog/views/page/layout/CatalogLayoutSpacesView.tsx +++ b/src/components/catalog/views/page/layout/CatalogLayoutSpacesView.tsx @@ -1,73 +1,51 @@ -import { FC, useEffect, useState } from 'react'; -import { LocalizeText } from '../../../../../api'; -import { Button } from '../../../../../common/Button'; -import { ButtonGroup } from '../../../../../common/ButtonGroup'; +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 { BatchUpdates } from '../../../../../hooks'; -import { IPurchasableOffer } from '../../../common/IPurchasableOffer'; +import { Text } from '../../../../../common/Text'; import { useCatalogContext } from '../../../context/CatalogContext'; -import { CatalogProductPreviewView } from '../offers/CatalogPageOfferPreviewView'; -import { CatalogPageOffersView } from '../offers/CatalogPageOffersView'; +import { CatalogPurchaseWidgetView } from '../widgets/CatalogPurchaseWidgetView'; +import { CatalogSpacesWidgetView } from '../widgets/CatalogSpacesWidgetView'; +import { CatalogTotalPriceWidget } from '../widgets/CatalogTotalPriceWidget'; +import { CatalogViewProductWidgetView } from '../widgets/CatalogViewProductWidgetView'; import { CatalogLayoutProps } from './CatalogLayout.types'; export const CatalogLayoutSpacesView: FC = props => { - const { page = null, roomPreviewer = null } = props; - const [ groups, setGroups ] = useState([]); - const [ activeGroupIndex, setActiveGroupIndex ] = useState(-1); - const { currentOffer = null, catalogState } = useCatalogContext(); - - const groupNames = [ 'floors', 'walls', 'views' ]; + const { page = null } = props; + const { currentOffer = null, roomPreviewer = null } = useCatalogContext(); useEffect(() => { - if(!page) return; - - const groupedOffers: IPurchasableOffer[][] = [ [], [], [] ]; - - for(const offer of page.offers) - { - const product = offer.product - - if(!product) continue; - - if(!product.furnitureData) continue; - - const className = product.furnitureData.className; - - switch(className) - { - case 'floor': - groupedOffers[0].push(offer); - break; - case 'wallpaper': - groupedOffers[1].push(offer); - break; - case 'landscape': - groupedOffers[2].push(offer); - break; - } - } - - BatchUpdates(() => - { - setGroups(groupedOffers); - setActiveGroupIndex(0); - }); - }, [ page ]); + roomPreviewer.updatePreviewObjectBoundingRectangle(new NitroPoint()); + }, [ roomPreviewer ]); return ( - - { groupNames.map((name, index) => )} - - + - - { !!currentOffer && - } + + { !currentOffer && + <> + { !!page.localization.getImage(1) && } + + } + { currentOffer && + <> + + + + + { currentOffer.localizationName } + + + + + + } ); diff --git a/src/components/catalog/views/page/layout/CatalogLayoutTrophiesView.tsx b/src/components/catalog/views/page/layout/CatalogLayoutTrophiesView.tsx index d3eee81a..ee269f8c 100644 --- a/src/components/catalog/views/page/layout/CatalogLayoutTrophiesView.tsx +++ b/src/components/catalog/views/page/layout/CatalogLayoutTrophiesView.tsx @@ -1,26 +1,56 @@ -import { FC, useState } from 'react'; +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 '../../../context/CatalogContext'; -import { CatalogProductPreviewView } from '../offers/CatalogPageOfferPreviewView'; -import { CatalogPageOffersView } from '../offers/CatalogPageOffersView'; +import { CatalogItemGridWidgetView } from '../widgets/CatalogItemGridWidgetView'; +import { CatalogPurchaseWidgetView } from '../widgets/CatalogPurchaseWidgetView'; +import { CatalogTotalPriceWidget } from '../widgets/CatalogTotalPriceWidget'; +import { CatalogViewProductWidgetView } from '../widgets/CatalogViewProductWidgetView'; import { CatalogLayoutProps } from './CatalogLayout.types'; export const CatalogLayoutTrophiesView: FC = props => { - const { page = null, roomPreviewer = null } = props; + const { page = null } = props; const [ trophyText, setTrophyText ] = useState(''); - const { currentOffer = null } = useCatalogContext(); + const { currentOffer = null, setPurchaseOptions = null } = useCatalogContext(); + + useEffect(() => + { + if(!currentOffer) return; + + setPurchaseOptions(prevValue => + { + const extraData = trophyText; + + return { ...prevValue, extraData }; + }); + }, [ currentOffer, trophyText, setPurchaseOptions ]); return ( - +