mirror of
https://github.com/billsonnn/nitro-react.git
synced 2024-11-27 08:00:51 +01:00
Start catalog changes
This commit is contained in:
parent
f23099c2fa
commit
85c562d14e
@ -6,7 +6,7 @@ export function GetFurnitureData(furniClassId: number, productType: string): IFu
|
|||||||
{
|
{
|
||||||
let furniData: IFurnitureData = null;
|
let furniData: IFurnitureData = null;
|
||||||
|
|
||||||
switch(productType.toUpperCase())
|
switch(productType.toLowerCase())
|
||||||
{
|
{
|
||||||
case ProductTypeEnum.FLOOR:
|
case ProductTypeEnum.FLOOR:
|
||||||
furniData = GetSessionDataManager().getFloorItemData(furniClassId);
|
furniData = GetSessionDataManager().getFloorItemData(furniClassId);
|
||||||
|
@ -1,47 +1,101 @@
|
|||||||
import { ApproveNameMessageEvent, CatalogPageMessageEvent, CatalogPagesListEvent, CatalogPublishedMessageEvent, ClubGiftInfoEvent, GiftReceiverNotFoundEvent, GiftWrappingConfigurationEvent, HabboClubOffersMessageEvent, LimitedEditionSoldOutEvent, MarketplaceConfigurationEvent, MarketplaceMakeOfferResult, ProductOfferEvent, PurchaseErrorMessageEvent, PurchaseNotAllowedMessageEvent, PurchaseOKMessageEvent, SellablePetPalettesMessageEvent, UserSubscriptionEvent } from '@nitrots/nitro-renderer';
|
import { ApproveNameMessageEvent, CatalogPageMessageEvent, CatalogPagesListEvent, CatalogPublishedMessageEvent, ClubGiftInfoEvent, GiftReceiverNotFoundEvent, GiftWrappingConfigurationEvent, HabboClubOffersMessageEvent, LimitedEditionSoldOutEvent, MarketplaceConfigurationEvent, MarketplaceMakeOfferResult, NodeData, ProductOfferEvent, PurchaseErrorMessageEvent, PurchaseNotAllowedMessageEvent, PurchaseOKMessageEvent, SellablePetPalettesMessageEvent, UserSubscriptionEvent } from '@nitrots/nitro-renderer';
|
||||||
import { GuildMembershipsMessageEvent } from '@nitrots/nitro-renderer/src/nitro/communication/messages/incoming/user/GuildMembershipsMessageEvent';
|
import { GuildMembershipsMessageEvent } from '@nitrots/nitro-renderer/src/nitro/communication/messages/incoming/user/GuildMembershipsMessageEvent';
|
||||||
import { FC, useCallback } from 'react';
|
import { FC, useCallback } from 'react';
|
||||||
import { LocalizeText } from '../../api';
|
import { GetFurnitureData, GetProductDataForLocalization, LocalizeText } from '../../api';
|
||||||
import { CatalogNameResultEvent, CatalogPurchaseFailureEvent } from '../../events';
|
import { CatalogNameResultEvent, CatalogPurchaseFailureEvent, CatalogSelectProductEvent } from '../../events';
|
||||||
import { CatalogGiftReceiverNotFoundEvent } from '../../events/catalog/CatalogGiftReceiverNotFoundEvent';
|
import { CatalogGiftReceiverNotFoundEvent } from '../../events/catalog/CatalogGiftReceiverNotFoundEvent';
|
||||||
import { CatalogPurchasedEvent } from '../../events/catalog/CatalogPurchasedEvent';
|
import { CatalogPurchasedEvent } from '../../events/catalog/CatalogPurchasedEvent';
|
||||||
import { CatalogPurchaseSoldOutEvent } from '../../events/catalog/CatalogPurchaseSoldOutEvent';
|
import { CatalogPurchaseSoldOutEvent } from '../../events/catalog/CatalogPurchaseSoldOutEvent';
|
||||||
|
import { BatchUpdates } from '../../hooks';
|
||||||
import { dispatchUiEvent } from '../../hooks/events/ui/ui-event';
|
import { dispatchUiEvent } from '../../hooks/events/ui/ui-event';
|
||||||
import { CreateMessageHook } from '../../hooks/messages/message-event';
|
import { CreateMessageHook } from '../../hooks/messages/message-event';
|
||||||
import { NotificationAlertType } from '../../views/notification-center/common/NotificationAlertType';
|
import { NotificationAlertType } from '../../views/notification-center/common/NotificationAlertType';
|
||||||
import { NotificationUtilities } from '../../views/notification-center/common/NotificationUtilities';
|
import { NotificationUtilities } from '../../views/notification-center/common/NotificationUtilities';
|
||||||
|
import { CatalogNode } from './common/CatalogNode';
|
||||||
import { CatalogPetPalette } from './common/CatalogPetPalette';
|
import { CatalogPetPalette } from './common/CatalogPetPalette';
|
||||||
|
import { CatalogType } from './common/CatalogType';
|
||||||
|
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';
|
||||||
import { SubscriptionInfo } from './common/SubscriptionInfo';
|
import { SubscriptionInfo } from './common/SubscriptionInfo';
|
||||||
import { useCatalogContext } from './context/CatalogContext';
|
import { useCatalogContext } from './context/CatalogContext';
|
||||||
import { CatalogActions } from './reducers/CatalogReducer';
|
import { CatalogActions } from './reducers/CatalogReducer';
|
||||||
|
|
||||||
export const CatalogMessageHandler: FC<{}> = props =>
|
export const CatalogMessageHandler: FC<{}> = props =>
|
||||||
{
|
{
|
||||||
const { catalogState = null, dispatchCatalogState = null } = useCatalogContext();
|
const { setIsBusy, pageId, currentType, setCurrentNode, setCurrentOffers, currentPage, setCurrentOffer, setPurchasableOffer, setFrontPageItems, showCatalogPage, catalogState, dispatchCatalogState } = useCatalogContext();
|
||||||
|
|
||||||
const onCatalogPagesListEvent = useCallback((event: CatalogPagesListEvent) =>
|
const onCatalogPagesListEvent = useCallback((event: CatalogPagesListEvent) =>
|
||||||
{
|
{
|
||||||
const parser = event.getParser();
|
const parser = event.getParser();
|
||||||
|
const offers: Map<number, ICatalogNode[]> = new Map();
|
||||||
|
|
||||||
dispatchCatalogState({
|
const getCatalogNode = (node: NodeData, depth: number, parent: ICatalogNode) =>
|
||||||
type: CatalogActions.SET_CATALOG_ROOT,
|
{
|
||||||
payload: {
|
const catalogNode = (new CatalogNode(node, depth, parent) as ICatalogNode);
|
||||||
root: parser.root
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
BatchUpdates(() =>
|
||||||
|
{
|
||||||
|
setCurrentNode(getCatalogNode(parser.root, 0, null));
|
||||||
|
setCurrentOffers(offers);
|
||||||
});
|
});
|
||||||
}, [ dispatchCatalogState ]);
|
}, [ setCurrentNode, setCurrentOffers ]);
|
||||||
|
|
||||||
const onCatalogPageMessageEvent = useCallback((event: CatalogPageMessageEvent) =>
|
const onCatalogPageMessageEvent = useCallback((event: CatalogPageMessageEvent) =>
|
||||||
{
|
{
|
||||||
const parser = event.getParser();
|
const parser = event.getParser();
|
||||||
|
|
||||||
dispatchCatalogState({
|
if(parser.catalogType !== currentType) return;
|
||||||
type: CatalogActions.SET_CATALOG_PAGE_PARSER,
|
|
||||||
payload: {
|
const purchasableOffers: IPurchasableOffer[] = [];
|
||||||
pageParser: parser
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
BatchUpdates(() =>
|
||||||
|
{
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, [ dispatchCatalogState ]);
|
}, [ currentType, pageId, setFrontPageItems, setIsBusy, showCatalogPage ]);
|
||||||
|
|
||||||
const onPurchaseOKMessageEvent = useCallback((event: PurchaseOKMessageEvent) =>
|
const onPurchaseOKMessageEvent = useCallback((event: PurchaseOKMessageEvent) =>
|
||||||
{
|
{
|
||||||
@ -72,14 +126,41 @@ export const CatalogMessageHandler: FC<{}> = props =>
|
|||||||
const onProductOfferEvent = useCallback((event: ProductOfferEvent) =>
|
const onProductOfferEvent = useCallback((event: ProductOfferEvent) =>
|
||||||
{
|
{
|
||||||
const parser = event.getParser();
|
const parser = event.getParser();
|
||||||
|
const offerData = parser.offer;
|
||||||
|
|
||||||
dispatchCatalogState({
|
if(!offerData || !offerData.products.length) return;
|
||||||
type: CatalogActions.SET_CATALOG_ACTIVE_OFFER,
|
|
||||||
payload: {
|
const offerProductData = offerData.products[0];
|
||||||
activeOffer: parser.offer
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
dispatchUiEvent(new CatalogSelectProductEvent(offer));
|
||||||
|
|
||||||
|
BatchUpdates(() =>
|
||||||
|
{
|
||||||
|
setCurrentOffer(offer);
|
||||||
|
setPurchasableOffer(offer);
|
||||||
});
|
});
|
||||||
}, [ dispatchCatalogState ]);
|
}, [ currentType, currentPage, setCurrentOffer, setPurchasableOffer ]);
|
||||||
|
|
||||||
const onSellablePetPalettesMessageEvent = useCallback((event: SellablePetPalettesMessageEvent) =>
|
const onSellablePetPalettesMessageEvent = useCallback((event: SellablePetPalettesMessageEvent) =>
|
||||||
{
|
{
|
||||||
|
@ -7,4 +7,26 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.nitro-catalog-navigation-grid-container {
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
border-color: #B6BEC5 !important;
|
||||||
|
background-color: #CDD3D9;
|
||||||
|
border: 2px solid;
|
||||||
|
|
||||||
|
.layout-grid-item {
|
||||||
|
font-size: $font-size-sm;
|
||||||
|
height: 23px !important;
|
||||||
|
border-color: unset !important;
|
||||||
|
background-color: #CDD3D9;
|
||||||
|
border: 0 !important;
|
||||||
|
padding: 1px 3px;
|
||||||
|
|
||||||
|
.svg-inline--fa {
|
||||||
|
color: $black;
|
||||||
|
font-size: 10px;
|
||||||
|
padding: 1px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@import './views/CatalogViews';
|
@import './views/CatalogViews';
|
||||||
|
@ -1,40 +1,100 @@
|
|||||||
import { GetCatalogIndexComposer, GetCatalogPageComposer, GetClubGiftInfo, GetGiftWrappingConfigurationComposer, GetMarketplaceConfigurationMessageComposer, ILinkEventTracker, INodeData, RoomPreviewer } from '@nitrots/nitro-renderer';
|
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, useReducer, useState } from 'react';
|
||||||
import { AddEventLinkTracker, GetRoomEngine, LocalizeText, RemoveLinkEventTracker } from '../../api';
|
import { AddEventLinkTracker, GetRoomEngine, LocalizeText, RemoveLinkEventTracker } from '../../api';
|
||||||
import { CREDITS, PlaySound } from '../../api/utils/PlaySound';
|
import { CREDITS, PlaySound } from '../../api/utils/PlaySound';
|
||||||
import { Column } from '../../common/Column';
|
import { Column } from '../../common/Column';
|
||||||
import { Grid } from '../../common/Grid';
|
import { Grid } from '../../common/Grid';
|
||||||
import { CatalogEvent } from '../../events';
|
import { CatalogEvent } from '../../events';
|
||||||
import { UseMountEffect } from '../../hooks';
|
import { BatchUpdates, UseMountEffect } from '../../hooks';
|
||||||
import { useUiEvent } from '../../hooks/events/ui/ui-event';
|
import { useUiEvent } from '../../hooks/events/ui/ui-event';
|
||||||
import { SendMessageHook } from '../../hooks/messages/message-event';
|
import { SendMessageHook } from '../../hooks/messages/message-event';
|
||||||
import { NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../layout';
|
import { NitroCardContentView, NitroCardHeaderView, NitroCardTabsView, NitroCardView } from '../../layout';
|
||||||
import { CatalogMessageHandler } from './CatalogMessageHandler';
|
import { CatalogMessageHandler } from './CatalogMessageHandler';
|
||||||
import { CatalogMode } from './common/CatalogMode';
|
import { CatalogPage } from './common/CatalogPage';
|
||||||
import { BuildCatalogPageTree } from './common/CatalogUtilities';
|
import { CatalogType } from './common/CatalogType';
|
||||||
|
import { ICatalogNode } from './common/ICatalogNode';
|
||||||
|
import { ICatalogPage } from './common/ICatalogPage';
|
||||||
|
import { IPageLocalization } from './common/IPageLocalization';
|
||||||
|
import { IPurchasableOffer } from './common/IPurchasableOffer';
|
||||||
|
import { RequestedPage } from './common/RequestedPage';
|
||||||
import { CatalogContextProvider } from './context/CatalogContext';
|
import { CatalogContextProvider } from './context/CatalogContext';
|
||||||
import { CatalogReducer, initialCatalog } from './reducers/CatalogReducer';
|
import { CatalogReducer, initialCatalog } from './reducers/CatalogReducer';
|
||||||
import { CatalogGiftView } from './views/gift/CatalogGiftView';
|
import { CatalogGiftView } from './views/gift/CatalogGiftView';
|
||||||
import { ACTIVE_PAGES, CatalogNavigationView } from './views/navigation/CatalogNavigationView';
|
import { CatalogNavigationView } from './views/navigation/CatalogNavigationView';
|
||||||
import { CatalogPageView } from './views/page/CatalogPageView';
|
import { CatalogPageView } from './views/page/CatalogPageView';
|
||||||
import { MarketplacePostOfferView } from './views/page/layout/marketplace/MarketplacePostOfferView';
|
import { MarketplacePostOfferView } from './views/page/layout/marketplace/MarketplacePostOfferView';
|
||||||
|
import { CatalogTabsViews } from './views/tabs/CatalogTabsView';
|
||||||
|
|
||||||
|
const DUMMY_PAGE_ID_FOR_OFFER_SEARCH: number = -12345678;
|
||||||
|
|
||||||
export const CatalogView: FC<{}> = props =>
|
export const CatalogView: FC<{}> = props =>
|
||||||
{
|
{
|
||||||
const [ isVisible, setIsVisible ] = useState(false);
|
const [ isVisible, setIsVisible ] = useState(false);
|
||||||
const [ roomPreviewer, setRoomPreviewer ] = useState<RoomPreviewer>(null);
|
const [ isInitialized, setIsInitialized ] = useState(false);
|
||||||
const [ pendingPageLookup, setPendingPageLookup ] = useState<{ value: string, isOffer: boolean }>(null);
|
const [ isBusy, setIsBusy ] = useState(false);
|
||||||
const [ pendingTree, setPendingTree ] = useState<INodeData[]>(null);
|
const [ forceRefresh, setForceRefresh ] = useState(false);
|
||||||
const [ pendingOpenTree, setPendingOpenTree ] = useState<INodeData[]>(null);
|
const [ pageId, setPageId ] = useState(-1);
|
||||||
const [ catalogState, dispatchCatalogState ] = useReducer(CatalogReducer, initialCatalog);
|
const [ previousPageId, setPreviousPageId ] = useState(-1);
|
||||||
const [ currentTab, setCurrentTab ] = useState<INodeData>(null);
|
const [ currentType, setCurrentType ] = useState(CatalogType.NORMAL);
|
||||||
const { root = null, pageParser = null, activeOffer = null, searchResult = null } = catalogState;
|
const [ currentNode, setCurrentNode ] = useState<ICatalogNode>(null);
|
||||||
|
const [ currentOffers, setCurrentOffers ] = useState<Map<number, ICatalogNode[]>>(null);
|
||||||
|
const [ currentPage, setCurrentPage ] = useState<ICatalogPage>(null);
|
||||||
|
const [ currentOffer, setCurrentOffer ] = useState<IPurchasableOffer>(null);
|
||||||
|
const [ purchasableOffer, setPurchasableOffer ] = useState<IPurchasableOffer>(null);
|
||||||
|
const [ currentTab, setCurrentTab ] = useState<ICatalogNode>(null);
|
||||||
|
const [ activeNodes, setActiveNodes ] = useState<ICatalogNode[]>([]);
|
||||||
|
const [ lastActiveNodes, setLastActiveNodes ] = useState<ICatalogNode[]>(null);
|
||||||
|
const [ frontPageItems, setFrontPageItems ] = useState<FrontPageItem[]>([]);
|
||||||
|
|
||||||
const saveActivePages = useCallback(() =>
|
|
||||||
|
const [ requestedPage, setRequestedPage ] = useState(new RequestedPage());
|
||||||
|
const [ roomPreviewer, setRoomPreviewer ] = useState<RoomPreviewer>(null);
|
||||||
|
const [ catalogState, dispatchCatalogState ] = useReducer(CatalogReducer, initialCatalog);
|
||||||
|
|
||||||
|
const loadCatalogPage = useCallback((pageId: number, offerId: number, forceRefresh: boolean = false) =>
|
||||||
{
|
{
|
||||||
setPendingOpenTree(ACTIVE_PAGES.slice());
|
if(pageId < 0) return;
|
||||||
|
|
||||||
|
BatchUpdates(() =>
|
||||||
|
{
|
||||||
|
setIsBusy(true);
|
||||||
|
setPageId(pageId);
|
||||||
|
|
||||||
|
if(forceRefresh) setForceRefresh(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
SendMessageHook(new GetCatalogPageComposer(pageId, offerId, currentType));
|
||||||
|
}, [ currentType ]);
|
||||||
|
|
||||||
|
const selectOffer = useCallback((offerId: number) =>
|
||||||
|
{
|
||||||
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
selectOffer(offerId);
|
||||||
|
});
|
||||||
|
}, [ currentPage, forceRefresh, selectOffer ]);
|
||||||
|
|
||||||
const onCatalogEvent = useCallback((event: CatalogEvent) =>
|
const onCatalogEvent = useCallback((event: CatalogEvent) =>
|
||||||
{
|
{
|
||||||
let save = false;
|
let save = false;
|
||||||
@ -56,9 +116,7 @@ export const CatalogView: FC<{}> = props =>
|
|||||||
PlaySound(CREDITS);
|
PlaySound(CREDITS);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}, []);
|
||||||
if(save) saveActivePages();
|
|
||||||
}, [ saveActivePages ]);
|
|
||||||
|
|
||||||
useUiEvent(CatalogEvent.SHOW_CATALOG, onCatalogEvent);
|
useUiEvent(CatalogEvent.SHOW_CATALOG, onCatalogEvent);
|
||||||
useUiEvent(CatalogEvent.HIDE_CATALOG, onCatalogEvent);
|
useUiEvent(CatalogEvent.HIDE_CATALOG, onCatalogEvent);
|
||||||
@ -82,13 +140,13 @@ export const CatalogView: FC<{}> = props =>
|
|||||||
switch(parts[2])
|
switch(parts[2])
|
||||||
{
|
{
|
||||||
case 'offerId':
|
case 'offerId':
|
||||||
setPendingPageLookup({ value: parts[3], isOffer: true });
|
//setPendingPageLookup({ value: parts[3], isOffer: true });
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setPendingPageLookup({ value: parts[2], isOffer: false });
|
//setPendingPageLookup({ value: parts[2], isOffer: false });
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -111,71 +169,6 @@ export const CatalogView: FC<{}> = props =>
|
|||||||
return () => RemoveLinkEventTracker(linkTracker);
|
return () => RemoveLinkEventTracker(linkTracker);
|
||||||
}, [ linkReceived ]);
|
}, [ linkReceived ]);
|
||||||
|
|
||||||
useEffect(() =>
|
|
||||||
{
|
|
||||||
const loadCatalog = (((pendingPageLookup !== null) && !catalogState.root) || (isVisible && !catalogState.root));
|
|
||||||
|
|
||||||
if(loadCatalog)
|
|
||||||
{
|
|
||||||
SendMessageHook(new GetCatalogIndexComposer(CatalogMode.MODE_NORMAL));
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(catalogState.root)
|
|
||||||
{
|
|
||||||
if(!isVisible && (pendingPageLookup !== null))
|
|
||||||
{
|
|
||||||
setIsVisible(true);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(pendingPageLookup !== null || pendingOpenTree)
|
|
||||||
{
|
|
||||||
let tree: INodeData[] = [];
|
|
||||||
|
|
||||||
if(pendingPageLookup !== null)
|
|
||||||
{
|
|
||||||
tree = BuildCatalogPageTree(catalogState.root, pendingPageLookup.value, pendingPageLookup.isOffer);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tree = pendingOpenTree.slice();
|
|
||||||
}
|
|
||||||
|
|
||||||
setCurrentTab(tree.shift());
|
|
||||||
setPendingOpenTree(null);
|
|
||||||
setPendingPageLookup(null);
|
|
||||||
setPendingTree(tree);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
setCurrentTab(prevValue =>
|
|
||||||
{
|
|
||||||
if(catalogState.root.children.length)
|
|
||||||
{
|
|
||||||
if(prevValue)
|
|
||||||
{
|
|
||||||
if(catalogState.root.children.indexOf(prevValue) >= 0) return prevValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ((catalogState.root.children.length && catalogState.root.children[0]) || null);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [ isVisible, pendingPageLookup, pendingOpenTree, catalogState.root, setCurrentTab ]);
|
|
||||||
|
|
||||||
useEffect(() =>
|
|
||||||
{
|
|
||||||
if(!currentTab) return;
|
|
||||||
|
|
||||||
SendMessageHook(new GetCatalogPageComposer(currentTab.pageId, -1, CatalogMode.MODE_NORMAL));
|
|
||||||
}, [ currentTab ]);
|
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
setRoomPreviewer(new RoomPreviewer(GetRoomEngine(), ++RoomPreviewer.PREVIEW_COUNTER));
|
setRoomPreviewer(new RoomPreviewer(GetRoomEngine(), ++RoomPreviewer.PREVIEW_COUNTER));
|
||||||
@ -191,6 +184,124 @@ export const CatalogView: FC<{}> = props =>
|
|||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
if(!currentNode) return;
|
||||||
|
|
||||||
|
switch(requestedPage.requestType)
|
||||||
|
{
|
||||||
|
// case RequestedPage.REQUEST_TYPE_NONE:
|
||||||
|
// loadFrontPage();
|
||||||
|
// return;
|
||||||
|
case RequestedPage.REQUEST_TYPE_ID:
|
||||||
|
requestedPage.resetRequest();
|
||||||
|
return;
|
||||||
|
case RequestedPage.REQUEST_TYPE_NAME:
|
||||||
|
requestedPage.resetRequest();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}, [ currentNode, requestedPage ]);
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
if(!isVisible) return;
|
||||||
|
|
||||||
|
if(!isInitialized) SendMessageHook(new GetCatalogIndexComposer(currentType));
|
||||||
|
}, [ isVisible, isInitialized, currentType ]);
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
if(!currentNode || !currentTab) return;
|
||||||
|
|
||||||
|
const activeNodes: ICatalogNode[] = [];
|
||||||
|
|
||||||
|
if(currentTab.isVisible && !currentTab.children.length && (currentTab !== currentNode))
|
||||||
|
{
|
||||||
|
loadCatalogPage(currentTab.pageId, -1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(currentTab.children.length)
|
||||||
|
{
|
||||||
|
for(const child of currentTab.children)
|
||||||
|
{
|
||||||
|
if(child.isVisible)
|
||||||
|
{
|
||||||
|
activeNodes.push(child);
|
||||||
|
|
||||||
|
loadCatalogPage(child.pageId, -1);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if(currentTab.children.length)
|
||||||
|
// {
|
||||||
|
// for(const child of currentTab.children)
|
||||||
|
// {
|
||||||
|
// if(child.isVisible)
|
||||||
|
// {
|
||||||
|
// activeNodes.push(child);
|
||||||
|
|
||||||
|
// loadCatalogPage(child.pageId, -1);
|
||||||
|
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
setActiveNodes(activeNodes);
|
||||||
|
}, [ currentNode, currentTab, loadCatalogPage ]);
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
if(!currentPage) return;
|
||||||
|
|
||||||
|
setCurrentOffer(null);
|
||||||
|
}, [ currentPage ]);
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
if(!currentNode) return;
|
||||||
|
|
||||||
|
BatchUpdates(() =>
|
||||||
|
{
|
||||||
|
setIsInitialized(true);
|
||||||
|
|
||||||
|
if(currentNode.isBranch)
|
||||||
|
{
|
||||||
|
for(const child of currentNode.children)
|
||||||
|
{
|
||||||
|
if(child && child.isVisible)
|
||||||
|
{
|
||||||
|
setCurrentTab(child);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, [ currentNode ]);
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
if(!isVisible && !lastActiveNodes && activeNodes && activeNodes.length)
|
||||||
|
{
|
||||||
|
setLastActiveNodes(activeNodes.concat());
|
||||||
|
}
|
||||||
|
|
||||||
|
else if(isVisible && lastActiveNodes)
|
||||||
|
{
|
||||||
|
BatchUpdates(() =>
|
||||||
|
{
|
||||||
|
setActiveNodes(lastActiveNodes.concat());
|
||||||
|
setLastActiveNodes(null);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [ isVisible, lastActiveNodes, activeNodes ]);
|
||||||
|
|
||||||
UseMountEffect(() =>
|
UseMountEffect(() =>
|
||||||
{
|
{
|
||||||
SendMessageHook(new GetMarketplaceConfigurationMessageComposer());
|
SendMessageHook(new GetMarketplaceConfigurationMessageComposer());
|
||||||
@ -198,35 +309,22 @@ export const CatalogView: FC<{}> = props =>
|
|||||||
SendMessageHook(new GetClubGiftInfo());
|
SendMessageHook(new GetClubGiftInfo());
|
||||||
});
|
});
|
||||||
|
|
||||||
const currentNavigationPage = ((searchResult && searchResult.page) || currentTab);
|
|
||||||
const navigationHidden = !!(pageParser && pageParser.frontPageItems.length);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CatalogContextProvider value={ { catalogState, dispatchCatalogState } }>
|
<CatalogContextProvider value={ { isVisible, isBusy, setIsBusy, pageId, currentType, setCurrentType, currentNode, setCurrentNode, currentOffers, setCurrentOffers, currentPage, setCurrentPage, currentOffer, setCurrentOffer, purchasableOffer, setPurchasableOffer, activeNodes, setActiveNodes, frontPageItems, setFrontPageItems, loadCatalogPage, showCatalogPage, catalogState, dispatchCatalogState } }>
|
||||||
<CatalogMessageHandler />
|
<CatalogMessageHandler />
|
||||||
{ isVisible &&
|
{ isVisible &&
|
||||||
<NitroCardView uniqueKey="catalog" className="nitro-catalog">
|
<NitroCardView uniqueKey="catalog" className="nitro-catalog">
|
||||||
<NitroCardHeaderView headerText={ LocalizeText('catalog.title') } onCloseClick={ event => { saveActivePages(); setIsVisible(false); } } />
|
<NitroCardHeaderView headerText={ LocalizeText('catalog.title') } onCloseClick={ event => { setIsVisible(false); } } />
|
||||||
<NitroCardTabsView>
|
<NitroCardTabsView>
|
||||||
{ root && root.children.length && root.children.map((page, index) =>
|
<CatalogTabsViews node={ currentNode } currentTab={ currentTab } setCurrentTab={ setCurrentTab } />
|
||||||
{
|
|
||||||
if(!page.visible) return null;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<NitroCardTabsItemView key={ index } isActive={ (currentTab === page) } onClick={ event => setCurrentTab(page) }>
|
|
||||||
{ page.localization }
|
|
||||||
</NitroCardTabsItemView>
|
|
||||||
);
|
|
||||||
}) }
|
|
||||||
</NitroCardTabsView>
|
</NitroCardTabsView>
|
||||||
<NitroCardContentView>
|
<NitroCardContentView>
|
||||||
<Grid>
|
<Grid>
|
||||||
{ currentNavigationPage && !navigationHidden &&
|
|
||||||
<Column size={ 3 } overflow="hidden">
|
<Column size={ 3 } overflow="hidden">
|
||||||
<CatalogNavigationView page={ currentNavigationPage } pendingTree={ pendingTree } setPendingTree={ setPendingTree } />
|
<CatalogNavigationView node={ currentTab } />
|
||||||
</Column> }
|
</Column>
|
||||||
<Column size={ (navigationHidden ? 12 : 9) } overflow="hidden">
|
<Column size={ 9 } overflow="hidden">
|
||||||
<CatalogPageView roomPreviewer={ roomPreviewer } />
|
<CatalogPageView page={ currentPage } roomPreviewer={ roomPreviewer } />
|
||||||
</Column>
|
</Column>
|
||||||
</Grid>
|
</Grid>
|
||||||
</NitroCardContentView>
|
</NitroCardContentView>
|
||||||
|
95
src/components/catalog/common/CatalogNode.ts
Normal file
95
src/components/catalog/common/CatalogNode.ts
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
import { NodeData } from '@nitrots/nitro-renderer';
|
||||||
|
import { ICatalogNode } from './ICatalogNode';
|
||||||
|
|
||||||
|
export class CatalogNode implements ICatalogNode
|
||||||
|
{
|
||||||
|
private _depth: number = 0;
|
||||||
|
private _localization: string = '';
|
||||||
|
private _pageId: number = -1;
|
||||||
|
private _pageName: string = '';
|
||||||
|
private _iconId: number = 0;
|
||||||
|
private _children: ICatalogNode[];
|
||||||
|
private _offerIds: number[];
|
||||||
|
private _parent: ICatalogNode;
|
||||||
|
private _isVisible: boolean;
|
||||||
|
|
||||||
|
constructor(node: NodeData, depth: number, parent: ICatalogNode)
|
||||||
|
{
|
||||||
|
this._depth = depth;
|
||||||
|
this._parent = parent;
|
||||||
|
this._localization = node.localization;
|
||||||
|
this._pageId = node.pageId;
|
||||||
|
this._pageName = node.pageName;
|
||||||
|
this._iconId = node.icon;
|
||||||
|
this._children = [];
|
||||||
|
this._offerIds = node.offerIds;
|
||||||
|
this._isVisible = node.visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get isOpen(): boolean
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get depth(): number
|
||||||
|
{
|
||||||
|
return this._depth;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get isBranch(): boolean
|
||||||
|
{
|
||||||
|
return (this._children.length > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get isLeaf(): boolean
|
||||||
|
{
|
||||||
|
return (this._children.length === 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get localization(): string
|
||||||
|
{
|
||||||
|
return this._localization;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get pageId(): number
|
||||||
|
{
|
||||||
|
return this._pageId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get pageName(): string
|
||||||
|
{
|
||||||
|
return this._pageName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get iconId(): number
|
||||||
|
{
|
||||||
|
return this._iconId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get children(): ICatalogNode[]
|
||||||
|
{
|
||||||
|
return this._children;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get offerIds(): number[]
|
||||||
|
{
|
||||||
|
return this._offerIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get parent(): ICatalogNode
|
||||||
|
{
|
||||||
|
return this._parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get isVisible(): boolean
|
||||||
|
{
|
||||||
|
return this._isVisible;
|
||||||
|
}
|
||||||
|
|
||||||
|
public addChild(child: ICatalogNode):void
|
||||||
|
{
|
||||||
|
if(!child) return;
|
||||||
|
|
||||||
|
this._children.push(child);
|
||||||
|
}
|
||||||
|
}
|
59
src/components/catalog/common/CatalogPage.ts
Normal file
59
src/components/catalog/common/CatalogPage.ts
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import { ICatalogPage } from './ICatalogPage';
|
||||||
|
import { IPageLocalization } from './IPageLocalization';
|
||||||
|
import { IPurchasableOffer } from './IPurchasableOffer';
|
||||||
|
|
||||||
|
export class CatalogPage implements ICatalogPage
|
||||||
|
{
|
||||||
|
public static MODE_NORMAL: number = 0;
|
||||||
|
|
||||||
|
private _pageId: number;
|
||||||
|
private _layoutCode: string;
|
||||||
|
private _localization: IPageLocalization;
|
||||||
|
private _offers: IPurchasableOffer[];
|
||||||
|
private _acceptSeasonCurrencyAsCredits: boolean;
|
||||||
|
private _mode: number;
|
||||||
|
|
||||||
|
constructor(pageId: number, layoutCode: string, localization: IPageLocalization, offers: IPurchasableOffer[], acceptSeasonCurrencyAsCredits: boolean, mode: number = -1)
|
||||||
|
{
|
||||||
|
this._pageId = pageId;
|
||||||
|
this._layoutCode = layoutCode;
|
||||||
|
this._localization = localization;
|
||||||
|
this._offers = offers;
|
||||||
|
this._acceptSeasonCurrencyAsCredits = acceptSeasonCurrencyAsCredits;
|
||||||
|
|
||||||
|
for(const offer of offers) (offer.page = this);
|
||||||
|
|
||||||
|
if(mode === -1) this._mode = CatalogPage.MODE_NORMAL;
|
||||||
|
else this._mode = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get pageId(): number
|
||||||
|
{
|
||||||
|
return this._pageId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get layoutCode(): string
|
||||||
|
{
|
||||||
|
return this._layoutCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get localization(): IPageLocalization
|
||||||
|
{
|
||||||
|
return this._localization;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get offers(): IPurchasableOffer[]
|
||||||
|
{
|
||||||
|
return this._offers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get acceptSeasonCurrencyAsCredits(): boolean
|
||||||
|
{
|
||||||
|
return this._acceptSeasonCurrencyAsCredits;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get mode(): number
|
||||||
|
{
|
||||||
|
return this._mode;
|
||||||
|
}
|
||||||
|
}
|
5
src/components/catalog/common/CatalogType.ts
Normal file
5
src/components/catalog/common/CatalogType.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export class CatalogType
|
||||||
|
{
|
||||||
|
public static NORMAL: string = 'NORMAL';
|
||||||
|
public static BUILDER: string = 'BUILDERS_CLUB';
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
import { CatalogPageMessageOfferData, CatalogPageMessageParser, IFurnitureData, INodeData, SellablePetPaletteData } from '@nitrots/nitro-renderer';
|
import { CatalogPageMessageOfferData, CatalogPageMessageParser, IFurnitureData, INodeData, SellablePetPaletteData } from '@nitrots/nitro-renderer';
|
||||||
import { GetConfiguration, GetProductDataForLocalization, GetRoomEngine } from '../../../api';
|
import { GetConfiguration, GetProductDataForLocalization, GetRoomEngine } from '../../../api';
|
||||||
|
import { ICatalogNode } from './ICatalogNode';
|
||||||
|
|
||||||
export interface ICatalogOffers
|
export interface ICatalogOffers
|
||||||
{
|
{
|
||||||
@ -21,25 +22,25 @@ export function GetOfferName(offer: CatalogPageMessageOfferData): string
|
|||||||
return offer.localizationId;
|
return offer.localizationId;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function GetOfferNodes(offers: ICatalogOffers, offerId: number): INodeData[]
|
export const GetOfferNodes = (offerNodes: Map<number, ICatalogNode[]>, offerId: number) =>
|
||||||
{
|
{
|
||||||
const pages = offers[offerId.toString()];
|
const nodes = offerNodes.get(offerId);
|
||||||
const allowedPages: INodeData[] = [];
|
const allowedNodes: ICatalogNode[] = [];
|
||||||
|
|
||||||
if(pages && pages.length)
|
if(nodes && nodes.length)
|
||||||
{
|
{
|
||||||
for(const page of pages)
|
for(const node of nodes)
|
||||||
{
|
{
|
||||||
if(!page.visible) continue;
|
if(!node.isVisible) continue;
|
||||||
|
|
||||||
allowedPages.push(page);
|
allowedNodes.push(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return allowedPages;
|
return allowedNodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SetOffersToNodes(offers: ICatalogOffers, pageData: INodeData): void
|
export const SetOffersToNodes = (offers: ICatalogOffers, pageData: INodeData) =>
|
||||||
{
|
{
|
||||||
if(pageData.offerIds && pageData.offerIds.length)
|
if(pageData.offerIds && pageData.offerIds.length)
|
||||||
{
|
{
|
||||||
|
33
src/components/catalog/common/FilterCatalogNode.ts
Normal file
33
src/components/catalog/common/FilterCatalogNode.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import { ICatalogNode } from './ICatalogNode';
|
||||||
|
|
||||||
|
export const FilterCatalogNode = (search: string, furniLines: string[], node: ICatalogNode, nodes: ICatalogNode[]) =>
|
||||||
|
{
|
||||||
|
if(node.isVisible && (node.pageId > 0))
|
||||||
|
{
|
||||||
|
let nodeAdded = false;
|
||||||
|
|
||||||
|
const hayStack = [ node.pageName, node.localization ].join(' ').toLowerCase().replace(/ /gi, '');
|
||||||
|
|
||||||
|
if(hayStack.indexOf(search) > -1)
|
||||||
|
{
|
||||||
|
nodes.push(node);
|
||||||
|
|
||||||
|
nodeAdded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!nodeAdded)
|
||||||
|
{
|
||||||
|
for(const furniLine of furniLines)
|
||||||
|
{
|
||||||
|
if(hayStack.indexOf(furniLine) >= 0)
|
||||||
|
{
|
||||||
|
nodes.push(node);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(const child of node.children) FilterCatalogNode(search, furniLines, child, nodes);
|
||||||
|
}
|
105
src/components/catalog/common/FurnitureOffer.ts
Normal file
105
src/components/catalog/common/FurnitureOffer.ts
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
import { IFurnitureData } from '@nitrots/nitro-renderer';
|
||||||
|
import { GetProductDataForLocalization } from '../../../api';
|
||||||
|
import { ICatalogPage } from './ICatalogPage';
|
||||||
|
import { IProduct } from './IProduct';
|
||||||
|
import { IPurchasableOffer } from './IPurchasableOffer';
|
||||||
|
import { Offer } from './Offer';
|
||||||
|
import { Product } from './Product';
|
||||||
|
|
||||||
|
export class FurnitureOffer implements IPurchasableOffer
|
||||||
|
{
|
||||||
|
private _furniData:IFurnitureData;
|
||||||
|
private _page: ICatalogPage;
|
||||||
|
private _product: IProduct;
|
||||||
|
|
||||||
|
constructor(furniData: IFurnitureData)
|
||||||
|
{
|
||||||
|
this._furniData = furniData;
|
||||||
|
this._product = (new Product(this._furniData.type, this._furniData.id, this._furniData.customParams, 1, GetProductDataForLocalization(this._furniData.className), this._furniData) as IProduct);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get offerId(): number
|
||||||
|
{
|
||||||
|
return (this.isRentOffer) ? this._furniData.rentOfferId : this._furniData.purchaseOfferId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get priceInActivityPoints(): number
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get activityPointType(): number
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get priceInCredits(): number
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get page(): ICatalogPage
|
||||||
|
{
|
||||||
|
return this._page;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set page(page: ICatalogPage)
|
||||||
|
{
|
||||||
|
this._page = page;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get priceType(): string
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public get product(): IProduct
|
||||||
|
{
|
||||||
|
return this._product;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get localizationId(): string
|
||||||
|
{
|
||||||
|
return 'roomItem.name.' + this._furniData.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get bundlePurchaseAllowed(): boolean
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get isRentOffer(): boolean
|
||||||
|
{
|
||||||
|
return (this._furniData.rentOfferId > -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get giftable(): boolean
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get pricingModel(): string
|
||||||
|
{
|
||||||
|
return Offer.PRICING_MODEL_FURNITURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get clubLevel(): number
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get badgeCode(): string
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public get localizationName(): string
|
||||||
|
{
|
||||||
|
return this._furniData.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get localizationDescription(): string
|
||||||
|
{
|
||||||
|
return this._furniData.description;
|
||||||
|
}
|
||||||
|
}
|
@ -27,7 +27,7 @@ export const GetProductIconUrl = (furniClassId: number, productType: string, cus
|
|||||||
iconName = [ 'th', 'wall', customParams ].join('_');
|
iconName = [ 'th', 'wall', customParams ].join('_');
|
||||||
break;
|
break;
|
||||||
case 'landscape':
|
case 'landscape':
|
||||||
iconName = [ 'th', furniData.className, customParams.replace('.', '_'), '001' ].join('_');
|
iconName = [ 'th', furniData.className, (customParams || '').replace('.', '_'), '001' ].join('_');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
16
src/components/catalog/common/ICatalogNode.ts
Normal file
16
src/components/catalog/common/ICatalogNode.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
export interface ICatalogNode
|
||||||
|
{
|
||||||
|
addChild(node: ICatalogNode): void;
|
||||||
|
readonly isOpen: boolean;
|
||||||
|
readonly depth: number;
|
||||||
|
readonly isBranch: boolean;
|
||||||
|
readonly isLeaf: boolean;
|
||||||
|
readonly localization: string;
|
||||||
|
readonly pageId: number;
|
||||||
|
readonly pageName: string;
|
||||||
|
readonly iconId: number;
|
||||||
|
readonly children: ICatalogNode[];
|
||||||
|
readonly offerIds: number[];
|
||||||
|
readonly parent: ICatalogNode;
|
||||||
|
readonly isVisible: boolean;
|
||||||
|
}
|
12
src/components/catalog/common/ICatalogPage.ts
Normal file
12
src/components/catalog/common/ICatalogPage.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { IPageLocalization } from './IPageLocalization';
|
||||||
|
import { IPurchasableOffer } from './IPurchasableOffer';
|
||||||
|
|
||||||
|
export interface ICatalogPage
|
||||||
|
{
|
||||||
|
readonly pageId: number;
|
||||||
|
readonly layoutCode: string;
|
||||||
|
readonly localization: IPageLocalization;
|
||||||
|
readonly offers: IPurchasableOffer[];
|
||||||
|
readonly acceptSeasonCurrencyAsCredits: boolean;
|
||||||
|
readonly mode: number;
|
||||||
|
}
|
5
src/components/catalog/common/IPageLocalization.ts
Normal file
5
src/components/catalog/common/IPageLocalization.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export interface IPageLocalization
|
||||||
|
{
|
||||||
|
getText(index: number): string
|
||||||
|
getImage(index: number): string
|
||||||
|
}
|
14
src/components/catalog/common/IProduct.ts
Normal file
14
src/components/catalog/common/IProduct.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { IFurnitureData, IProductData } from '@nitrots/nitro-renderer';
|
||||||
|
|
||||||
|
export interface IProduct
|
||||||
|
{
|
||||||
|
readonly productType: string;
|
||||||
|
readonly productClassId: number;
|
||||||
|
readonly extraParam: string;
|
||||||
|
readonly productCount: number;
|
||||||
|
readonly productData: IProductData;
|
||||||
|
readonly furnitureData: IFurnitureData;
|
||||||
|
readonly isUniqueLimitedItem: boolean;
|
||||||
|
readonly uniqueLimitedItemSeriesSize: number;
|
||||||
|
uniqueLimitedItemsLeft: number;
|
||||||
|
}
|
22
src/components/catalog/common/IPurchasableOffer.ts
Normal file
22
src/components/catalog/common/IPurchasableOffer.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { ICatalogPage } from './ICatalogPage';
|
||||||
|
import { IProduct } from './IProduct';
|
||||||
|
|
||||||
|
export interface IPurchasableOffer
|
||||||
|
{
|
||||||
|
readonly 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;
|
||||||
|
}
|
231
src/components/catalog/common/Offer.ts
Normal file
231
src/components/catalog/common/Offer.ts
Normal file
@ -0,0 +1,231 @@
|
|||||||
|
import { GetFurnitureData, GetProductDataForLocalization, LocalizeText } from '../../../api';
|
||||||
|
import { ICatalogPage } from './ICatalogPage';
|
||||||
|
import { IProduct } from './IProduct';
|
||||||
|
import { IPurchasableOffer } from './IPurchasableOffer';
|
||||||
|
import { Product } from './Product';
|
||||||
|
import { ProductTypeEnum } from './ProductTypeEnum';
|
||||||
|
|
||||||
|
export class Offer implements IPurchasableOffer
|
||||||
|
{
|
||||||
|
public static PRICING_MODEL_UNKNOWN: string = 'pricing_model_unknown';
|
||||||
|
public static PRICING_MODEL_SINGLE: string = 'pricing_model_single';
|
||||||
|
public static PRICING_MODEL_MULTI: string = 'pricing_model_multi';
|
||||||
|
public static PRICING_MODEL_BUNDLE: string = 'pricing_model_bundle';
|
||||||
|
public static PRICING_MODEL_FURNITURE: string = 'pricing_model_furniture';
|
||||||
|
public static PRICE_TYPE_NONE: string = 'price_type_none';
|
||||||
|
public static PRICE_TYPE_CREDITS: string = 'price_type_credits';
|
||||||
|
public static PRICE_TYPE_ACTIVITYPOINTS: string = 'price_type_activitypoints';
|
||||||
|
public static PRICE_TYPE_CREDITS_ACTIVITYPOINTS: string = 'price_type_credits_and_activitypoints';
|
||||||
|
|
||||||
|
private _pricingModel: string;
|
||||||
|
private _priceType: string;
|
||||||
|
private _offerId: number;
|
||||||
|
private _localizationId: string;
|
||||||
|
private _priceInCredits: number;
|
||||||
|
private _priceInActivityPoints: number;
|
||||||
|
private _activityPointType: number;
|
||||||
|
private _giftable: boolean;
|
||||||
|
private _isRentOffer: boolean;
|
||||||
|
private _page: ICatalogPage;
|
||||||
|
private _clubLevel: number = 0;
|
||||||
|
private _products: IProduct[];
|
||||||
|
private _badgeCode: string;
|
||||||
|
private _bundlePurchaseAllowed: boolean = false;
|
||||||
|
|
||||||
|
constructor(offerId: number, localizationId: string, isRentOffer: boolean, priceInCredits: number, priceInActivityPoints: number, activityPointType: number, giftable: boolean, clubLevel: number, products: IProduct[], bundlePurchaseAllowed: boolean)
|
||||||
|
{
|
||||||
|
this._offerId = offerId;
|
||||||
|
this._localizationId = localizationId;
|
||||||
|
this._isRentOffer = isRentOffer;
|
||||||
|
this._priceInCredits = priceInCredits;
|
||||||
|
this._priceInActivityPoints = priceInActivityPoints;
|
||||||
|
this._activityPointType = activityPointType;
|
||||||
|
this._giftable = giftable;
|
||||||
|
this._clubLevel = clubLevel;
|
||||||
|
this._products = products;
|
||||||
|
this._bundlePurchaseAllowed = bundlePurchaseAllowed;
|
||||||
|
|
||||||
|
this.setPricingModelForProducts();
|
||||||
|
this.setPricingType();
|
||||||
|
|
||||||
|
for(const product of products)
|
||||||
|
{
|
||||||
|
if(product.productType === ProductTypeEnum.BADGE)
|
||||||
|
{
|
||||||
|
this._badgeCode = product.extraParam;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public get clubLevel(): number
|
||||||
|
{
|
||||||
|
return this._clubLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get page(): ICatalogPage
|
||||||
|
{
|
||||||
|
return this._page;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set page(k: ICatalogPage)
|
||||||
|
{
|
||||||
|
this._page = k;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get offerId(): number
|
||||||
|
{
|
||||||
|
return this._offerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get localizationId(): string
|
||||||
|
{
|
||||||
|
return this._localizationId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get priceInCredits(): number
|
||||||
|
{
|
||||||
|
return this._priceInCredits;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get priceInActivityPoints(): number
|
||||||
|
{
|
||||||
|
return this._priceInActivityPoints;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get activityPointType(): number
|
||||||
|
{
|
||||||
|
return this._activityPointType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get giftable(): boolean
|
||||||
|
{
|
||||||
|
return this._giftable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get product(): IProduct
|
||||||
|
{
|
||||||
|
if(!this._products || !this._products.length) return null;
|
||||||
|
|
||||||
|
if(this._products.length === 1) return this._products[0];
|
||||||
|
|
||||||
|
const products = Product.stripAddonProducts(this._products);
|
||||||
|
|
||||||
|
if(products.length) return products[0];
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get pricingModel(): string
|
||||||
|
{
|
||||||
|
return this._pricingModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get priceType(): string
|
||||||
|
{
|
||||||
|
return this._priceType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get bundlePurchaseAllowed(): boolean
|
||||||
|
{
|
||||||
|
return this._bundlePurchaseAllowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get isRentOffer(): boolean
|
||||||
|
{
|
||||||
|
return this._isRentOffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get badgeCode(): string
|
||||||
|
{
|
||||||
|
return this._badgeCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get localizationName(): string
|
||||||
|
{
|
||||||
|
const productData = GetProductDataForLocalization(this._localizationId);
|
||||||
|
|
||||||
|
if(productData) return productData.name;
|
||||||
|
|
||||||
|
return LocalizeText(this._localizationId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get localizationDescription(): string
|
||||||
|
{
|
||||||
|
const productData = GetProductDataForLocalization(this._localizationId);
|
||||||
|
|
||||||
|
if(productData) return productData.description;
|
||||||
|
|
||||||
|
return LocalizeText(this._localizationId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private setPricingModelForProducts(): void
|
||||||
|
{
|
||||||
|
const products = Product.stripAddonProducts(this._products);
|
||||||
|
|
||||||
|
if(products.length === 1)
|
||||||
|
{
|
||||||
|
if(products[0].productCount === 1)
|
||||||
|
{
|
||||||
|
this._pricingModel = Offer.PRICING_MODEL_SINGLE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this._pricingModel = Offer.PRICING_MODEL_MULTI;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if(products.length > 1)
|
||||||
|
{
|
||||||
|
this._pricingModel = Offer.PRICING_MODEL_BUNDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this._pricingModel = Offer.PRICING_MODEL_UNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private setPricingType(): void
|
||||||
|
{
|
||||||
|
if((this._priceInCredits > 0) && (this._priceInActivityPoints > 0))
|
||||||
|
{
|
||||||
|
this._priceType = Offer.PRICE_TYPE_CREDITS_ACTIVITYPOINTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if(this._priceInCredits > 0)
|
||||||
|
{
|
||||||
|
this._priceType = Offer.PRICE_TYPE_CREDITS;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if(this._priceInActivityPoints > 0)
|
||||||
|
{
|
||||||
|
this._priceType = Offer.PRICE_TYPE_ACTIVITYPOINTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this._priceType = Offer.PRICE_TYPE_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public clone(): IPurchasableOffer
|
||||||
|
{
|
||||||
|
const products: IProduct[] = [];
|
||||||
|
const productData = GetProductDataForLocalization(this.localizationId);
|
||||||
|
|
||||||
|
for(const product of this._products)
|
||||||
|
{
|
||||||
|
const furnitureData = GetFurnitureData(product.productClassId, product.productType);
|
||||||
|
|
||||||
|
products.push(new Product(product.productType, product.productClassId, product.extraParam, product.productCount, productData, furnitureData));
|
||||||
|
}
|
||||||
|
|
||||||
|
const offer = new Offer(this.offerId, this.localizationId, this.isRentOffer, this.priceInCredits, this.priceInActivityPoints, this.activityPointType, this.giftable, this.clubLevel, products, this.bundlePurchaseAllowed);
|
||||||
|
|
||||||
|
offer.page = this.page;
|
||||||
|
|
||||||
|
return offer;
|
||||||
|
}
|
||||||
|
}
|
36
src/components/catalog/common/PageLocalization.ts
Normal file
36
src/components/catalog/common/PageLocalization.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import { GetConfiguration } from '../../../api';
|
||||||
|
import { IPageLocalization } from './IPageLocalization';
|
||||||
|
|
||||||
|
export class PageLocalization implements IPageLocalization
|
||||||
|
{
|
||||||
|
private _images: string[];
|
||||||
|
private _texts: string[]
|
||||||
|
|
||||||
|
constructor(images: string[], texts: string[])
|
||||||
|
{
|
||||||
|
this._images = images;
|
||||||
|
this._texts = texts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getText(index: number): string
|
||||||
|
{
|
||||||
|
let message = (this._texts[index] || '');
|
||||||
|
|
||||||
|
if(message && message.length) message = message.replace(/\r\n|\r|\n/g, '<br />');
|
||||||
|
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getImage(index: number): string
|
||||||
|
{
|
||||||
|
const imageName = (this._images[index] || '');
|
||||||
|
|
||||||
|
if(!imageName || !imageName.length) return null;
|
||||||
|
|
||||||
|
let assetUrl = GetConfiguration<string>('catalog.asset.image.url');
|
||||||
|
|
||||||
|
assetUrl = assetUrl.replace('%name%', imageName);
|
||||||
|
|
||||||
|
return assetUrl;
|
||||||
|
}
|
||||||
|
}
|
93
src/components/catalog/common/Product.ts
Normal file
93
src/components/catalog/common/Product.ts
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
import { IFurnitureData, IProductData } from '@nitrots/nitro-renderer';
|
||||||
|
import { IProduct } from './IProduct';
|
||||||
|
import { ProductTypeEnum } from './ProductTypeEnum';
|
||||||
|
|
||||||
|
export class Product implements IProduct
|
||||||
|
{
|
||||||
|
public static EFFECT_CLASSID_NINJA_DISAPPEAR: number = 108;
|
||||||
|
|
||||||
|
private _productType: string;
|
||||||
|
private _productClassId: number;
|
||||||
|
private _extraParam: string;
|
||||||
|
private _productCount: number;
|
||||||
|
private _productData: IProductData;
|
||||||
|
private _furnitureData: IFurnitureData;
|
||||||
|
private _isUniqueLimitedItem: boolean;
|
||||||
|
private _uniqueLimitedItemSeriesSize: number;
|
||||||
|
private _uniqueLimitedItemsLeft: number;
|
||||||
|
|
||||||
|
constructor(productType: string, productClassId: number, extraParam: string, productCount: number, productData: IProductData, furnitureData: IFurnitureData, isUniqueLimitedItem: boolean = false, uniqueLimitedItemSeriesSize: number = 0, uniqueLimitedItemsLeft: number = 0)
|
||||||
|
{
|
||||||
|
this._productType = productType;
|
||||||
|
this._productClassId = productClassId;
|
||||||
|
this._extraParam = extraParam;
|
||||||
|
this._productCount = productCount;
|
||||||
|
this._productData = productData;
|
||||||
|
this._furnitureData = furnitureData;
|
||||||
|
this._isUniqueLimitedItem = isUniqueLimitedItem;
|
||||||
|
this._uniqueLimitedItemSeriesSize = uniqueLimitedItemSeriesSize;
|
||||||
|
this._uniqueLimitedItemsLeft = uniqueLimitedItemsLeft;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static stripAddonProducts(products: IProduct[]): IProduct[]
|
||||||
|
{
|
||||||
|
if(products.length === 1) return products;
|
||||||
|
|
||||||
|
return products.filter(product => ((product.productType !== ProductTypeEnum.BADGE) && (product.productType !== ProductTypeEnum.EFFECT) && (product.productClassId !== Product.EFFECT_CLASSID_NINJA_DISAPPEAR)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public get productType(): string
|
||||||
|
{
|
||||||
|
return this._productType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get productClassId(): number
|
||||||
|
{
|
||||||
|
return this._productClassId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get extraParam(): string
|
||||||
|
{
|
||||||
|
return this._extraParam;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set extraParam(extraParam: string)
|
||||||
|
{
|
||||||
|
this._extraParam = extraParam;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get productCount(): number
|
||||||
|
{
|
||||||
|
return this._productCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get productData(): IProductData
|
||||||
|
{
|
||||||
|
return this._productData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get furnitureData(): IFurnitureData
|
||||||
|
{
|
||||||
|
return this._furnitureData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get isUniqueLimitedItem(): boolean
|
||||||
|
{
|
||||||
|
return this._isUniqueLimitedItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get uniqueLimitedItemSeriesSize(): number
|
||||||
|
{
|
||||||
|
return this._uniqueLimitedItemSeriesSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get uniqueLimitedItemsLeft(): number
|
||||||
|
{
|
||||||
|
return this._uniqueLimitedItemsLeft;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set uniqueLimitedItemsLeft(uniqueLimitedItemsLeft: number)
|
||||||
|
{
|
||||||
|
this._uniqueLimitedItemsLeft = uniqueLimitedItemsLeft;
|
||||||
|
}
|
||||||
|
}
|
59
src/components/catalog/common/RequestedPage.ts
Normal file
59
src/components/catalog/common/RequestedPage.ts
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
export class RequestedPage
|
||||||
|
{
|
||||||
|
public static REQUEST_TYPE_NONE: number = 0;
|
||||||
|
public static REQUEST_TYPE_ID: number = 1;
|
||||||
|
public static REQUEST_TYPE_NAME: number = 2;
|
||||||
|
|
||||||
|
private _requestType: number;
|
||||||
|
private _requestId: number;
|
||||||
|
private _requestedOfferId: number;
|
||||||
|
private _requestName: string;
|
||||||
|
|
||||||
|
constructor()
|
||||||
|
{
|
||||||
|
this._requestType = RequestedPage.REQUEST_TYPE_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public setRequestById(id: number):void
|
||||||
|
{
|
||||||
|
this._requestType = RequestedPage.REQUEST_TYPE_ID;
|
||||||
|
this._requestId = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public setRequestByName(name: string):void
|
||||||
|
{
|
||||||
|
this._requestType = RequestedPage.REQUEST_TYPE_NAME;
|
||||||
|
this._requestName = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public resetRequest():void
|
||||||
|
{
|
||||||
|
this._requestType = RequestedPage.REQUEST_TYPE_NONE;
|
||||||
|
this._requestedOfferId = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get requestType(): number
|
||||||
|
{
|
||||||
|
return this._requestType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get requestId(): number
|
||||||
|
{
|
||||||
|
return this._requestId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get requestedOfferId(): number
|
||||||
|
{
|
||||||
|
return this._requestedOfferId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set requestedOfferId(offerId: number)
|
||||||
|
{
|
||||||
|
this._requestedOfferId = offerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get requestName(): string
|
||||||
|
{
|
||||||
|
return this._requestName;
|
||||||
|
}
|
||||||
|
}
|
@ -1,12 +1,68 @@
|
|||||||
import { createContext, FC, useContext } from 'react';
|
import { FrontPageItem } from '@nitrots/nitro-renderer';
|
||||||
import { CatalogContextProps, ICatalogContext } from './CatalogContext.types';
|
import { createContext, Dispatch, FC, ProviderProps, SetStateAction, useContext } from 'react';
|
||||||
|
import { ICatalogNode } from '../common/ICatalogNode';
|
||||||
|
import { ICatalogPage } from '../common/ICatalogPage';
|
||||||
|
import { IPageLocalization } from '../common/IPageLocalization';
|
||||||
|
import { IPurchasableOffer } from '../common/IPurchasableOffer';
|
||||||
|
import { ICatalogAction, ICatalogState } from '../reducers/CatalogReducer';
|
||||||
|
|
||||||
|
export interface ICatalogContext
|
||||||
|
{
|
||||||
|
isVisible: boolean;
|
||||||
|
isBusy: boolean;
|
||||||
|
setIsBusy: Dispatch<SetStateAction<boolean>>;
|
||||||
|
pageId: number;
|
||||||
|
currentType: string;
|
||||||
|
setCurrentType: Dispatch<SetStateAction<string>>;
|
||||||
|
currentNode: ICatalogNode;
|
||||||
|
setCurrentNode: Dispatch<SetStateAction<ICatalogNode>>;
|
||||||
|
currentOffers: Map<number, ICatalogNode[]>;
|
||||||
|
setCurrentOffers: Dispatch<SetStateAction<Map<number, ICatalogNode[]>>>;
|
||||||
|
currentPage: ICatalogPage;
|
||||||
|
setCurrentPage: Dispatch<SetStateAction<ICatalogPage>>;
|
||||||
|
currentOffer: IPurchasableOffer;
|
||||||
|
setCurrentOffer: Dispatch<SetStateAction<IPurchasableOffer>>;
|
||||||
|
purchasableOffer: IPurchasableOffer;
|
||||||
|
setPurchasableOffer: Dispatch<SetStateAction<IPurchasableOffer>>;
|
||||||
|
activeNodes: ICatalogNode[];
|
||||||
|
setActiveNodes: Dispatch<SetStateAction<ICatalogNode[]>>;
|
||||||
|
frontPageItems: FrontPageItem[];
|
||||||
|
setFrontPageItems: Dispatch<SetStateAction<FrontPageItem[]>>;
|
||||||
|
loadCatalogPage: (pageId: number, offerId: number, forceRefresh?: boolean) => void;
|
||||||
|
showCatalogPage: (pageId: number, layoutCode: string, localization: IPageLocalization, offers: IPurchasableOffer[], offerId: number, acceptSeasonCurrencyAsCredits: boolean) => void;
|
||||||
|
|
||||||
|
catalogState: ICatalogState;
|
||||||
|
dispatchCatalogState: Dispatch<ICatalogAction>;
|
||||||
|
}
|
||||||
|
|
||||||
const CatalogContext = createContext<ICatalogContext>({
|
const CatalogContext = createContext<ICatalogContext>({
|
||||||
|
isVisible: null,
|
||||||
|
isBusy: null,
|
||||||
|
setIsBusy: null,
|
||||||
|
pageId: null,
|
||||||
|
currentType: null,
|
||||||
|
setCurrentType: null,
|
||||||
|
currentNode: null,
|
||||||
|
setCurrentNode: null,
|
||||||
|
currentOffers: null,
|
||||||
|
setCurrentOffers: null,
|
||||||
|
currentPage: null,
|
||||||
|
setCurrentPage: null,
|
||||||
|
currentOffer: null,
|
||||||
|
setCurrentOffer: null,
|
||||||
|
purchasableOffer: null,
|
||||||
|
setPurchasableOffer: null,
|
||||||
|
activeNodes: null,
|
||||||
|
setActiveNodes: null,
|
||||||
|
frontPageItems: null,
|
||||||
|
setFrontPageItems: null,
|
||||||
|
loadCatalogPage: null,
|
||||||
|
showCatalogPage: null,
|
||||||
catalogState: null,
|
catalogState: null,
|
||||||
dispatchCatalogState: null
|
dispatchCatalogState: null
|
||||||
});
|
});
|
||||||
|
|
||||||
export const CatalogContextProvider: FC<CatalogContextProps> = props =>
|
export const CatalogContextProvider: FC<ProviderProps<ICatalogContext>> = props =>
|
||||||
{
|
{
|
||||||
return <CatalogContext.Provider value={ props.value }>{ props.children }</CatalogContext.Provider>
|
return <CatalogContext.Provider value={ props.value }>{ props.children }</CatalogContext.Provider>
|
||||||
}
|
}
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
import { Dispatch, ProviderProps } from 'react';
|
|
||||||
import { ICatalogAction, ICatalogState } from '../reducers/CatalogReducer';
|
|
||||||
|
|
||||||
export interface ICatalogContext
|
|
||||||
{
|
|
||||||
catalogState: ICatalogState;
|
|
||||||
dispatchCatalogState: Dispatch<ICatalogAction>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CatalogContextProps extends ProviderProps<ICatalogContext>
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
@ -2,14 +2,12 @@ import { CatalogPageMessageOfferData, CatalogPageMessageParser, ClubGiftInfoPars
|
|||||||
import { HabboGroupEntryData } from '@nitrots/nitro-renderer/src/nitro/communication/messages/parser/user/HabboGroupEntryData';
|
import { HabboGroupEntryData } from '@nitrots/nitro-renderer/src/nitro/communication/messages/parser/user/HabboGroupEntryData';
|
||||||
import { Reducer } from 'react';
|
import { Reducer } from 'react';
|
||||||
import { CatalogPetPalette } from '../common/CatalogPetPalette';
|
import { CatalogPetPalette } from '../common/CatalogPetPalette';
|
||||||
import { ICatalogOffers, ICatalogSearchResult, SetOffersToNodes } from '../common/CatalogUtilities';
|
import { ICatalogSearchResult } from '../common/CatalogUtilities';
|
||||||
import { GiftWrappingConfiguration } from '../common/GiftWrappingConfiguration';
|
import { GiftWrappingConfiguration } from '../common/GiftWrappingConfiguration';
|
||||||
import { SubscriptionInfo } from '../common/SubscriptionInfo';
|
import { SubscriptionInfo } from '../common/SubscriptionInfo';
|
||||||
|
|
||||||
export interface ICatalogState
|
export interface ICatalogState
|
||||||
{
|
{
|
||||||
root: INodeData;
|
|
||||||
offerRoot: ICatalogOffers;
|
|
||||||
currentTab: INodeData;
|
currentTab: INodeData;
|
||||||
pageParser: CatalogPageMessageParser;
|
pageParser: CatalogPageMessageParser;
|
||||||
activeOffer: CatalogPageMessageOfferData;
|
activeOffer: CatalogPageMessageOfferData;
|
||||||
@ -27,8 +25,6 @@ export interface ICatalogAction
|
|||||||
{
|
{
|
||||||
type: string;
|
type: string;
|
||||||
payload: {
|
payload: {
|
||||||
root?: INodeData;
|
|
||||||
offerRoot?: ICatalogOffers;
|
|
||||||
currentTab?: INodeData;
|
currentTab?: INodeData;
|
||||||
pageParser?: CatalogPageMessageParser;
|
pageParser?: CatalogPageMessageParser;
|
||||||
activeOffer?: CatalogPageMessageOfferData;
|
activeOffer?: CatalogPageMessageOfferData;
|
||||||
@ -46,7 +42,6 @@ export interface ICatalogAction
|
|||||||
export class CatalogActions
|
export class CatalogActions
|
||||||
{
|
{
|
||||||
public static RESET_STATE: string = 'CA_RESET_STATE';
|
public static RESET_STATE: string = 'CA_RESET_STATE';
|
||||||
public static SET_CATALOG_ROOT: string = 'CA_SET_CATALOG_ROOT';
|
|
||||||
public static SET_CATALOG_CURRENT_TAB: string = 'CA_SET_CATALOG_CURRENT_TAB';
|
public static SET_CATALOG_CURRENT_TAB: string = 'CA_SET_CATALOG_CURRENT_TAB';
|
||||||
public static SET_CATALOG_PAGE_PARSER: string = 'CA_SET_CATALOG_PAGE';
|
public static SET_CATALOG_PAGE_PARSER: string = 'CA_SET_CATALOG_PAGE';
|
||||||
public static SET_CATALOG_ACTIVE_OFFER: string = 'CA_SET_ACTIVE_OFFER';
|
public static SET_CATALOG_ACTIVE_OFFER: string = 'CA_SET_ACTIVE_OFFER';
|
||||||
@ -61,8 +56,6 @@ export class CatalogActions
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const initialCatalog: ICatalogState = {
|
export const initialCatalog: ICatalogState = {
|
||||||
root: null,
|
|
||||||
offerRoot: null,
|
|
||||||
currentTab: null,
|
currentTab: null,
|
||||||
pageParser: null,
|
pageParser: null,
|
||||||
activeOffer: null,
|
activeOffer: null,
|
||||||
@ -80,16 +73,6 @@ export const CatalogReducer: Reducer<ICatalogState, ICatalogAction> = (state, ac
|
|||||||
{
|
{
|
||||||
switch(action.type)
|
switch(action.type)
|
||||||
{
|
{
|
||||||
case CatalogActions.SET_CATALOG_ROOT: {
|
|
||||||
const root = (action.payload.root || state.root || null);
|
|
||||||
const currentTab = ((root && (root.children.length > 0) && root.children[0]) || null);
|
|
||||||
|
|
||||||
const offerRoot: ICatalogOffers = {};
|
|
||||||
|
|
||||||
SetOffersToNodes(offerRoot, root);
|
|
||||||
|
|
||||||
return { ...state, root, offerRoot, currentTab };
|
|
||||||
}
|
|
||||||
case CatalogActions.SET_CATALOG_CURRENT_TAB: {
|
case CatalogActions.SET_CATALOG_CURRENT_TAB: {
|
||||||
const currentTab = (action.payload.currentTab || state.currentTab || null);
|
const currentTab = (action.payload.currentTab || state.currentTab || null);
|
||||||
const searchResult = null;
|
const searchResult = null;
|
||||||
|
@ -6,5 +6,4 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@import './gift/CatalogGiftView';
|
@import './gift/CatalogGiftView';
|
||||||
@import './navigation/CatalogNavigationView';
|
|
||||||
@import './page/CatalogPageView';
|
@import './page/CatalogPageView';
|
||||||
|
@ -1,16 +1,25 @@
|
|||||||
import { NitroToolbarAnimateIconEvent, TextureUtils, ToolbarIconEnum } from '@nitrots/nitro-renderer';
|
import { NitroToolbarAnimateIconEvent, TextureUtils, ToolbarIconEnum } from '@nitrots/nitro-renderer';
|
||||||
import { FC, useCallback, useRef } from 'react';
|
import { FC, useCallback, useRef, useState } from 'react';
|
||||||
import { GetRoomEngine } from '../../../../api';
|
import { GetRoomEngine } from '../../../../api';
|
||||||
import { CatalogEvent } from '../../../../events';
|
import { CatalogEvent, CatalogSelectProductEvent } from '../../../../events';
|
||||||
import { useUiEvent } from '../../../../hooks';
|
import { useUiEvent } from '../../../../hooks';
|
||||||
import { RoomPreviewerView } from '../../../../views/shared/room-previewer/RoomPreviewerView';
|
import { RoomPreviewerView } from '../../../../views/shared/room-previewer/RoomPreviewerView';
|
||||||
import { RoomPreviewerViewProps } from '../../../../views/shared/room-previewer/RoomPreviewerView.types';
|
import { RoomPreviewerViewProps } from '../../../../views/shared/room-previewer/RoomPreviewerView.types';
|
||||||
|
import { IPurchasableOffer } from '../../common/IPurchasableOffer';
|
||||||
|
|
||||||
export const CatalogRoomPreviewerView: FC<RoomPreviewerViewProps> = props =>
|
export const CatalogRoomPreviewerView: FC<RoomPreviewerViewProps> = props =>
|
||||||
{
|
{
|
||||||
const { roomPreviewer = null } = props;
|
const { roomPreviewer = null } = props;
|
||||||
|
const [ offer, setOffer ] = useState<IPurchasableOffer>(null);
|
||||||
const elementRef = useRef<HTMLDivElement>(null);
|
const elementRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
const onCatalogSelectProductEvent = useCallback((event: CatalogSelectProductEvent) =>
|
||||||
|
{
|
||||||
|
setOffer(event.offer);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useUiEvent(CatalogSelectProductEvent.SELECT_PRODUCT, onCatalogSelectProductEvent)
|
||||||
|
|
||||||
const animatePurchase = useCallback(() =>
|
const animatePurchase = useCallback(() =>
|
||||||
{
|
{
|
||||||
if(!elementRef) return;
|
if(!elementRef) return;
|
||||||
|
@ -1,95 +1,52 @@
|
|||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { GetCatalogPageComposer, INodeData } from '@nitrots/nitro-renderer';
|
import { FC, useEffect, useState } from 'react';
|
||||||
import { Dispatch, FC, SetStateAction, useCallback, useEffect, useState } from 'react';
|
|
||||||
import { LayoutGridItem } from '../../../../common/layout/LayoutGridItem';
|
import { LayoutGridItem } from '../../../../common/layout/LayoutGridItem';
|
||||||
import { Text } from '../../../../common/Text';
|
import { Text } from '../../../../common/Text';
|
||||||
import { SendMessageHook } from '../../../../hooks/messages/message-event';
|
import { BatchUpdates } from '../../../../hooks';
|
||||||
import { CatalogMode } from '../../common/CatalogMode';
|
import { ICatalogNode } from '../../common/ICatalogNode';
|
||||||
|
import { useCatalogContext } from '../../context/CatalogContext';
|
||||||
import { CatalogIconView } from '../catalog-icon/CatalogIconView';
|
import { CatalogIconView } from '../catalog-icon/CatalogIconView';
|
||||||
import { CatalogNavigationSetView } from './CatalogNavigationSetView';
|
import { CatalogNavigationSetView } from './CatalogNavigationSetView';
|
||||||
import { ACTIVE_PAGES } from './CatalogNavigationView';
|
|
||||||
|
|
||||||
export interface CatalogNavigationItemViewProps
|
export interface CatalogNavigationItemViewProps
|
||||||
{
|
{
|
||||||
page: INodeData;
|
node: ICatalogNode;
|
||||||
isActive: boolean;
|
isActive: boolean;
|
||||||
pendingTree: INodeData[];
|
selectNode: (node: ICatalogNode) => void;
|
||||||
setPendingTree: Dispatch<SetStateAction<INodeData[]>>;
|
|
||||||
setActiveChild: Dispatch<SetStateAction<INodeData>>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CatalogNavigationItemView: FC<CatalogNavigationItemViewProps> = props =>
|
export const CatalogNavigationItemView: FC<CatalogNavigationItemViewProps> = props =>
|
||||||
{
|
{
|
||||||
const { page = null, isActive = false, pendingTree = null, setPendingTree = null, setActiveChild = null } = props;
|
const { node = null, isActive = false, selectNode = null } = props;
|
||||||
const [ isExpanded, setIsExpanded ] = useState(false);
|
const [ isExpanded, setIsExpanded ] = useState(false);
|
||||||
|
const { loadCatalogPage = null } = useCatalogContext();
|
||||||
|
|
||||||
const select = useCallback((selectPage: INodeData, expand: boolean = false) =>
|
const select = () =>
|
||||||
{
|
{
|
||||||
if(!selectPage) return;
|
BatchUpdates(() =>
|
||||||
|
{
|
||||||
|
if(!isActive) selectNode(node);
|
||||||
|
else setIsExpanded(prevValue => !prevValue);
|
||||||
|
|
||||||
setActiveChild(prevValue =>
|
loadCatalogPage(node.pageId, -1, true);
|
||||||
{
|
|
||||||
if(prevValue === selectPage)
|
|
||||||
{
|
|
||||||
if(selectPage.pageId > -1) SendMessageHook(new GetCatalogPageComposer(selectPage.pageId, -1, CatalogMode.MODE_NORMAL));
|
|
||||||
}
|
|
||||||
|
|
||||||
return selectPage;
|
|
||||||
});
|
|
||||||
|
|
||||||
if(selectPage.children && selectPage.children.length)
|
|
||||||
{
|
|
||||||
setIsExpanded(prevValue =>
|
|
||||||
{
|
|
||||||
if(expand) return true;
|
|
||||||
|
|
||||||
return !prevValue;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [ setActiveChild ]);
|
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
if(!pendingTree || !pendingTree.length) return;
|
setIsExpanded(isActive);
|
||||||
|
}, [ isActive ]);
|
||||||
if(page !== pendingTree[0]) return;
|
|
||||||
|
|
||||||
const newTree = [ ...pendingTree ];
|
|
||||||
|
|
||||||
newTree.shift();
|
|
||||||
|
|
||||||
if(newTree.length) setPendingTree(newTree);
|
|
||||||
else setPendingTree(null);
|
|
||||||
|
|
||||||
select(page, true);
|
|
||||||
}, [ page, pendingTree, setPendingTree, select ]);
|
|
||||||
|
|
||||||
useEffect(() =>
|
|
||||||
{
|
|
||||||
if(!isActive || !page) return;
|
|
||||||
|
|
||||||
setIsExpanded(true);
|
|
||||||
|
|
||||||
if(page.pageId > -1) SendMessageHook(new GetCatalogPageComposer(page.pageId, -1, CatalogMode.MODE_NORMAL));
|
|
||||||
|
|
||||||
const index = (ACTIVE_PAGES.push(page) - 1);
|
|
||||||
|
|
||||||
return () =>
|
|
||||||
{
|
|
||||||
ACTIVE_PAGES.length = index;
|
|
||||||
}
|
|
||||||
}, [ isActive, page ]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<LayoutGridItem column={ false } itemActive={ isActive } onClick={ event => select(page) }>
|
<LayoutGridItem column={ false } itemActive={ isActive } onClick={ select }>
|
||||||
<CatalogIconView icon={ page.icon } />
|
<CatalogIconView icon={ node.iconId } />
|
||||||
<Text grow truncate>{ page.localization }</Text>
|
<Text grow truncate>{ node.localization }</Text>
|
||||||
{ (page.children.length > 0) &&
|
{ node.isBranch &&
|
||||||
<FontAwesomeIcon icon={ isExpanded ? 'caret-up' : 'caret-down' } /> }
|
<FontAwesomeIcon icon={ isExpanded ? 'caret-up' : 'caret-down' } /> }
|
||||||
</LayoutGridItem>
|
</LayoutGridItem>
|
||||||
{ isActive && isExpanded && page.children && (page.children.length > 0) &&
|
{ isExpanded && node.isBranch &&
|
||||||
<CatalogNavigationSetView page={ page } pendingTree={ pendingTree } setPendingTree={ setPendingTree } /> }
|
<CatalogNavigationSetView node={ node } /> }
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,44 +1,71 @@
|
|||||||
import { INodeData } from '@nitrots/nitro-renderer';
|
import { FC, useEffect, useState } from 'react';
|
||||||
import { Dispatch, FC, SetStateAction, useEffect, useState } from 'react';
|
import { UseMountEffect } from '../../../../hooks';
|
||||||
|
import { ICatalogNode } from '../../common/ICatalogNode';
|
||||||
|
import { useCatalogContext } from '../../context/CatalogContext';
|
||||||
import { CatalogNavigationItemView } from './CatalogNavigationItemView';
|
import { CatalogNavigationItemView } from './CatalogNavigationItemView';
|
||||||
|
|
||||||
export interface CatalogNavigationSetViewProps
|
export interface CatalogNavigationSetViewProps
|
||||||
{
|
{
|
||||||
page: INodeData;
|
node: ICatalogNode;
|
||||||
isFirstSet?: boolean;
|
|
||||||
pendingTree: INodeData[];
|
|
||||||
setPendingTree: Dispatch<SetStateAction<INodeData[]>>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CatalogNavigationSetView: FC<CatalogNavigationSetViewProps> = props =>
|
export const CatalogNavigationSetView: FC<CatalogNavigationSetViewProps> = props =>
|
||||||
{
|
{
|
||||||
const { page = null, isFirstSet = false, pendingTree = null, setPendingTree = null } = props;
|
const { node = null } = props;
|
||||||
const [ activeChild, setActiveChild ] = useState<INodeData>(null);
|
const [ activeNode, setActiveNode ] = useState<ICatalogNode>(null);
|
||||||
|
const { activeNodes = null, setActiveNodes = null } = useCatalogContext();
|
||||||
|
|
||||||
|
const selectNode = (node: ICatalogNode) =>
|
||||||
|
{
|
||||||
|
setActiveNode(node);
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
if(!page || (page.pageId === -1) || !isFirstSet || pendingTree) return;
|
if(!node || !activeNode) return;
|
||||||
|
|
||||||
if(page.children.length)
|
setActiveNodes(prevValue =>
|
||||||
{
|
{
|
||||||
if(activeChild)
|
const newNodes = prevValue.slice(0, (node.depth - 1));
|
||||||
|
|
||||||
|
newNodes.push(activeNode);
|
||||||
|
|
||||||
|
return newNodes;
|
||||||
|
});
|
||||||
|
|
||||||
|
return () =>
|
||||||
{
|
{
|
||||||
if(page.children.indexOf(activeChild) === -1) setActiveChild(null);
|
setActiveNodes(prevValue =>
|
||||||
|
{
|
||||||
|
const newNodes = prevValue.slice(0, (node.depth - 1));
|
||||||
|
|
||||||
return;
|
return newNodes;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
}, [ node, activeNode, setActiveNodes ]);
|
||||||
|
|
||||||
setActiveChild(page.children[0]);
|
UseMountEffect(() =>
|
||||||
|
{
|
||||||
|
if(activeNodes && activeNodes.length)
|
||||||
|
{
|
||||||
|
const index = activeNodes.indexOf(node);
|
||||||
|
|
||||||
|
if(index > -1)
|
||||||
|
{
|
||||||
|
const childNode = activeNodes[index + 1];
|
||||||
|
|
||||||
|
if(childNode) setActiveNode(childNode);
|
||||||
}
|
}
|
||||||
}, [ page, isFirstSet, activeChild, pendingTree ]);
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{ page && (page.children.length > 0) && page.children.map((page, index) =>
|
{ node && (node.children.length > 0) && node.children.map((node, index) =>
|
||||||
{
|
{
|
||||||
if(!page.visible) return null;
|
if(!node.isVisible) return null;
|
||||||
|
|
||||||
return <CatalogNavigationItemView key={ index } page={ page } isActive={ (activeChild === page) } pendingTree={ pendingTree } setPendingTree={ setPendingTree } setActiveChild={ setActiveChild } />
|
return <CatalogNavigationItemView key={ index } node={ node } isActive={ (activeNodes.indexOf(node) > -1) } selectNode={ selectNode } />
|
||||||
}) }
|
}) }
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
.nitro-catalog-navigation-grid-container {
|
|
||||||
border-radius: 0.25rem;
|
|
||||||
border-color: #B6BEC5 !important;
|
|
||||||
background-color: #CDD3D9;
|
|
||||||
border: 2px solid;
|
|
||||||
|
|
||||||
.layout-grid-item {
|
|
||||||
font-size: $font-size-sm;
|
|
||||||
height: 23px !important;
|
|
||||||
border-color: unset !important;
|
|
||||||
background-color: #CDD3D9;
|
|
||||||
border: 0 !important;
|
|
||||||
padding: 1px 3px;
|
|
||||||
|
|
||||||
.svg-inline--fa {
|
|
||||||
color: $black;
|
|
||||||
font-size: 10px;
|
|
||||||
padding: 1px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,41 +1,42 @@
|
|||||||
import { INodeData } from '@nitrots/nitro-renderer';
|
import { FC, useCallback, useState } from 'react';
|
||||||
import { Dispatch, FC, SetStateAction, useEffect } from 'react';
|
|
||||||
import { Column } from '../../../../common/Column';
|
import { Column } from '../../../../common/Column';
|
||||||
import { Grid } from '../../../../common/Grid';
|
import { Grid } from '../../../../common/Grid';
|
||||||
|
import { FilterCatalogNode } from '../../common/FilterCatalogNode';
|
||||||
|
import { ICatalogNode } from '../../common/ICatalogNode';
|
||||||
|
import { useCatalogContext } from '../../context/CatalogContext';
|
||||||
import { CatalogSearchView } from '../search/CatalogSearchView';
|
import { CatalogSearchView } from '../search/CatalogSearchView';
|
||||||
import { CatalogNavigationSetView } from './CatalogNavigationSetView';
|
import { CatalogNavigationSetView } from './CatalogNavigationSetView';
|
||||||
|
|
||||||
export interface CatalogNavigationViewProps
|
export interface CatalogNavigationViewProps
|
||||||
{
|
{
|
||||||
page: INodeData;
|
node: ICatalogNode;
|
||||||
pendingTree: INodeData[];
|
|
||||||
setPendingTree: Dispatch<SetStateAction<INodeData[]>>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export let ACTIVE_PAGES: INodeData[] = [];
|
|
||||||
|
|
||||||
export const CatalogNavigationView: FC<CatalogNavigationViewProps> = props =>
|
export const CatalogNavigationView: FC<CatalogNavigationViewProps> = props =>
|
||||||
{
|
{
|
||||||
const { page = null, pendingTree = null, setPendingTree = null } = props;
|
const { node = null } = props;
|
||||||
|
const [ filteredNodes, setFilteredNodes ] = useState<ICatalogNode[]>([]);
|
||||||
|
const { currentNode = null, activeNodes = null } = useCatalogContext();
|
||||||
|
|
||||||
useEffect(() =>
|
const filterNodes = useCallback((value: string, furniLines: string[]) =>
|
||||||
{
|
{
|
||||||
if(!page) return;
|
const nodes: ICatalogNode[] = [];
|
||||||
|
|
||||||
ACTIVE_PAGES = [ page ];
|
FilterCatalogNode(value, furniLines, currentNode, nodes);
|
||||||
|
|
||||||
return () =>
|
setFilteredNodes(nodes.filter(node => (node.isVisible)));
|
||||||
{
|
}, [ currentNode ]);
|
||||||
ACTIVE_PAGES = [];
|
|
||||||
}
|
|
||||||
}, [ page ]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<CatalogSearchView />
|
<CatalogSearchView />
|
||||||
<Column fullHeight className="nitro-catalog-navigation-grid-container p-1" overflow="hidden">
|
<Column fullHeight className="nitro-catalog-navigation-grid-container p-1" overflow="hidden">
|
||||||
<Grid grow columnCount={ 1 } gap={ 1 } overflow="auto">
|
<Grid grow columnCount={ 1 } gap={ 1 } overflow="auto">
|
||||||
<CatalogNavigationSetView page={ page } isFirstSet={ true } pendingTree={ pendingTree } setPendingTree={ setPendingTree } />
|
{/* { filterNodes && (filteredNodes.length > 0) && filteredNodes.map((node, index) =>
|
||||||
|
{
|
||||||
|
return <CatalogNavigationItemView key={ index } node={ node } isActive={ (activeNodes.indexOf(node) > -1) } selectNode={ selectNode } />;
|
||||||
|
})} */}
|
||||||
|
<CatalogNavigationSetView node={ node } />
|
||||||
</Grid>
|
</Grid>
|
||||||
</Column>
|
</Column>
|
||||||
</>
|
</>
|
||||||
|
@ -1,25 +1,24 @@
|
|||||||
import { CatalogPageMessageParser } from '@nitrots/nitro-renderer';
|
|
||||||
import { FC } from 'react';
|
import { FC } from 'react';
|
||||||
import { NitroLayoutFlexColumn } from '../../../../layout';
|
import { NitroLayoutFlexColumn } from '../../../../layout';
|
||||||
import { GetCatalogPageImage, GetCatalogPageText } from '../../common/CatalogUtilities';
|
import { ICatalogPage } from '../../common/ICatalogPage';
|
||||||
|
|
||||||
export interface CatalogPageDetailsViewProps
|
export interface CatalogPageDetailsViewProps
|
||||||
{
|
{
|
||||||
pageParser: CatalogPageMessageParser;
|
page: ICatalogPage;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CatalogPageDetailsView: FC<CatalogPageDetailsViewProps> = props =>
|
export const CatalogPageDetailsView: FC<CatalogPageDetailsViewProps> = props =>
|
||||||
{
|
{
|
||||||
const { pageParser = null } = props;
|
const { page = null } = props;
|
||||||
|
|
||||||
if(!pageParser) return null;
|
if(!page) return null;
|
||||||
|
|
||||||
const imageUrl = GetCatalogPageImage(pageParser, 1);
|
const imageUrl = page.localization.getImage(1);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NitroLayoutFlexColumn className="justify-content-center align-items-center h-100" overflow="hidden" gap={ 2 }>
|
<NitroLayoutFlexColumn className="justify-content-center align-items-center h-100" overflow="hidden" gap={ 2 }>
|
||||||
{ imageUrl && <img className="" alt="" src={ imageUrl } /> }
|
{ imageUrl && <img className="" alt="" src={ imageUrl } /> }
|
||||||
<div className="d-flex flex-column fs-6 text-center text-black lh-sm overflow-auto" dangerouslySetInnerHTML={ { __html: GetCatalogPageText(pageParser, 0) } } />
|
<div className="d-flex flex-column fs-6 text-center text-black lh-sm overflow-auto" dangerouslySetInnerHTML={ { __html: page.localization.getText(0) } } />
|
||||||
</NitroLayoutFlexColumn>
|
</NitroLayoutFlexColumn>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,39 +1,35 @@
|
|||||||
import { CatalogPageMessageOfferData, IObjectData, RoomPreviewer, Vector3d } from '@nitrots/nitro-renderer';
|
import { IObjectData, RoomPreviewer, Vector3d } from '@nitrots/nitro-renderer';
|
||||||
import { FC, useCallback, useEffect, useState } from 'react';
|
import { FC, useCallback, useEffect } from 'react';
|
||||||
import { GetAvatarRenderManager, GetFurnitureDataForProductOffer, GetSessionDataManager } from '../../../../api';
|
import { GetAvatarRenderManager, GetSessionDataManager } from '../../../../api';
|
||||||
import { SetRoomPreviewerStuffDataEvent } from '../../../../events';
|
import { SetRoomPreviewerStuffDataEvent } from '../../../../events';
|
||||||
import { useUiEvent } from '../../../../hooks';
|
import { useUiEvent } from '../../../../hooks';
|
||||||
import { FurniCategory } from '../../common/FurniCategory';
|
import { FurniCategory } from '../../common/FurniCategory';
|
||||||
|
import { ICatalogPage } from '../../common/ICatalogPage';
|
||||||
|
import { IPurchasableOffer } from '../../common/IPurchasableOffer';
|
||||||
import { ProductTypeEnum } from '../../common/ProductTypeEnum';
|
import { ProductTypeEnum } from '../../common/ProductTypeEnum';
|
||||||
import { useCatalogContext } from '../../context/CatalogContext';
|
import { useCatalogContext } from '../../context/CatalogContext';
|
||||||
import { GetCatalogLayout } from './layout/GetCatalogLayout';
|
import { GetCatalogLayout } from './layout/GetCatalogLayout';
|
||||||
import { CatalogLayoutSearchResultView } from './search-result/CatalogLayoutSearchResultView';
|
|
||||||
|
|
||||||
export interface CatalogPageViewProps
|
export interface CatalogPageViewProps
|
||||||
{
|
{
|
||||||
|
page: ICatalogPage;
|
||||||
roomPreviewer: RoomPreviewer;
|
roomPreviewer: RoomPreviewer;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CatalogPageView: FC<CatalogPageViewProps> = props =>
|
export const CatalogPageView: FC<CatalogPageViewProps> = props =>
|
||||||
{
|
{
|
||||||
const { roomPreviewer = null } = props;
|
const { page = null, roomPreviewer = null } = props;
|
||||||
const [ lastOffer, setLastOffer ] = useState<CatalogPageMessageOfferData>(null);
|
const { currentOffer = null } = useCatalogContext();
|
||||||
const { catalogState = null } = useCatalogContext();
|
|
||||||
const { pageParser = null, activeOffer = null, searchResult = null } = catalogState;
|
|
||||||
|
|
||||||
const updatePreviewerForOffer = useCallback((offer: CatalogPageMessageOfferData, stuffData: IObjectData = null) =>
|
const updatePreviewerForOffer = useCallback((offer: IPurchasableOffer, stuffData: IObjectData = null) =>
|
||||||
{
|
{
|
||||||
if(!offer || !roomPreviewer) return;
|
if(!offer || !roomPreviewer) return;
|
||||||
|
|
||||||
const product = offer.products[0];
|
const product = offer.product;
|
||||||
|
|
||||||
if(!product) return;
|
if(!product && !product.furnitureData && (product.productType !== ProductTypeEnum.ROBOT)) return;
|
||||||
|
|
||||||
const furniData = GetFurnitureDataForProductOffer(product);
|
switch(product.productType.toLowerCase())
|
||||||
|
|
||||||
if(!furniData && (product.productType !== ProductTypeEnum.ROBOT)) return;
|
|
||||||
|
|
||||||
switch(product.productType)
|
|
||||||
{
|
{
|
||||||
case ProductTypeEnum.ROBOT: {
|
case ProductTypeEnum.ROBOT: {
|
||||||
roomPreviewer.updateObjectRoom('default', 'default', 'default');
|
roomPreviewer.updateObjectRoom('default', 'default', 'default');
|
||||||
@ -46,10 +42,10 @@ export const CatalogPageView: FC<CatalogPageViewProps> = props =>
|
|||||||
case ProductTypeEnum.FLOOR: {
|
case ProductTypeEnum.FLOOR: {
|
||||||
roomPreviewer.updateObjectRoom('default', 'default', 'default');
|
roomPreviewer.updateObjectRoom('default', 'default', 'default');
|
||||||
|
|
||||||
if(furniData.specialType === FurniCategory.FIGURE_PURCHASABLE_SET)
|
if(product.furnitureData.specialType === FurniCategory.FIGURE_PURCHASABLE_SET)
|
||||||
{
|
{
|
||||||
const setIds: number[] = [];
|
const setIds: number[] = [];
|
||||||
const sets = furniData.customParams.split(',');
|
const sets = product.furnitureData.customParams.split(',');
|
||||||
|
|
||||||
for(const set of sets)
|
for(const set of sets)
|
||||||
{
|
{
|
||||||
@ -64,12 +60,13 @@ export const CatalogPageView: FC<CatalogPageViewProps> = props =>
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
roomPreviewer.addFurnitureIntoRoom(product.furniClassId, new Vector3d(90), stuffData);
|
console.log('??')
|
||||||
|
roomPreviewer.addFurnitureIntoRoom(product.productClassId, new Vector3d(90), stuffData);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case ProductTypeEnum.WALL: {
|
case ProductTypeEnum.WALL: {
|
||||||
switch(furniData.className)
|
switch(product.furnitureData.className)
|
||||||
{
|
{
|
||||||
case 'floor':
|
case 'floor':
|
||||||
roomPreviewer.reset(false);
|
roomPreviewer.reset(false);
|
||||||
@ -85,7 +82,7 @@ export const CatalogPageView: FC<CatalogPageViewProps> = props =>
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
roomPreviewer.updateObjectRoom('default', 'default', 'default');
|
roomPreviewer.updateObjectRoom('default', 'default', 'default');
|
||||||
roomPreviewer.addWallItemIntoRoom(product.furniClassId, new Vector3d(90), product.extraParam);
|
roomPreviewer.addWallItemIntoRoom(product.productClassId, new Vector3d(90), product.extraParam);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,15 +106,12 @@ export const CatalogPageView: FC<CatalogPageViewProps> = props =>
|
|||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
if(!activeOffer) return;
|
if(!currentOffer) return;
|
||||||
|
|
||||||
updatePreviewerForOffer(activeOffer);
|
updatePreviewerForOffer(currentOffer);
|
||||||
}, [ activeOffer, updatePreviewerForOffer ]);
|
}, [ currentOffer, updatePreviewerForOffer ]);
|
||||||
|
|
||||||
if(searchResult && searchResult.furniture)
|
if(!page) return null;
|
||||||
{
|
|
||||||
return <CatalogLayoutSearchResultView roomPreviewer={ roomPreviewer } furnitureDatas={ searchResult.furniture } />;
|
return GetCatalogLayout(page, roomPreviewer);
|
||||||
}
|
|
||||||
|
|
||||||
return ((pageParser && GetCatalogLayout(pageParser, roomPreviewer)) || null);
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import { CatalogPageMessageParser, RoomPreviewer } from '@nitrots/nitro-renderer';
|
import { RoomPreviewer } from '@nitrots/nitro-renderer';
|
||||||
|
import { ICatalogPage } from '../../../common/ICatalogPage';
|
||||||
|
|
||||||
export interface CatalogLayoutProps
|
export interface CatalogLayoutProps
|
||||||
{
|
{
|
||||||
|
page: ICatalogPage;
|
||||||
roomPreviewer: RoomPreviewer;
|
roomPreviewer: RoomPreviewer;
|
||||||
pageParser?: CatalogPageMessageParser;
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import { CatalogPageMessageParser, RoomPreviewer } from '@nitrots/nitro-renderer';
|
import { RoomPreviewer } from '@nitrots/nitro-renderer';
|
||||||
|
import { ICatalogPage } from '../../../common/ICatalogPage';
|
||||||
import { CatalogLayoutBadgeDisplayView } from './badge-display/CatalogLayoutBadgeDisplayView';
|
import { CatalogLayoutBadgeDisplayView } from './badge-display/CatalogLayoutBadgeDisplayView';
|
||||||
|
import { CatalogLayoutProps } from './CatalogLayout.types';
|
||||||
import { CatalogLayoutDefaultView } from './default/CatalogLayoutDefaultView';
|
import { CatalogLayoutDefaultView } from './default/CatalogLayoutDefaultView';
|
||||||
import { CatalogLayoutFrontpage4View } from './frontpage4/CatalogLayoutFrontpage4View';
|
import { CatalogLayoutFrontpage4View } from './frontpage4/CatalogLayoutFrontpage4View';
|
||||||
import { CatalogLayouGuildCustomFurniView } from './guild-custom-furni/CatalogLayoutGuildCustomFurniView';
|
import { CatalogLayouGuildCustomFurniView } from './guild-custom-furni/CatalogLayoutGuildCustomFurniView';
|
||||||
@ -17,51 +19,53 @@ import { CatalogLayoutTrophiesView } from './trophies/CatalogLayoutTrophiesView'
|
|||||||
import { CatalogLayoutVipBuyView } from './vip-buy/CatalogLayoutVipBuyView';
|
import { CatalogLayoutVipBuyView } from './vip-buy/CatalogLayoutVipBuyView';
|
||||||
import { CatalogLayoutVipGiftsView } from './vip-gifts/CatalogLayoutVipGiftsView';
|
import { CatalogLayoutVipGiftsView } from './vip-gifts/CatalogLayoutVipGiftsView';
|
||||||
|
|
||||||
export const GetCatalogLayout = (pageParser: CatalogPageMessageParser, roomPreviewer: RoomPreviewer) =>
|
export const GetCatalogLayout = (page: ICatalogPage, roomPreviewer: RoomPreviewer) =>
|
||||||
{
|
{
|
||||||
switch(pageParser.layoutCode)
|
const layoutProps: CatalogLayoutProps = { page, roomPreviewer };
|
||||||
|
|
||||||
|
switch(page.layoutCode)
|
||||||
{
|
{
|
||||||
case 'frontpage_featured':
|
case 'frontpage_featured':
|
||||||
return null
|
return null
|
||||||
case 'frontpage4':
|
case 'frontpage4':
|
||||||
return <CatalogLayoutFrontpage4View roomPreviewer={ roomPreviewer } pageParser={ pageParser } />;
|
return <CatalogLayoutFrontpage4View { ...layoutProps } />;
|
||||||
case 'pets':
|
case 'pets':
|
||||||
return <CatalogLayoutPetView roomPreviewer={ roomPreviewer } pageParser={ pageParser } />;
|
return <CatalogLayoutPetView { ...layoutProps } />;
|
||||||
case 'pets2':
|
case 'pets2':
|
||||||
return <CatalogLayoutPets2View roomPreviewer={ roomPreviewer } pageParser={ pageParser } />;
|
return <CatalogLayoutPets2View { ...layoutProps } />;
|
||||||
case 'pets3':
|
case 'pets3':
|
||||||
return <CatalogLayoutPets3View roomPreviewer={ roomPreviewer } pageParser={ pageParser } />;
|
return <CatalogLayoutPets3View { ...layoutProps } />;
|
||||||
case 'vip_buy':
|
case 'vip_buy':
|
||||||
return <CatalogLayoutVipBuyView roomPreviewer={ roomPreviewer } pageParser={ pageParser } />;
|
return <CatalogLayoutVipBuyView { ...layoutProps } />;
|
||||||
case 'guild_frontpage':
|
case 'guild_frontpage':
|
||||||
return <CatalogLayouGuildFrontpageView roomPreviewer={ roomPreviewer } pageParser={ pageParser } />;
|
return <CatalogLayouGuildFrontpageView { ...layoutProps } />;
|
||||||
case 'guild_forum':
|
case 'guild_forum':
|
||||||
return <CatalogLayouGuildForumView roomPreviewer={ roomPreviewer } pageParser={ pageParser } />;
|
return <CatalogLayouGuildForumView { ...layoutProps } />;
|
||||||
case 'guild_custom_furni':
|
case 'guild_custom_furni':
|
||||||
return <CatalogLayouGuildCustomFurniView roomPreviewer={ roomPreviewer } pageParser={ pageParser } />;
|
return <CatalogLayouGuildCustomFurniView { ...layoutProps } />;
|
||||||
case 'search_results':
|
case 'search_results':
|
||||||
return null;
|
return null;
|
||||||
case 'club_gifts':
|
case 'club_gifts':
|
||||||
return <CatalogLayoutVipGiftsView roomPreviewer={ roomPreviewer } pageParser={ pageParser } />;
|
return <CatalogLayoutVipGiftsView { ...layoutProps } />;
|
||||||
case 'marketplace_own_items':
|
case 'marketplace_own_items':
|
||||||
return <CatalogLayoutMarketplaceOwnItemsView roomPreviewer={ roomPreviewer } pageParser={ pageParser } />;
|
return <CatalogLayoutMarketplaceOwnItemsView { ...layoutProps } />;
|
||||||
case 'marketplace':
|
case 'marketplace':
|
||||||
return <CatalogLayoutMarketplacePublicItemsView roomPreviewer={ roomPreviewer } pageParser={ pageParser } />;
|
return <CatalogLayoutMarketplacePublicItemsView { ...layoutProps } />;
|
||||||
case 'single_bundle':
|
case 'single_bundle':
|
||||||
return <CatalogLayoutSingleBundleView roomPreviewer={ roomPreviewer } pageParser={ pageParser } />;
|
return <CatalogLayoutSingleBundleView { ...layoutProps } />;
|
||||||
case 'spaces_new':
|
case 'spaces_new':
|
||||||
return <CatalogLayoutSpacesView roomPreviewer={ roomPreviewer } pageParser={ pageParser } />;
|
return <CatalogLayoutSpacesView { ...layoutProps } />;
|
||||||
case 'trophies':
|
case 'trophies':
|
||||||
return <CatalogLayoutTrophiesView roomPreviewer={roomPreviewer} pageParser={ pageParser } />;
|
return <CatalogLayoutTrophiesView roomPreviewer={roomPreviewer} page={ page } />;
|
||||||
case 'info_loyalty':
|
case 'info_loyalty':
|
||||||
return <CatalogLayoutInfoLoyaltyView roomPreviewer={ roomPreviewer } pageParser={ pageParser } />;
|
return <CatalogLayoutInfoLoyaltyView { ...layoutProps } />;
|
||||||
case 'badge_display':
|
case 'badge_display':
|
||||||
return <CatalogLayoutBadgeDisplayView roomPreviewer={roomPreviewer} pageParser={ pageParser } />;
|
return <CatalogLayoutBadgeDisplayView roomPreviewer={roomPreviewer} page={ page } />;
|
||||||
//case 'default_3x3_color_grouping':
|
//case 'default_3x3_color_grouping':
|
||||||
//return <CatalogLayoutColorGroupingView roomPreviewer={roomPreviewer} pageParser={ pageParser } />;
|
//return <CatalogLayoutColorGroupingView { ...layoutProps } />;
|
||||||
case 'bots':
|
case 'bots':
|
||||||
case 'default_3x3':
|
case 'default_3x3':
|
||||||
default:
|
default:
|
||||||
return <CatalogLayoutDefaultView roomPreviewer={ roomPreviewer } pageParser={ pageParser } />;
|
return <CatalogLayoutDefaultView { ...layoutProps } />;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,21 +10,19 @@ import { InventoryBadgesRequestEvent } from '../../../../../../events/inventory/
|
|||||||
import { dispatchUiEvent, useUiEvent } from '../../../../../../hooks';
|
import { dispatchUiEvent, useUiEvent } from '../../../../../../hooks';
|
||||||
import { BadgeImageView } from '../../../../../../views/shared/badge-image/BadgeImageView';
|
import { BadgeImageView } from '../../../../../../views/shared/badge-image/BadgeImageView';
|
||||||
import { useCatalogContext } from '../../../../context/CatalogContext';
|
import { useCatalogContext } from '../../../../context/CatalogContext';
|
||||||
|
import { CatalogProductPreviewView } from '../../offers/CatalogPageOfferPreviewView';
|
||||||
import { CatalogPageOffersView } from '../../offers/CatalogPageOffersView';
|
import { CatalogPageOffersView } from '../../offers/CatalogPageOffersView';
|
||||||
import { CatalogProductPreviewView } from '../../product-preview/CatalogProductPreviewView';
|
|
||||||
import { CatalogLayoutProps } from '../CatalogLayout.types';
|
import { CatalogLayoutProps } from '../CatalogLayout.types';
|
||||||
|
|
||||||
export const CatalogLayoutBadgeDisplayView: FC<CatalogLayoutProps> = props =>
|
export const CatalogLayoutBadgeDisplayView: FC<CatalogLayoutProps> = props =>
|
||||||
{
|
{
|
||||||
const { roomPreviewer = null, pageParser = null } = props;
|
const { page = null, roomPreviewer = null } = props;
|
||||||
const [ badges, setBadges ] = useState<string[]>([]);
|
const [ badges, setBadges ] = useState<string[]>([]);
|
||||||
const [ currentBadge, setCurrentBadge ] = useState<string>(null);
|
const [ currentBadge, setCurrentBadge ] = useState<string>(null);
|
||||||
const { catalogState = null } = useCatalogContext();
|
const { currentOffer = null } = useCatalogContext();
|
||||||
const { activeOffer = null } = catalogState;
|
|
||||||
|
|
||||||
const onInventoryBadgesUpdatedEvent = useCallback((event: InventoryBadgesUpdatedEvent) =>
|
const onInventoryBadgesUpdatedEvent = useCallback((event: InventoryBadgesUpdatedEvent) =>
|
||||||
{
|
{
|
||||||
console.log(event);
|
|
||||||
setBadges(event.badges);
|
setBadges(event.badges);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@ -37,9 +35,10 @@ export const CatalogLayoutBadgeDisplayView: FC<CatalogLayoutProps> = props =>
|
|||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
if(!currentBadge || !activeOffer) return;
|
if(!currentBadge || !currentOffer) return;
|
||||||
|
|
||||||
const productData = [];
|
const productData = [];
|
||||||
|
|
||||||
productData.push('0');
|
productData.push('0');
|
||||||
productData.push(currentBadge);
|
productData.push(currentBadge);
|
||||||
productData.push('');
|
productData.push('');
|
||||||
@ -49,13 +48,13 @@ export const CatalogLayoutBadgeDisplayView: FC<CatalogLayoutProps> = props =>
|
|||||||
const stringDataType = new StringDataType();
|
const stringDataType = new StringDataType();
|
||||||
stringDataType.setValue(productData);
|
stringDataType.setValue(productData);
|
||||||
|
|
||||||
dispatchUiEvent(new SetRoomPreviewerStuffDataEvent(activeOffer, stringDataType));
|
dispatchUiEvent(new SetRoomPreviewerStuffDataEvent(currentOffer, stringDataType));
|
||||||
}, [ currentBadge, activeOffer, roomPreviewer ]);
|
}, [ currentBadge, currentOffer, roomPreviewer ]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid>
|
<Grid>
|
||||||
<Column size={ 7 } overflow="hidden">
|
<Column size={ 7 } overflow="hidden">
|
||||||
<CatalogPageOffersView shrink offers={ pageParser.offers } />
|
<CatalogPageOffersView shrink offers={ page.offers } />
|
||||||
<Column gap={ 1 } overflow="hidden">
|
<Column gap={ 1 } overflow="hidden">
|
||||||
<Text truncate shrink fontWeight="bold">{ LocalizeText('catalog_selectbadge') }</Text>
|
<Text truncate shrink fontWeight="bold">{ LocalizeText('catalog_selectbadge') }</Text>
|
||||||
<Grid grow columnCount={ 5 } overflow="auto">
|
<Grid grow columnCount={ 5 } overflow="auto">
|
||||||
@ -71,7 +70,8 @@ export const CatalogLayoutBadgeDisplayView: FC<CatalogLayoutProps> = props =>
|
|||||||
</Column>
|
</Column>
|
||||||
</Column>
|
</Column>
|
||||||
<Column size={ 5 } overflow="hidden">
|
<Column size={ 5 } overflow="hidden">
|
||||||
<CatalogProductPreviewView pageParser={ pageParser } activeOffer={ activeOffer } roomPreviewer={ roomPreviewer } extra={ currentBadge } disabled={ !currentBadge } />
|
{ !!currentOffer &&
|
||||||
|
<CatalogProductPreviewView offer={ currentOffer } roomPreviewer={ roomPreviewer } extra={ currentBadge } disabled={ !currentBadge } /> }
|
||||||
</Column>
|
</Column>
|
||||||
</Grid>
|
</Grid>
|
||||||
);
|
);
|
||||||
|
@ -1,9 +1,4 @@
|
|||||||
import { CatalogPageMessageOfferData, IFurnitureData } from '@nitrots/nitro-renderer';
|
import { FC, useState } from 'react';
|
||||||
import { FC, useMemo, useState } from 'react';
|
|
||||||
import { GetSessionDataManager } from '../../../../../../api';
|
|
||||||
import { NitroLayoutGrid, NitroLayoutGridColumn } from '../../../../../../layout';
|
|
||||||
import { ProductTypeEnum } from '../../../../common/ProductTypeEnum';
|
|
||||||
import { CatalogPageOffersView } from '../../offers/CatalogPageOffersView';
|
|
||||||
import { CatalogLayoutProps } from '../CatalogLayout.types';
|
import { CatalogLayoutProps } from '../CatalogLayout.types';
|
||||||
|
|
||||||
export interface CatalogLayoutColorGroupViewProps extends CatalogLayoutProps
|
export interface CatalogLayoutColorGroupViewProps extends CatalogLayoutProps
|
||||||
@ -13,79 +8,81 @@ export interface CatalogLayoutColorGroupViewProps extends CatalogLayoutProps
|
|||||||
|
|
||||||
export const CatalogLayoutColorGroupingView : FC<CatalogLayoutColorGroupViewProps> = props =>
|
export const CatalogLayoutColorGroupingView : FC<CatalogLayoutColorGroupViewProps> = props =>
|
||||||
{
|
{
|
||||||
const { roomPreviewer = null, pageParser = null } = props;
|
const { page = null, roomPreviewer = null } = props;
|
||||||
const [ colorableItems, setColorableItems ] = useState<Map<string, number[]>>(new Map<string, number[]>());
|
const [ colorableItems, setColorableItems ] = useState<Map<string, number[]>>(new Map<string, number[]>());
|
||||||
|
|
||||||
const offers = useMemo(() =>
|
// const offers = useMemo(() =>
|
||||||
{
|
// {
|
||||||
const offers: CatalogPageMessageOfferData[] = [];
|
// const offers: CatalogPageMessageOfferData[] = [];
|
||||||
const addedColorableItems = new Map<string, boolean>();
|
// const addedColorableItems = new Map<string, boolean>();
|
||||||
|
|
||||||
pageParser.offers.forEach(offer =>
|
// pageParser.offers.forEach(offer =>
|
||||||
{
|
// {
|
||||||
const product = offer.products[0];
|
// const product = offer.products[0];
|
||||||
if(!product) return;
|
// if(!product) return;
|
||||||
|
|
||||||
let furniData: IFurnitureData = null;
|
// let furniData: IFurnitureData = null;
|
||||||
|
|
||||||
if(product.productType === ProductTypeEnum.FLOOR)
|
// if(product.productType === ProductTypeEnum.FLOOR)
|
||||||
{
|
// {
|
||||||
furniData = GetSessionDataManager().getFloorItemData(product.furniClassId);
|
// furniData = GetSessionDataManager().getFloorItemData(product.furniClassId);
|
||||||
}
|
// }
|
||||||
else if(product.productType === ProductTypeEnum.WALL)
|
// else if(product.productType === ProductTypeEnum.WALL)
|
||||||
{
|
// {
|
||||||
furniData = GetSessionDataManager().getWallItemData(product.furniClassId);
|
// furniData = GetSessionDataManager().getWallItemData(product.furniClassId);
|
||||||
}
|
// }
|
||||||
|
|
||||||
if(((!(furniData)) || ((furniData.fullName.indexOf('*') === -1))))
|
// if(((!(furniData)) || ((furniData.fullName.indexOf('*') === -1))))
|
||||||
{
|
// {
|
||||||
offers.push(offer);
|
// offers.push(offer);
|
||||||
}
|
// }
|
||||||
else
|
// else
|
||||||
{
|
// {
|
||||||
const name = furniData.fullName.split('*')[0];
|
// const name = furniData.fullName.split('*')[0];
|
||||||
const colorIndex = parseInt(furniData.fullName.split('*')[1]);
|
// const colorIndex = parseInt(furniData.fullName.split('*')[1]);
|
||||||
|
|
||||||
if(!colorableItems[name])
|
// if(!colorableItems[name])
|
||||||
{
|
// {
|
||||||
colorableItems[name] = [];
|
// colorableItems[name] = [];
|
||||||
}
|
// }
|
||||||
|
|
||||||
let selectedColor = 0;
|
// let selectedColor = 0;
|
||||||
if(furniData.colors)
|
// if(furniData.colors)
|
||||||
{
|
// {
|
||||||
for(let color of furniData.colors)
|
// for(let color of furniData.colors)
|
||||||
{
|
// {
|
||||||
if(color !== 0xFFFFFF)
|
// if(color !== 0xFFFFFF)
|
||||||
{
|
// {
|
||||||
selectedColor = color;
|
// selectedColor = color;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
if(colorableItems[name].indexOf(selectedColor) === -1)
|
// if(colorableItems[name].indexOf(selectedColor) === -1)
|
||||||
{
|
// {
|
||||||
colorableItems[name][colorIndex] = selectedColor;
|
// colorableItems[name][colorIndex] = selectedColor;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
if(!addedColorableItems.has(name))
|
// if(!addedColorableItems.has(name))
|
||||||
{
|
// {
|
||||||
offers.push(offer);
|
// offers.push(offer);
|
||||||
addedColorableItems.set(name, true);
|
// addedColorableItems.set(name, true);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
console.log(colorableItems);
|
// console.log(colorableItems);
|
||||||
return offers;
|
// return offers;
|
||||||
}, [colorableItems, pageParser.offers]);
|
// }, [colorableItems, pageParser.offers]);
|
||||||
|
|
||||||
return (
|
return null;
|
||||||
<NitroLayoutGrid>
|
|
||||||
<NitroLayoutGridColumn size={ 7 }>
|
|
||||||
<CatalogPageOffersView offers={ offers } />
|
|
||||||
</NitroLayoutGridColumn>
|
|
||||||
<NitroLayoutGridColumn size={ 5 }>
|
|
||||||
|
|
||||||
</NitroLayoutGridColumn>
|
// return (
|
||||||
</NitroLayoutGrid>
|
// <NitroLayoutGrid>
|
||||||
);
|
// <NitroLayoutGridColumn size={ 7 }>
|
||||||
|
// <CatalogPageOffersView offers={ offers } />
|
||||||
|
// </NitroLayoutGridColumn>
|
||||||
|
// <NitroLayoutGridColumn size={ 5 }>
|
||||||
|
|
||||||
|
// </NitroLayoutGridColumn>
|
||||||
|
// </NitroLayoutGrid>
|
||||||
|
// );
|
||||||
}
|
}
|
||||||
|
@ -2,23 +2,26 @@ import { FC } from 'react';
|
|||||||
import { Column } from '../../../../../../common/Column';
|
import { Column } from '../../../../../../common/Column';
|
||||||
import { Grid } from '../../../../../../common/Grid';
|
import { Grid } from '../../../../../../common/Grid';
|
||||||
import { useCatalogContext } from '../../../../context/CatalogContext';
|
import { useCatalogContext } from '../../../../context/CatalogContext';
|
||||||
|
import { CatalogPageDetailsView } from '../../../page-details/CatalogPageDetailsView';
|
||||||
|
import { CatalogProductPreviewView } from '../../offers/CatalogPageOfferPreviewView';
|
||||||
import { CatalogPageOffersView } from '../../offers/CatalogPageOffersView';
|
import { CatalogPageOffersView } from '../../offers/CatalogPageOffersView';
|
||||||
import { CatalogProductPreviewView } from '../../product-preview/CatalogProductPreviewView';
|
|
||||||
import { CatalogLayoutProps } from '../CatalogLayout.types';
|
import { CatalogLayoutProps } from '../CatalogLayout.types';
|
||||||
|
|
||||||
export const CatalogLayoutDefaultView: FC<CatalogLayoutProps> = props =>
|
export const CatalogLayoutDefaultView: FC<CatalogLayoutProps> = props =>
|
||||||
{
|
{
|
||||||
const { roomPreviewer = null, pageParser = null } = props;
|
const { page = null, roomPreviewer = null } = props;
|
||||||
const { catalogState = null } = useCatalogContext();
|
const { currentOffer = null } = useCatalogContext();
|
||||||
const { activeOffer = null } = catalogState;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid>
|
<Grid>
|
||||||
<Column size={ 7 } overflow="hidden">
|
<Column size={ 7 } overflow="hidden">
|
||||||
<CatalogPageOffersView offers={ pageParser.offers } />
|
<CatalogPageOffersView offers={ page.offers } />
|
||||||
</Column>
|
</Column>
|
||||||
<Column size={ 5 } overflow="hidden">
|
<Column size={ 5 } overflow="hidden">
|
||||||
<CatalogProductPreviewView pageParser={ pageParser } activeOffer={ activeOffer } roomPreviewer={ roomPreviewer } />
|
{ !currentOffer &&
|
||||||
|
<CatalogPageDetailsView page={ page } /> }
|
||||||
|
{ !!currentOffer &&
|
||||||
|
<CatalogProductPreviewView offer={ currentOffer } roomPreviewer={ roomPreviewer } /> }
|
||||||
</Column>
|
</Column>
|
||||||
</Grid>
|
</Grid>
|
||||||
);
|
);
|
||||||
|
@ -3,14 +3,15 @@ import { FC, useCallback } from 'react';
|
|||||||
import { CreateLinkEvent } from '../../../../../../api';
|
import { CreateLinkEvent } from '../../../../../../api';
|
||||||
import { Column } from '../../../../../../common/Column';
|
import { Column } from '../../../../../../common/Column';
|
||||||
import { Grid } from '../../../../../../common/Grid';
|
import { Grid } from '../../../../../../common/Grid';
|
||||||
import { GetCatalogPageText } from '../../../../common/CatalogUtilities';
|
import { useCatalogContext } from '../../../../context/CatalogContext';
|
||||||
import { CatalogRedeemVoucherView } from '../../redeem-voucher/CatalogRedeemVoucherView';
|
import { CatalogRedeemVoucherView } from '../../redeem-voucher/CatalogRedeemVoucherView';
|
||||||
import { CatalogLayoutProps } from '../CatalogLayout.types';
|
import { CatalogLayoutProps } from '../CatalogLayout.types';
|
||||||
import { CatalogLayoutFrontPageItemView } from './CatalogLayoutFrontPageItemView';
|
import { CatalogLayoutFrontPageItemView } from './CatalogLayoutFrontPageItemView';
|
||||||
|
|
||||||
export const CatalogLayoutFrontpage4View: FC<CatalogLayoutProps> = props =>
|
export const CatalogLayoutFrontpage4View: FC<CatalogLayoutProps> = props =>
|
||||||
{
|
{
|
||||||
const { pageParser = null } = props;
|
const { page = null } = props;
|
||||||
|
const { frontPageItems = [] } = useCatalogContext();
|
||||||
|
|
||||||
const selectItem = useCallback((item: FrontPageItem) =>
|
const selectItem = useCallback((item: FrontPageItem) =>
|
||||||
{
|
{
|
||||||
@ -28,17 +29,17 @@ export const CatalogLayoutFrontpage4View: FC<CatalogLayoutProps> = props =>
|
|||||||
return (
|
return (
|
||||||
<Grid>
|
<Grid>
|
||||||
<Column size={ 4 }>
|
<Column size={ 4 }>
|
||||||
{ pageParser.frontPageItems[0] &&
|
{ frontPageItems[0] &&
|
||||||
<CatalogLayoutFrontPageItemView item={ pageParser.frontPageItems[0] } onClick={ event => selectItem(pageParser.frontPageItems[0]) } /> }
|
<CatalogLayoutFrontPageItemView item={ frontPageItems[0] } onClick={ event => selectItem(frontPageItems[0]) } /> }
|
||||||
</Column>
|
</Column>
|
||||||
<Column size={ 8 }>
|
<Column size={ 8 }>
|
||||||
{ pageParser.frontPageItems[1] &&
|
{ frontPageItems[1] &&
|
||||||
<CatalogLayoutFrontPageItemView item={ pageParser.frontPageItems[1] } onClick={ event => selectItem(pageParser.frontPageItems[1]) } /> }
|
<CatalogLayoutFrontPageItemView item={ frontPageItems[1] } onClick={ event => selectItem(frontPageItems[1]) } /> }
|
||||||
{ pageParser.frontPageItems[2] &&
|
{ frontPageItems[2] &&
|
||||||
<CatalogLayoutFrontPageItemView item={ pageParser.frontPageItems[2] } onClick={ event => selectItem(pageParser.frontPageItems[2]) } /> }
|
<CatalogLayoutFrontPageItemView item={ frontPageItems[2] } onClick={ event => selectItem(frontPageItems[2]) } /> }
|
||||||
{ pageParser.frontPageItems[3] &&
|
{ frontPageItems[3] &&
|
||||||
<CatalogLayoutFrontPageItemView item={ pageParser.frontPageItems[3] } onClick={ event => selectItem(pageParser.frontPageItems[3]) } /> }
|
<CatalogLayoutFrontPageItemView item={ frontPageItems[3] } onClick={ event => selectItem(frontPageItems[3]) } /> }
|
||||||
<CatalogRedeemVoucherView text={ GetCatalogPageText(pageParser, 1) } />
|
<CatalogRedeemVoucherView text={ page.localization.getText(1) } />
|
||||||
</Column>
|
</Column>
|
||||||
</Grid>
|
</Grid>
|
||||||
);
|
);
|
||||||
|
@ -7,16 +7,16 @@ import { dispatchUiEvent } from '../../../../../../hooks';
|
|||||||
import { SendMessageHook } from '../../../../../../hooks/messages';
|
import { SendMessageHook } from '../../../../../../hooks/messages';
|
||||||
import { useCatalogContext } from '../../../../context/CatalogContext';
|
import { useCatalogContext } from '../../../../context/CatalogContext';
|
||||||
import { CatalogSelectGroupView } from '../../../select-group/CatalogSelectGroupView';
|
import { CatalogSelectGroupView } from '../../../select-group/CatalogSelectGroupView';
|
||||||
|
import { CatalogProductPreviewView } from '../../offers/CatalogPageOfferPreviewView';
|
||||||
import { CatalogPageOffersView } from '../../offers/CatalogPageOffersView';
|
import { CatalogPageOffersView } from '../../offers/CatalogPageOffersView';
|
||||||
import { CatalogProductPreviewView } from '../../product-preview/CatalogProductPreviewView';
|
|
||||||
import { CatalogLayoutProps } from '../CatalogLayout.types';
|
import { CatalogLayoutProps } from '../CatalogLayout.types';
|
||||||
|
|
||||||
export const CatalogLayouGuildCustomFurniView: FC<CatalogLayoutProps> = props =>
|
export const CatalogLayouGuildCustomFurniView: FC<CatalogLayoutProps> = props =>
|
||||||
{
|
{
|
||||||
const { roomPreviewer = null, pageParser = null } = props;
|
const { page = null, roomPreviewer = null } = props;
|
||||||
const [ selectedGroupIndex, setSelectedGroupIndex ] = useState<number>(0);
|
const [ selectedGroupIndex, setSelectedGroupIndex ] = useState<number>(0);
|
||||||
const { catalogState = null } = useCatalogContext();
|
const { currentOffer = null, catalogState = null } = useCatalogContext();
|
||||||
const { activeOffer = null, groups = null } = catalogState;
|
const { groups = null } = catalogState;
|
||||||
|
|
||||||
const selectedGroup = useMemo(() =>
|
const selectedGroup = useMemo(() =>
|
||||||
{
|
{
|
||||||
@ -27,14 +27,17 @@ export const CatalogLayouGuildCustomFurniView: FC<CatalogLayoutProps> = props =>
|
|||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
|
if(!page) return;
|
||||||
|
|
||||||
SendMessageHook(new CatalogGroupsComposer());
|
SendMessageHook(new CatalogGroupsComposer());
|
||||||
}, [ pageParser ]);
|
}, [ page ]);
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
if(!activeOffer || !groups[selectedGroupIndex]) return;
|
if(!currentOffer || !groups[selectedGroupIndex]) return;
|
||||||
|
|
||||||
const productData = [];
|
const productData = [];
|
||||||
|
|
||||||
productData.push('0');
|
productData.push('0');
|
||||||
productData.push(groups[selectedGroupIndex].groupId);
|
productData.push(groups[selectedGroupIndex].groupId);
|
||||||
productData.push(groups[selectedGroupIndex].badgeCode);
|
productData.push(groups[selectedGroupIndex].badgeCode);
|
||||||
@ -44,20 +47,21 @@ export const CatalogLayouGuildCustomFurniView: FC<CatalogLayoutProps> = props =>
|
|||||||
const stringDataType = new StringDataType();
|
const stringDataType = new StringDataType();
|
||||||
stringDataType.setValue(productData);
|
stringDataType.setValue(productData);
|
||||||
|
|
||||||
dispatchUiEvent(new SetRoomPreviewerStuffDataEvent(activeOffer, stringDataType));
|
dispatchUiEvent(new SetRoomPreviewerStuffDataEvent(currentOffer, stringDataType));
|
||||||
}, [ groups, selectedGroupIndex, activeOffer ]);
|
}, [ groups, currentOffer, selectedGroupIndex ]);
|
||||||
|
|
||||||
if(!groups) return null;
|
if(!groups) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid>
|
<Grid>
|
||||||
<Column size={ 7 } overflow="hidden">
|
<Column size={ 7 } overflow="hidden">
|
||||||
<CatalogPageOffersView offers={ pageParser.offers } />
|
<CatalogPageOffersView offers={ page.offers } />
|
||||||
</Column>
|
</Column>
|
||||||
<Column size={ 5 } overflow="hidden">
|
<Column size={ 5 } overflow="hidden">
|
||||||
<CatalogProductPreviewView pageParser={ pageParser } activeOffer={ activeOffer } roomPreviewer={ roomPreviewer } badgeCode={ ((selectedGroup && selectedGroup.badgeCode) || null) } extra={ groups[selectedGroupIndex] ? groups[selectedGroupIndex].groupId.toString() : '' } disabled={ !(!!groups[selectedGroupIndex]) }>
|
{ !!currentOffer &&
|
||||||
|
<CatalogProductPreviewView offer={ currentOffer } roomPreviewer={ roomPreviewer } badgeCode={ ((selectedGroup && selectedGroup.badgeCode) || null) } extra={ groups[selectedGroupIndex] ? groups[selectedGroupIndex].groupId.toString() : '' } disabled={ !(!!groups[selectedGroupIndex]) }>
|
||||||
<CatalogSelectGroupView selectedGroupIndex={ selectedGroupIndex } setSelectedGroupIndex={ setSelectedGroupIndex } />
|
<CatalogSelectGroupView selectedGroupIndex={ selectedGroupIndex } setSelectedGroupIndex={ setSelectedGroupIndex } />
|
||||||
</CatalogProductPreviewView>
|
</CatalogProductPreviewView> }
|
||||||
</Column>
|
</Column>
|
||||||
</Grid>
|
</Grid>
|
||||||
);
|
);
|
||||||
|
@ -4,44 +4,35 @@ import { Base } from '../../../../../../common/Base';
|
|||||||
import { Column } from '../../../../../../common/Column';
|
import { Column } from '../../../../../../common/Column';
|
||||||
import { Grid } from '../../../../../../common/Grid';
|
import { Grid } from '../../../../../../common/Grid';
|
||||||
import { SendMessageHook } from '../../../../../../hooks/messages';
|
import { SendMessageHook } from '../../../../../../hooks/messages';
|
||||||
import { GetCatalogPageText } from '../../../../common/CatalogUtilities';
|
|
||||||
import { useCatalogContext } from '../../../../context/CatalogContext';
|
import { useCatalogContext } from '../../../../context/CatalogContext';
|
||||||
import { CatalogActions } from '../../../../reducers/CatalogReducer';
|
|
||||||
import { CatalogSelectGroupView } from '../../../select-group/CatalogSelectGroupView';
|
import { CatalogSelectGroupView } from '../../../select-group/CatalogSelectGroupView';
|
||||||
import { CatalogProductPreviewView } from '../../product-preview/CatalogProductPreviewView';
|
import { CatalogProductPreviewView } from '../../offers/CatalogPageOfferPreviewView';
|
||||||
import { CatalogLayoutProps } from '../CatalogLayout.types';
|
import { CatalogLayoutProps } from '../CatalogLayout.types';
|
||||||
|
|
||||||
export const CatalogLayouGuildForumView: FC<CatalogLayoutProps> = props =>
|
export const CatalogLayouGuildForumView: FC<CatalogLayoutProps> = props =>
|
||||||
{
|
{
|
||||||
const { pageParser = null } = props;
|
const { page = null } = props;
|
||||||
const [ selectedGroupIndex, setSelectedGroupIndex ] = useState<number>(0);
|
const [ selectedGroupIndex, setSelectedGroupIndex ] = useState<number>(0);
|
||||||
const { catalogState = null, dispatchCatalogState = null } = useCatalogContext();
|
const { currentOffer = null, setCurrentOffer = null, catalogState = null, dispatchCatalogState = null } = useCatalogContext();
|
||||||
const { activeOffer = null, groups = null } = catalogState;
|
const { groups = null } = catalogState;
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
SendMessageHook(new CatalogGroupsComposer());
|
SendMessageHook(new CatalogGroupsComposer());
|
||||||
|
|
||||||
if(pageParser.offers.length > 0)
|
if(page.offers.length) setCurrentOffer(page.offers[0]);
|
||||||
{
|
}, [ page, setCurrentOffer ]);
|
||||||
dispatchCatalogState({
|
|
||||||
type: CatalogActions.SET_CATALOG_ACTIVE_OFFER,
|
|
||||||
payload: {
|
|
||||||
activeOffer: pageParser.offers[0]
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, [ dispatchCatalogState, pageParser ]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid>
|
<Grid>
|
||||||
<Column className="bg-muted rounded p-2 text-black" size={ 7 } overflow="hidden">
|
<Column className="bg-muted rounded p-2 text-black" size={ 7 } overflow="hidden">
|
||||||
<Base className="overflow-auto" dangerouslySetInnerHTML={ { __html: GetCatalogPageText(pageParser, 1) } } />
|
<Base className="overflow-auto" dangerouslySetInnerHTML={ { __html: page.localization.getText(1) } } />
|
||||||
</Column>
|
</Column>
|
||||||
<Column size={ 5 } overflow="hidden">
|
<Column size={ 5 } overflow="hidden">
|
||||||
<CatalogProductPreviewView pageParser={ pageParser } activeOffer={ activeOffer } roomPreviewer={ null } extra={ groups[selectedGroupIndex] ? groups[selectedGroupIndex].groupId.toString() : '' } disabled={ !(!!groups[selectedGroupIndex]) }>
|
{ !!currentOffer &&
|
||||||
|
<CatalogProductPreviewView offer={ currentOffer } roomPreviewer={ null } extra={ groups[selectedGroupIndex] ? groups[selectedGroupIndex].groupId.toString() : '' } disabled={ !(!!groups[selectedGroupIndex]) }>
|
||||||
<CatalogSelectGroupView selectedGroupIndex={ selectedGroupIndex } setSelectedGroupIndex={ setSelectedGroupIndex } />
|
<CatalogSelectGroupView selectedGroupIndex={ selectedGroupIndex } setSelectedGroupIndex={ setSelectedGroupIndex } />
|
||||||
</CatalogProductPreviewView>
|
</CatalogProductPreviewView> }
|
||||||
</Column>
|
</Column>
|
||||||
</Grid>
|
</Grid>
|
||||||
);
|
);
|
||||||
|
@ -5,22 +5,21 @@ import { Button } from '../../../../../../common/Button';
|
|||||||
import { Column } from '../../../../../../common/Column';
|
import { Column } from '../../../../../../common/Column';
|
||||||
import { Grid } from '../../../../../../common/Grid';
|
import { Grid } from '../../../../../../common/Grid';
|
||||||
import { LayoutImage } from '../../../../../../common/layout/LayoutImage';
|
import { LayoutImage } from '../../../../../../common/layout/LayoutImage';
|
||||||
import { GetCatalogPageImage, GetCatalogPageText } from '../../../../common/CatalogUtilities';
|
|
||||||
import { CatalogLayoutProps } from '../CatalogLayout.types';
|
import { CatalogLayoutProps } from '../CatalogLayout.types';
|
||||||
|
|
||||||
export const CatalogLayouGuildFrontpageView: FC<CatalogLayoutProps> = props =>
|
export const CatalogLayouGuildFrontpageView: FC<CatalogLayoutProps> = props =>
|
||||||
{
|
{
|
||||||
const { pageParser = null } = props;
|
const { page = null } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid>
|
<Grid>
|
||||||
<Column size={ 7 } overflow="hidden" className="bg-muted rounded p-2 text-black">
|
<Column size={ 7 } overflow="hidden" className="bg-muted rounded p-2 text-black">
|
||||||
<Base dangerouslySetInnerHTML={ { __html: GetCatalogPageText(pageParser, 2) } } />
|
<Base dangerouslySetInnerHTML={ { __html: page.localization.getText(2) } } />
|
||||||
<Base overflow="auto" dangerouslySetInnerHTML={ { __html: GetCatalogPageText(pageParser, 0) } } />
|
<Base overflow="auto" dangerouslySetInnerHTML={ { __html: page.localization.getText(0) } } />
|
||||||
<Base dangerouslySetInnerHTML={ { __html: GetCatalogPageText(pageParser, 1) } } />
|
<Base dangerouslySetInnerHTML={ { __html: page.localization.getText(1) } } />
|
||||||
</Column>
|
</Column>
|
||||||
<Column center size={ 5 } overflow="hidden">
|
<Column center size={ 5 } overflow="hidden">
|
||||||
<LayoutImage imageUrl={ GetCatalogPageImage(pageParser, 1) } />
|
<LayoutImage imageUrl={ page.localization.getImage(1) } />
|
||||||
<Button onClick={ () => CreateLinkEvent('groups/create') }>
|
<Button onClick={ () => CreateLinkEvent('groups/create') }>
|
||||||
{ LocalizeText('catalog.start.guild.purchase.button') }
|
{ LocalizeText('catalog.start.guild.purchase.button') }
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
import { FC } from 'react';
|
import { FC } from 'react';
|
||||||
import { GetCatalogPageText } from '../../../../common/CatalogUtilities';
|
|
||||||
import { CatalogLayoutProps } from '../CatalogLayout.types';
|
import { CatalogLayoutProps } from '../CatalogLayout.types';
|
||||||
|
|
||||||
export const CatalogLayoutInfoLoyaltyView: FC<CatalogLayoutProps> = props =>
|
export const CatalogLayoutInfoLoyaltyView: FC<CatalogLayoutProps> = props =>
|
||||||
{
|
{
|
||||||
const { pageParser = null } = props;
|
const { page = null } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-100 nitro-catalog-layout-info-loyalty text-black d-flex flex-row">
|
<div className="h-100 nitro-catalog-layout-info-loyalty text-black d-flex flex-row">
|
||||||
<div className="overflow-auto h-100 d-flex flex-column info-loyalty-content">
|
<div className="overflow-auto h-100 d-flex flex-column info-loyalty-content">
|
||||||
<div dangerouslySetInnerHTML={ { __html: GetCatalogPageText(pageParser, 0) } } />
|
<div dangerouslySetInnerHTML={ { __html: page.localization.getText(0) } } />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { ApproveNameMessageComposer, CatalogPageMessageOfferData } from '@nitrots/nitro-renderer';
|
import { ApproveNameMessageComposer } from '@nitrots/nitro-renderer';
|
||||||
import { FC, useCallback, useState } from 'react';
|
import { FC, useCallback, useState } from 'react';
|
||||||
import { LocalizeText } from '../../../../../../api';
|
import { LocalizeText } from '../../../../../../api';
|
||||||
import { Column } from '../../../../../../common/Column';
|
import { Column } from '../../../../../../common/Column';
|
||||||
@ -8,13 +8,15 @@ import { CatalogEvent } from '../../../../../../events';
|
|||||||
import { useUiEvent } from '../../../../../../hooks/events/ui/ui-event';
|
import { useUiEvent } from '../../../../../../hooks/events/ui/ui-event';
|
||||||
import { SendMessageHook } from '../../../../../../hooks/messages/message-event';
|
import { SendMessageHook } from '../../../../../../hooks/messages/message-event';
|
||||||
import { CurrencyIcon } from '../../../../../../views/shared/currency-icon/CurrencyIcon';
|
import { CurrencyIcon } from '../../../../../../views/shared/currency-icon/CurrencyIcon';
|
||||||
|
import { IPurchasableOffer } from '../../../../common/IPurchasableOffer';
|
||||||
|
import { Offer } from '../../../../common/Offer';
|
||||||
import { CatalogPurchaseButtonView } from '../../purchase/CatalogPurchaseButtonView';
|
import { CatalogPurchaseButtonView } from '../../purchase/CatalogPurchaseButtonView';
|
||||||
import { CatalogPurchaseGiftButtonView } from '../../purchase/CatalogPurchaseGiftButtonView';
|
import { CatalogPurchaseGiftButtonView } from '../../purchase/CatalogPurchaseGiftButtonView';
|
||||||
import { CatalogPetNameApprovalView } from './CatalogPetNameApprovalView';
|
import { CatalogPetNameApprovalView } from './CatalogPetNameApprovalView';
|
||||||
|
|
||||||
export interface CatalogLayoutPetPurchaseViewProps
|
export interface CatalogLayoutPetPurchaseViewProps
|
||||||
{
|
{
|
||||||
offer: CatalogPageMessageOfferData;
|
offer: IPurchasableOffer;
|
||||||
pageId: number;
|
pageId: number;
|
||||||
extra?: string;
|
extra?: string;
|
||||||
}
|
}
|
||||||
@ -53,22 +55,23 @@ export const CatalogLayoutPetPurchaseView: FC<CatalogLayoutPetPurchaseViewProps>
|
|||||||
<div className="flex-grow-1 align-items-end">
|
<div className="flex-grow-1 align-items-end">
|
||||||
<Text>{ LocalizeText('catalog.bundlewidget.price') }</Text>
|
<Text>{ LocalizeText('catalog.bundlewidget.price') }</Text>
|
||||||
</div>
|
</div>
|
||||||
<Column>
|
<Column gap={ 1 }>
|
||||||
{ (offer.priceCredits > 0) &&
|
{ ((offer.priceType === Offer.PRICE_TYPE_CREDITS_ACTIVITYPOINTS) || (offer.priceType === Offer.PRICE_TYPE_CREDITS)) &&
|
||||||
<Flex alignItems="center" justifyContent="end" gap={ 1 }>
|
<Flex alignItems="center" justifyContent="end" gap={ 1 }>
|
||||||
<Text>{ offer.priceCredits }</Text>
|
<Text>{ offer.priceInCredits }</Text>
|
||||||
<CurrencyIcon type={ -1 } />
|
<CurrencyIcon type={ -1 } />
|
||||||
</Flex> }
|
</Flex> }
|
||||||
{ (offer.priceActivityPoints > 0) &&
|
{ ((offer.priceType === Offer.PRICE_TYPE_CREDITS_ACTIVITYPOINTS) || (offer.priceType === Offer.PRICE_TYPE_ACTIVITYPOINTS)) &&
|
||||||
<Flex alignItems="center" justifyContent="end" gap={ 1 }>
|
<Flex alignItems="center" justifyContent="end" gap={ 1 }>
|
||||||
<Text>{ offer.priceActivityPoints }</Text>
|
<Text>{ offer.priceInActivityPoints }</Text>
|
||||||
<CurrencyIcon type={ offer.priceActivityPointsType } />
|
<CurrencyIcon type={ offer.activityPointType } />
|
||||||
</Flex> }
|
</Flex> }
|
||||||
</Column>
|
</Column>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Column gap={ 1 }>
|
<Column gap={ 1 }>
|
||||||
<CatalogPurchaseButtonView offer={ offer } pageId={ pageId } extra={ extraData } quantity={ 1 } isPurchaseAllowed={ nameApproved } beforePurchase={ beforePurchase } />
|
<CatalogPurchaseButtonView offer={ offer } pageId={ pageId } extra={ extraData } quantity={ 1 } isPurchaseAllowed={ nameApproved } beforePurchase={ beforePurchase } />
|
||||||
{ offer.giftable && <CatalogPurchaseGiftButtonView offer={ offer } pageId={ pageId } extra={ extraData } disabled={ nameApproved } /> }
|
{ offer.giftable &&
|
||||||
|
<CatalogPurchaseGiftButtonView offer={ offer } pageId={ pageId } extra={ extraData } disabled={ nameApproved } /> }
|
||||||
</Column>
|
</Column>
|
||||||
</Column>
|
</Column>
|
||||||
);
|
);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { ColorConverter, GetSellablePetPalettesComposer, SellablePetPaletteData } from '@nitrots/nitro-renderer';
|
import { ColorConverter, GetSellablePetPalettesComposer, SellablePetPaletteData } from '@nitrots/nitro-renderer';
|
||||||
import { FC, useEffect, useMemo, useState } from 'react';
|
import { FC, useEffect, useMemo, useState } from 'react';
|
||||||
import { GetProductDataForLocalization, LocalizeText } from '../../../../../../api';
|
import { LocalizeText } from '../../../../../../api';
|
||||||
import { Base } from '../../../../../../common/Base';
|
import { Base } from '../../../../../../common/Base';
|
||||||
import { Button } from '../../../../../../common/Button';
|
import { Button } from '../../../../../../common/Button';
|
||||||
import { Column } from '../../../../../../common/Column';
|
import { Column } from '../../../../../../common/Column';
|
||||||
@ -13,7 +13,6 @@ import { SendMessageHook } from '../../../../../../hooks/messages/message-event'
|
|||||||
import { PetImageView } from '../../../../../../views/shared/pet-image/PetImageView';
|
import { PetImageView } from '../../../../../../views/shared/pet-image/PetImageView';
|
||||||
import { GetPetAvailableColors, GetPetIndexFromLocalization } from '../../../../common/CatalogUtilities';
|
import { GetPetAvailableColors, GetPetIndexFromLocalization } from '../../../../common/CatalogUtilities';
|
||||||
import { useCatalogContext } from '../../../../context/CatalogContext';
|
import { useCatalogContext } from '../../../../context/CatalogContext';
|
||||||
import { CatalogActions } from '../../../../reducers/CatalogReducer';
|
|
||||||
import { CatalogRoomPreviewerView } from '../../../catalog-room-previewer/CatalogRoomPreviewerView';
|
import { CatalogRoomPreviewerView } from '../../../catalog-room-previewer/CatalogRoomPreviewerView';
|
||||||
import { CatalogPageDetailsView } from '../../../page-details/CatalogPageDetailsView';
|
import { CatalogPageDetailsView } from '../../../page-details/CatalogPageDetailsView';
|
||||||
import { CatalogLayoutProps } from '../CatalogLayout.types';
|
import { CatalogLayoutProps } from '../CatalogLayout.types';
|
||||||
@ -21,15 +20,15 @@ import { CatalogLayoutPetPurchaseView } from './CatalogLayoutPetPurchaseView';
|
|||||||
|
|
||||||
export const CatalogLayoutPetView: FC<CatalogLayoutProps> = props =>
|
export const CatalogLayoutPetView: FC<CatalogLayoutProps> = props =>
|
||||||
{
|
{
|
||||||
const { roomPreviewer = null, pageParser = null } = props;
|
const { page = null, roomPreviewer = null } = props;
|
||||||
const [ petIndex, setPetIndex ] = useState(-1);
|
const [ petIndex, setPetIndex ] = useState(-1);
|
||||||
const [ sellablePalettes, setSellablePalettes ] = useState<SellablePetPaletteData[]>([]);
|
const [ sellablePalettes, setSellablePalettes ] = useState<SellablePetPaletteData[]>([]);
|
||||||
const [ selectedPaletteIndex, setSelectedPaletteIndex ] = useState(-1);
|
const [ selectedPaletteIndex, setSelectedPaletteIndex ] = useState(-1);
|
||||||
const [ sellableColors, setSellableColors ] = useState<number[][]>([]);
|
const [ sellableColors, setSellableColors ] = useState<number[][]>([]);
|
||||||
const [ selectedColorIndex, setSelectedColorIndex ] = useState(-1);
|
const [ selectedColorIndex, setSelectedColorIndex ] = useState(-1);
|
||||||
const [ colorsShowing, setColorsShowing ] = useState(false);
|
const [ colorsShowing, setColorsShowing ] = useState(false);
|
||||||
const { catalogState = null, dispatchCatalogState = null } = useCatalogContext();
|
const { currentOffer = null, setCurrentOffer = null, catalogState = null, dispatchCatalogState = null } = useCatalogContext();
|
||||||
const { activeOffer = null, petPalettes = [] } = catalogState;
|
const { petPalettes = [] } = catalogState;
|
||||||
|
|
||||||
const getColor = useMemo(() =>
|
const getColor = useMemo(() =>
|
||||||
{
|
{
|
||||||
@ -69,29 +68,23 @@ export const CatalogLayoutPetView: FC<CatalogLayoutProps> = props =>
|
|||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
if(!pageParser || !pageParser.offers.length) return;
|
if(!page || !page.offers.length) return;
|
||||||
|
|
||||||
const offer = pageParser.offers[0];
|
const offer = page.offers[0];
|
||||||
|
|
||||||
dispatchCatalogState({
|
|
||||||
type: CatalogActions.SET_CATALOG_ACTIVE_OFFER,
|
|
||||||
payload: {
|
|
||||||
activeOffer: offer
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
BatchUpdates(() =>
|
BatchUpdates(() =>
|
||||||
{
|
{
|
||||||
|
setCurrentOffer(offer);
|
||||||
setPetIndex(GetPetIndexFromLocalization(offer.localizationId));
|
setPetIndex(GetPetIndexFromLocalization(offer.localizationId));
|
||||||
setColorsShowing(false);
|
setColorsShowing(false);
|
||||||
});
|
});
|
||||||
}, [ pageParser, dispatchCatalogState ]);
|
}, [ page, setCurrentOffer ]);
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
if(!activeOffer) return;
|
if(!currentOffer) return;
|
||||||
|
|
||||||
const productData = GetProductDataForLocalization(activeOffer.localizationId);
|
const productData = currentOffer.product.productData;
|
||||||
|
|
||||||
if(!productData) return;
|
if(!productData) return;
|
||||||
|
|
||||||
@ -124,7 +117,7 @@ export const CatalogLayoutPetView: FC<CatalogLayoutProps> = props =>
|
|||||||
});
|
});
|
||||||
|
|
||||||
SendMessageHook(new GetSellablePetPalettesComposer(productData.type));
|
SendMessageHook(new GetSellablePetPalettesComposer(productData.type));
|
||||||
}, [ activeOffer, petPalettes ]);
|
}, [ currentOffer, petPalettes ]);
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
@ -154,7 +147,7 @@ export const CatalogLayoutPetView: FC<CatalogLayoutProps> = props =>
|
|||||||
roomPreviewer.addPetIntoRoom(petFigureString);
|
roomPreviewer.addPetIntoRoom(petFigureString);
|
||||||
}, [ roomPreviewer, petIndex, sellablePalettes, selectedPaletteIndex, getColor ]);
|
}, [ roomPreviewer, petIndex, sellablePalettes, selectedPaletteIndex, getColor ]);
|
||||||
|
|
||||||
if(!activeOffer) return null;
|
if(!currentOffer) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid>
|
<Grid>
|
||||||
@ -173,7 +166,7 @@ export const CatalogLayoutPetView: FC<CatalogLayoutProps> = props =>
|
|||||||
</Column>
|
</Column>
|
||||||
<Column size={ 5 } overflow="hidden">
|
<Column size={ 5 } overflow="hidden">
|
||||||
{ (petIndex === -1) &&
|
{ (petIndex === -1) &&
|
||||||
<CatalogPageDetailsView pageParser={ pageParser } /> }
|
<CatalogPageDetailsView page={ page } /> }
|
||||||
{ (petIndex >= 0) &&
|
{ (petIndex >= 0) &&
|
||||||
<>
|
<>
|
||||||
<Column overflow="hidden" position="relative" gap={ 0 }>
|
<Column overflow="hidden" position="relative" gap={ 0 }>
|
||||||
@ -187,7 +180,7 @@ export const CatalogLayoutPetView: FC<CatalogLayoutProps> = props =>
|
|||||||
</Column>
|
</Column>
|
||||||
<Column grow>
|
<Column grow>
|
||||||
<Text grow truncate>{ petBreedName }</Text>
|
<Text grow truncate>{ petBreedName }</Text>
|
||||||
<CatalogLayoutPetPurchaseView offer={ activeOffer } pageId={ pageParser.pageId } extra={ petPurchaseString } />
|
<CatalogLayoutPetPurchaseView offer={ currentOffer } pageId={ page.pageId } extra={ petPurchaseString } />
|
||||||
</Column>
|
</Column>
|
||||||
</> }
|
</> }
|
||||||
</Column>
|
</Column>
|
||||||
|
@ -2,26 +2,25 @@ import { FC } from 'react';
|
|||||||
import { Base } from '../../../../../../common/Base';
|
import { Base } from '../../../../../../common/Base';
|
||||||
import { Column } from '../../../../../../common/Column';
|
import { Column } from '../../../../../../common/Column';
|
||||||
import { Flex } from '../../../../../../common/Flex';
|
import { Flex } from '../../../../../../common/Flex';
|
||||||
import { GetCatalogPageImage, GetCatalogPageText } from '../../../../common/CatalogUtilities';
|
|
||||||
import { CatalogLayoutProps } from '../CatalogLayout.types';
|
import { CatalogLayoutProps } from '../CatalogLayout.types';
|
||||||
|
|
||||||
export const CatalogLayoutPets3View: FC<CatalogLayoutProps> = props =>
|
export const CatalogLayoutPets3View: FC<CatalogLayoutProps> = props =>
|
||||||
{
|
{
|
||||||
const { pageParser = null } = props;
|
const { page = null } = props;
|
||||||
|
|
||||||
const imageUrl = GetCatalogPageImage(pageParser, 1);
|
const imageUrl = page.localization.getImage(1);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Column grow className="bg-muted rounded text-black p-2" overflow="hidden">
|
<Column grow className="bg-muted rounded text-black p-2" overflow="hidden">
|
||||||
<Flex alignItems="center" gap={ 2 }>
|
<Flex alignItems="center" gap={ 2 }>
|
||||||
{ imageUrl && <img alt="" src={ GetCatalogPageImage(pageParser, 1) } /> }
|
{ imageUrl && <img alt="" src={ imageUrl } /> }
|
||||||
<Base className="fs-5" dangerouslySetInnerHTML={ { __html: GetCatalogPageText(pageParser, 1) } } />
|
<Base className="fs-5" dangerouslySetInnerHTML={ { __html: page.localization.getText(1) } } />
|
||||||
</Flex>
|
</Flex>
|
||||||
<Column grow alignItems="center" overflow="auto">
|
<Column grow alignItems="center" overflow="auto">
|
||||||
<Base dangerouslySetInnerHTML={ { __html: GetCatalogPageText(pageParser, 2) } } />
|
<Base dangerouslySetInnerHTML={ { __html: page.localization.getText(2) } } />
|
||||||
</Column>
|
</Column>
|
||||||
<Flex alignItems="center">
|
<Flex alignItems="center">
|
||||||
<Base className="fw-bold" dangerouslySetInnerHTML={ { __html: GetCatalogPageText(pageParser, 3) } } />
|
<Base className="fw-bold" dangerouslySetInnerHTML={ { __html: page.localization.getText(3) } } />
|
||||||
</Flex>
|
</Flex>
|
||||||
</Column>
|
</Column>
|
||||||
);
|
);
|
||||||
|
@ -3,26 +3,24 @@ import { Column } from '../../../../../../common/Column';
|
|||||||
import { Grid } from '../../../../../../common/Grid';
|
import { Grid } from '../../../../../../common/Grid';
|
||||||
import { useCatalogContext } from '../../../../context/CatalogContext';
|
import { useCatalogContext } from '../../../../context/CatalogContext';
|
||||||
import { CatalogPageDetailsView } from '../../../page-details/CatalogPageDetailsView';
|
import { CatalogPageDetailsView } from '../../../page-details/CatalogPageDetailsView';
|
||||||
import { CatalogProductView } from '../../product/CatalogProductView';
|
|
||||||
import { CatalogPurchaseView } from '../../purchase/CatalogPurchaseView';
|
import { CatalogPurchaseView } from '../../purchase/CatalogPurchaseView';
|
||||||
import { CatalogLayoutProps } from '../CatalogLayout.types';
|
import { CatalogLayoutProps } from '../CatalogLayout.types';
|
||||||
|
|
||||||
export const CatalogLayoutSingleBundleView: FC<CatalogLayoutProps> = props =>
|
export const CatalogLayoutSingleBundleView: FC<CatalogLayoutProps> = props =>
|
||||||
{
|
{
|
||||||
const { roomPreviewer = null, pageParser = null } = props;
|
const { page = null, roomPreviewer = null } = props;
|
||||||
const { catalogState = null, dispatchCatalogState = null } = useCatalogContext();
|
const { currentOffer = null } = useCatalogContext();
|
||||||
const { activeOffer = null } = catalogState;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid>
|
<Grid>
|
||||||
<Column size={ 7 } overflow="hidden">
|
<Column size={ 7 } overflow="hidden">
|
||||||
<Grid grow overflow="auto">
|
<Grid grow overflow="auto">
|
||||||
{ activeOffer && activeOffer.products && (activeOffer.products.length > 0) && activeOffer.products.map((product, index) => <CatalogProductView key={ index } itemActive={ false } product={ product } />)}
|
{/* { currentOffer && currentOffer.products && (activeOffer.products.length > 0) && activeOffer.products.map((product, index) => <CatalogProductView key={ index } itemActive={ false } product={ product } />)} */}
|
||||||
</Grid>
|
</Grid>
|
||||||
</Column>
|
</Column>
|
||||||
<Column size={ 5 } overflow="hidden">
|
<Column size={ 5 } overflow="hidden">
|
||||||
<CatalogPageDetailsView pageParser={ pageParser } />
|
<CatalogPageDetailsView page={ page } />
|
||||||
{ activeOffer && <CatalogPurchaseView offer={ activeOffer } pageId={ pageParser.pageId } /> }
|
{ currentOffer && <CatalogPurchaseView offer={ currentOffer } pageId={ page.pageId } /> }
|
||||||
</Column>
|
</Column>
|
||||||
</Grid>
|
</Grid>
|
||||||
);
|
);
|
||||||
|
@ -1,53 +1,41 @@
|
|||||||
import { CatalogPageMessageOfferData, IFurnitureData } from '@nitrots/nitro-renderer';
|
|
||||||
import { FC, useEffect, useState } from 'react';
|
import { FC, useEffect, useState } from 'react';
|
||||||
import { GetSessionDataManager, LocalizeText } from '../../../../../../api';
|
import { LocalizeText } from '../../../../../../api';
|
||||||
import { Button } from '../../../../../../common/Button';
|
import { Button } from '../../../../../../common/Button';
|
||||||
import { ButtonGroup } from '../../../../../../common/ButtonGroup';
|
import { ButtonGroup } from '../../../../../../common/ButtonGroup';
|
||||||
import { Column } from '../../../../../../common/Column';
|
import { Column } from '../../../../../../common/Column';
|
||||||
import { Grid } from '../../../../../../common/Grid';
|
import { Grid } from '../../../../../../common/Grid';
|
||||||
import { ProductTypeEnum } from '../../../../common/ProductTypeEnum';
|
import { BatchUpdates } from '../../../../../../hooks';
|
||||||
|
import { IPurchasableOffer } from '../../../../common/IPurchasableOffer';
|
||||||
import { useCatalogContext } from '../../../../context/CatalogContext';
|
import { useCatalogContext } from '../../../../context/CatalogContext';
|
||||||
|
import { CatalogProductPreviewView } from '../../offers/CatalogPageOfferPreviewView';
|
||||||
import { CatalogPageOffersView } from '../../offers/CatalogPageOffersView';
|
import { CatalogPageOffersView } from '../../offers/CatalogPageOffersView';
|
||||||
import { CatalogProductPreviewView } from '../../product-preview/CatalogProductPreviewView';
|
|
||||||
import { CatalogLayoutProps } from '../CatalogLayout.types';
|
import { CatalogLayoutProps } from '../CatalogLayout.types';
|
||||||
|
|
||||||
export const CatalogLayoutSpacesView: FC<CatalogLayoutProps> = props =>
|
export const CatalogLayoutSpacesView: FC<CatalogLayoutProps> = props =>
|
||||||
{
|
{
|
||||||
const { roomPreviewer = null, pageParser = null } = props;
|
const { page = null, roomPreviewer = null } = props;
|
||||||
const [ groups, setGroups ] = useState<CatalogPageMessageOfferData[][]>([]);
|
const [ groups, setGroups ] = useState<IPurchasableOffer[][]>([]);
|
||||||
const [ activeGroupIndex, setActiveGroupIndex ] = useState(-1);
|
const [ activeGroupIndex, setActiveGroupIndex ] = useState(-1);
|
||||||
const { catalogState } = useCatalogContext();
|
const { currentOffer = null, catalogState } = useCatalogContext();
|
||||||
const { activeOffer = null } = catalogState;
|
const { activeOffer = null } = catalogState;
|
||||||
|
|
||||||
const groupNames = [ 'floors', 'walls', 'views' ];
|
const groupNames = [ 'floors', 'walls', 'views' ];
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
if(!pageParser) return;
|
if(!page) return;
|
||||||
|
|
||||||
const groupedOffers: CatalogPageMessageOfferData[][] = [ [], [], [] ];
|
const groupedOffers: IPurchasableOffer[][] = [ [], [], [] ];
|
||||||
|
|
||||||
for(const offer of pageParser.offers)
|
for(const offer of page.offers)
|
||||||
{
|
{
|
||||||
const product = offer.products[0];
|
const product = offer.product
|
||||||
|
|
||||||
if(!product) continue;
|
if(!product) continue;
|
||||||
|
|
||||||
let furniData: IFurnitureData = null;
|
if(!product.furnitureData) continue;
|
||||||
|
|
||||||
if(product.productType === ProductTypeEnum.FLOOR)
|
const className = product.furnitureData.className;
|
||||||
{
|
|
||||||
furniData = GetSessionDataManager().getFloorItemData(product.furniClassId);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if(product.productType === ProductTypeEnum.WALL)
|
|
||||||
{
|
|
||||||
furniData = GetSessionDataManager().getWallItemData(product.furniClassId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!furniData) continue;
|
|
||||||
|
|
||||||
const className = furniData.className;
|
|
||||||
|
|
||||||
switch(className)
|
switch(className)
|
||||||
{
|
{
|
||||||
@ -63,22 +51,24 @@ export const CatalogLayoutSpacesView: FC<CatalogLayoutProps> = props =>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BatchUpdates(() =>
|
||||||
|
{
|
||||||
setGroups(groupedOffers);
|
setGroups(groupedOffers);
|
||||||
setActiveGroupIndex(0);
|
setActiveGroupIndex(0);
|
||||||
}, [ pageParser ]);
|
});
|
||||||
|
}, [ page ]);
|
||||||
const product = ((activeOffer && activeOffer.products[0]) || null);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid>
|
<Grid>
|
||||||
<Column size={ 7 } overflow="hidden">
|
<Column size={ 7 } overflow="hidden">
|
||||||
<ButtonGroup>
|
<ButtonGroup>
|
||||||
{ groupNames.map((name, index) => <Button key={ index } size="sm" active={ (activeGroupIndex === index) } onClick={ event => setActiveGroupIndex(index) }>{ LocalizeText(`catalog.spaces.tab.${ name }`) }</Button>)}
|
{ groupNames.map((name, index) => <Button key={ index } active={ (activeGroupIndex === index) } onClick={ event => setActiveGroupIndex(index) }>{ LocalizeText(`catalog.spaces.tab.${ name }`) }</Button>)}
|
||||||
</ButtonGroup>
|
</ButtonGroup>
|
||||||
<CatalogPageOffersView offers={ groups[activeGroupIndex] } />
|
<CatalogPageOffersView offers={ groups[activeGroupIndex] } />
|
||||||
</Column>
|
</Column>
|
||||||
<Column size={ 5 } overflow="hidden">
|
<Column size={ 5 } overflow="hidden">
|
||||||
<CatalogProductPreviewView pageParser={ pageParser } activeOffer={ activeOffer } roomPreviewer={ roomPreviewer } />
|
{ !!currentOffer &&
|
||||||
|
<CatalogProductPreviewView offer={ currentOffer } roomPreviewer={ roomPreviewer } /> }
|
||||||
</Column>
|
</Column>
|
||||||
</Grid>
|
</Grid>
|
||||||
);
|
);
|
||||||
|
@ -2,27 +2,25 @@ import { FC, useState } from 'react';
|
|||||||
import { Column } from '../../../../../../common/Column';
|
import { Column } from '../../../../../../common/Column';
|
||||||
import { Grid } from '../../../../../../common/Grid';
|
import { Grid } from '../../../../../../common/Grid';
|
||||||
import { useCatalogContext } from '../../../../context/CatalogContext';
|
import { useCatalogContext } from '../../../../context/CatalogContext';
|
||||||
|
import { CatalogProductPreviewView } from '../../offers/CatalogPageOfferPreviewView';
|
||||||
import { CatalogPageOffersView } from '../../offers/CatalogPageOffersView';
|
import { CatalogPageOffersView } from '../../offers/CatalogPageOffersView';
|
||||||
import { CatalogProductPreviewView } from '../../product-preview/CatalogProductPreviewView';
|
|
||||||
import { CatalogLayoutProps } from '../CatalogLayout.types';
|
import { CatalogLayoutProps } from '../CatalogLayout.types';
|
||||||
|
|
||||||
export const CatalogLayoutTrophiesView: FC<CatalogLayoutProps> = props =>
|
export const CatalogLayoutTrophiesView: FC<CatalogLayoutProps> = props =>
|
||||||
{
|
{
|
||||||
const { roomPreviewer = null, pageParser = null } = props;
|
const { page = null, roomPreviewer = null } = props;
|
||||||
const { catalogState = null, dispatchCatalogState = null } = useCatalogContext();
|
|
||||||
const { activeOffer = null } = catalogState;
|
|
||||||
const [ trophyText, setTrophyText ] = useState<string>('');
|
const [ trophyText, setTrophyText ] = useState<string>('');
|
||||||
|
const { currentOffer = null } = useCatalogContext();
|
||||||
const product = ((activeOffer && activeOffer.products[0]) || null);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid>
|
<Grid>
|
||||||
<Column size={ 7 } overflow="hidden">
|
<Column size={ 7 } overflow="hidden">
|
||||||
<CatalogPageOffersView offers={ pageParser.offers } />
|
<CatalogPageOffersView offers={ page.offers } />
|
||||||
<textarea className="flex-grow-1 form-control w-100" defaultValue={ trophyText || '' } onChange={ event => setTrophyText(event.target.value) } />
|
<textarea className="flex-grow-1 form-control w-100" defaultValue={ trophyText || '' } onChange={ event => setTrophyText(event.target.value) } />
|
||||||
</Column>
|
</Column>
|
||||||
<Column size={ 5 } overflow="hidden">
|
<Column size={ 5 } overflow="hidden">
|
||||||
<CatalogProductPreviewView pageParser={ pageParser } activeOffer={ activeOffer } roomPreviewer={ roomPreviewer } extra={ trophyText } />
|
{ !!currentOffer &&
|
||||||
|
<CatalogProductPreviewView offer={ currentOffer } roomPreviewer={ roomPreviewer } extra={ trophyText } /> }
|
||||||
</Column>
|
</Column>
|
||||||
</Grid>
|
</Grid>
|
||||||
);
|
);
|
||||||
|
@ -1,19 +1,18 @@
|
|||||||
import { CatalogPageMessageOfferData, CatalogPageMessageParser, RoomPreviewer } from '@nitrots/nitro-renderer';
|
import { RoomPreviewer } from '@nitrots/nitro-renderer';
|
||||||
import { FC } from 'react';
|
import { FC } from 'react';
|
||||||
import { Base } from '../../../../../common/Base';
|
import { Base } from '../../../../../common/Base';
|
||||||
import { Column } from '../../../../../common/Column';
|
import { Column } from '../../../../../common/Column';
|
||||||
import { Text } from '../../../../../common/Text';
|
import { Text } from '../../../../../common/Text';
|
||||||
import { BadgeImageView } from '../../../../../views/shared/badge-image/BadgeImageView';
|
import { BadgeImageView } from '../../../../../views/shared/badge-image/BadgeImageView';
|
||||||
import { LimitedEditionCompletePlateView } from '../../../../../views/shared/limited-edition/LimitedEditionCompletePlateView';
|
import { LimitedEditionCompletePlateView } from '../../../../../views/shared/limited-edition/LimitedEditionCompletePlateView';
|
||||||
import { GetOfferName } from '../../../common/CatalogUtilities';
|
import { IPurchasableOffer } from '../../../common/IPurchasableOffer';
|
||||||
|
import { Offer } from '../../../common/Offer';
|
||||||
import { CatalogRoomPreviewerView } from '../../catalog-room-previewer/CatalogRoomPreviewerView';
|
import { CatalogRoomPreviewerView } from '../../catalog-room-previewer/CatalogRoomPreviewerView';
|
||||||
import { CatalogPageDetailsView } from '../../page-details/CatalogPageDetailsView';
|
|
||||||
import { CatalogPurchaseView } from '../purchase/CatalogPurchaseView';
|
import { CatalogPurchaseView } from '../purchase/CatalogPurchaseView';
|
||||||
|
|
||||||
export interface CatalogProductPreviewViewProps
|
export interface CatalogProductPreviewViewProps
|
||||||
{
|
{
|
||||||
pageParser: CatalogPageMessageParser;
|
offer: IPurchasableOffer;
|
||||||
activeOffer: CatalogPageMessageOfferData;
|
|
||||||
roomPreviewer: RoomPreviewer;
|
roomPreviewer: RoomPreviewer;
|
||||||
badgeCode?: string;
|
badgeCode?: string;
|
||||||
extra?: string;
|
extra?: string;
|
||||||
@ -22,29 +21,32 @@ export interface CatalogProductPreviewViewProps
|
|||||||
|
|
||||||
export const CatalogProductPreviewView: FC<CatalogProductPreviewViewProps> = props =>
|
export const CatalogProductPreviewView: FC<CatalogProductPreviewViewProps> = props =>
|
||||||
{
|
{
|
||||||
const { pageParser = null, activeOffer = null, roomPreviewer = null, badgeCode = null, extra = '', disabled = false, children = null } = props;
|
const { offer = null, roomPreviewer = null, badgeCode = null, extra = null, disabled = false, children = null } = props;
|
||||||
|
|
||||||
const product = ((activeOffer && activeOffer.products[0]) || null);
|
const product = ((offer && offer.product) || null);
|
||||||
|
|
||||||
if(!product) return <CatalogPageDetailsView pageParser={ pageParser } />;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Column overflow="hidden" position="relative" gap={ 0 }>
|
<Column overflow="hidden" position="relative" gap={ 0 }>
|
||||||
{ roomPreviewer && <CatalogRoomPreviewerView roomPreviewer={ roomPreviewer } height={ 140 } /> }
|
{ ((offer.pricingModel === Offer.PRICING_MODEL_SINGLE) || (offer.pricingModel === Offer.PRICING_MODEL_MULTI)) &&
|
||||||
{ product.uniqueLimitedItem &&
|
<CatalogRoomPreviewerView roomPreviewer={ roomPreviewer } height={ 140 } /> }
|
||||||
|
{ product.isUniqueLimitedItem &&
|
||||||
<Base fullWidth position="absolute" className="top-1">
|
<Base fullWidth position="absolute" className="top-1">
|
||||||
<LimitedEditionCompletePlateView className="mx-auto" uniqueLimitedItemsLeft={ product.uniqueLimitedItemsLeft } uniqueLimitedSeriesSize={ product.uniqueLimitedSeriesSize } />
|
<LimitedEditionCompletePlateView className="mx-auto" uniqueLimitedItemsLeft={ product.uniqueLimitedItemsLeft } uniqueLimitedSeriesSize={ product.uniqueLimitedItemSeriesSize } />
|
||||||
</Base> }
|
</Base> }
|
||||||
{ badgeCode && badgeCode.length &&
|
{ badgeCode && (badgeCode.length > 0) &&
|
||||||
<Base position="absolute" className="top-1 end-1">
|
<Base position="absolute" className="top-1 end-1">
|
||||||
<BadgeImageView badgeCode={ badgeCode } isGroup={ true } />
|
<BadgeImageView badgeCode={ badgeCode } isGroup={ true } />
|
||||||
</Base> }
|
</Base> }
|
||||||
|
{ offer.badgeCode && (offer.badgeCode.length > 0) &&
|
||||||
|
<Base position="absolute" className="top-1 end-1">
|
||||||
|
<BadgeImageView badgeCode={ offer.badgeCode } />
|
||||||
|
</Base> }
|
||||||
</Column>
|
</Column>
|
||||||
<Column grow>
|
<Column grow>
|
||||||
<Text grow truncate>{ GetOfferName(activeOffer) }</Text>
|
<Text grow truncate>{ offer.localizationName }</Text>
|
||||||
{ children }
|
{ children }
|
||||||
<CatalogPurchaseView offer={ activeOffer } pageId={ pageParser.pageId } extra={ extra } disabled={ disabled } />
|
<CatalogPurchaseView offer={ offer } pageId={ ((offer.page && offer.page.pageId) || -1) } extra={ extra } disabled={ disabled } />
|
||||||
</Column>
|
</Column>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
@ -1,20 +1,23 @@
|
|||||||
import { CatalogPageMessageOfferData, MouseEventType } from '@nitrots/nitro-renderer';
|
import { GetProductOfferComposer, MouseEventType } from '@nitrots/nitro-renderer';
|
||||||
import { FC, MouseEvent, useCallback, useState } from 'react';
|
import { Dispatch, FC, MouseEvent, SetStateAction, useCallback, useState } from 'react';
|
||||||
|
import { SendMessageHook } from '../../../../../hooks';
|
||||||
|
import { FurnitureOffer } from '../../../common/FurnitureOffer';
|
||||||
|
import { IPurchasableOffer } from '../../../common/IPurchasableOffer';
|
||||||
import { useCatalogContext } from '../../../context/CatalogContext';
|
import { useCatalogContext } from '../../../context/CatalogContext';
|
||||||
import { CatalogActions } from '../../../reducers/CatalogReducer';
|
|
||||||
import { CatalogProductView } from '../product/CatalogProductView';
|
import { CatalogProductView } from '../product/CatalogProductView';
|
||||||
|
|
||||||
export interface CatalogPageOfferViewProps
|
export interface CatalogPageOfferViewProps
|
||||||
{
|
{
|
||||||
isActive: boolean;
|
isActive: boolean;
|
||||||
offer: CatalogPageMessageOfferData;
|
offer: IPurchasableOffer;
|
||||||
|
setActiveOffer: Dispatch<SetStateAction<IPurchasableOffer>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CatalogPageOfferView: FC<CatalogPageOfferViewProps> = props =>
|
export const CatalogPageOfferView: FC<CatalogPageOfferViewProps> = props =>
|
||||||
{
|
{
|
||||||
const { isActive = false, offer = null } = props;
|
const { isActive = false, offer = null, setActiveOffer = null } = props;
|
||||||
const [ isMouseDown, setMouseDown ] = useState(false);
|
const [ isMouseDown, setMouseDown ] = useState(false);
|
||||||
const { dispatchCatalogState = null } = useCatalogContext();
|
const { setCurrentOffer = null } = useCatalogContext();
|
||||||
|
|
||||||
const onMouseEvent = useCallback((event: MouseEvent) =>
|
const onMouseEvent = useCallback((event: MouseEvent) =>
|
||||||
{
|
{
|
||||||
@ -23,12 +26,16 @@ export const CatalogPageOfferView: FC<CatalogPageOfferViewProps> = props =>
|
|||||||
case MouseEventType.MOUSE_CLICK:
|
case MouseEventType.MOUSE_CLICK:
|
||||||
if(isActive) return;
|
if(isActive) return;
|
||||||
|
|
||||||
dispatchCatalogState({
|
setActiveOffer(offer);
|
||||||
type: CatalogActions.SET_CATALOG_ACTIVE_OFFER,
|
|
||||||
payload: {
|
if(offer instanceof FurnitureOffer)
|
||||||
activeOffer: offer
|
{
|
||||||
|
SendMessageHook(new GetProductOfferComposer(offer.offerId));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
setCurrentOffer(offer);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
case MouseEventType.MOUSE_DOWN:
|
case MouseEventType.MOUSE_DOWN:
|
||||||
setMouseDown(true);
|
setMouseDown(true);
|
||||||
@ -40,9 +47,9 @@ export const CatalogPageOfferView: FC<CatalogPageOfferViewProps> = props =>
|
|||||||
if(!isMouseDown || !isActive) return;
|
if(!isMouseDown || !isActive) return;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}, [ isActive, offer, isMouseDown, dispatchCatalogState ]);
|
}, [ isActive, offer, isMouseDown, setActiveOffer, setCurrentOffer ]);
|
||||||
|
|
||||||
const product = ((offer.products && offer.products[0]) || null);
|
const product = offer.product;
|
||||||
|
|
||||||
if(!product) return null;
|
if(!product) return null;
|
||||||
|
|
||||||
|
@ -1,23 +1,21 @@
|
|||||||
import { CatalogPageMessageOfferData } from '@nitrots/nitro-renderer';
|
import { FC, useState } from 'react';
|
||||||
import { FC } from 'react';
|
|
||||||
import { Grid, GridProps } from '../../../../../common/Grid';
|
import { Grid, GridProps } from '../../../../../common/Grid';
|
||||||
import { useCatalogContext } from '../../../context/CatalogContext';
|
import { IPurchasableOffer } from '../../../common/IPurchasableOffer';
|
||||||
import { CatalogPageOfferView } from './CatalogPageOfferView';
|
import { CatalogPageOfferView } from './CatalogPageOfferView';
|
||||||
|
|
||||||
export interface CatalogPageOffersViewProps extends GridProps
|
export interface CatalogPageOffersViewProps extends GridProps
|
||||||
{
|
{
|
||||||
offers: CatalogPageMessageOfferData[];
|
offers: IPurchasableOffer[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CatalogPageOffersView: FC<CatalogPageOffersViewProps> = props =>
|
export const CatalogPageOffersView: FC<CatalogPageOffersViewProps> = props =>
|
||||||
{
|
{
|
||||||
const { offers = [], children = null, ...rest } = props;
|
const { offers = [], children = null, ...rest } = props;
|
||||||
const { catalogState = null } = useCatalogContext();
|
const [ activeOffer, setActiveOffer ] = useState<IPurchasableOffer>(null);
|
||||||
const { activeOffer = null } = catalogState;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid grow columnCount={ 5 } overflow="auto" { ...rest }>
|
<Grid grow columnCount={ 5 } overflow="auto" { ...rest }>
|
||||||
{ offers && (offers.length > 0) && offers.map((offer, index) => <CatalogPageOfferView key={ index } isActive={ (activeOffer === offer) } offer={ offer } />) }
|
{ offers && (offers.length > 0) && offers.map((offer, index) => <CatalogPageOfferView key={ index } isActive={ (activeOffer === offer) } offer={ offer } setActiveOffer={ setActiveOffer } />) }
|
||||||
{ children }
|
{ children }
|
||||||
</Grid>
|
</Grid>
|
||||||
);
|
);
|
||||||
|
@ -1,27 +1,28 @@
|
|||||||
import { CatalogPageMessageProductData } from '@nitrots/nitro-renderer';
|
|
||||||
import { FC } from 'react';
|
import { FC } from 'react';
|
||||||
import { LayoutGridItem, LayoutGridItemProps } from '../../../../../common/layout/LayoutGridItem';
|
import { LayoutGridItem, LayoutGridItemProps } from '../../../../../common/layout/LayoutGridItem';
|
||||||
import { AvatarImageView } from '../../../../../views/shared/avatar-image/AvatarImageView';
|
import { AvatarImageView } from '../../../../../views/shared/avatar-image/AvatarImageView';
|
||||||
import { GetProductIconUrl } from '../../../common/GetProuductIconUrl';
|
import { GetProductIconUrl } from '../../../common/GetProuductIconUrl';
|
||||||
|
import { IProduct } from '../../../common/IProduct';
|
||||||
import { ProductTypeEnum } from '../../../common/ProductTypeEnum';
|
import { ProductTypeEnum } from '../../../common/ProductTypeEnum';
|
||||||
|
|
||||||
export interface CatalogProductViewProps extends LayoutGridItemProps
|
export interface CatalogProductViewProps extends LayoutGridItemProps
|
||||||
{
|
{
|
||||||
product: CatalogPageMessageProductData;
|
product: IProduct;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CatalogProductView: FC<CatalogProductViewProps> = props =>
|
export const CatalogProductView: FC<CatalogProductViewProps> = props =>
|
||||||
{
|
{
|
||||||
const { product = null, ...rest } = props;
|
const { product = null, children = null, ...rest } = props;
|
||||||
|
|
||||||
if(!product) return null;
|
if(!product) return null;
|
||||||
|
|
||||||
const iconUrl = GetProductIconUrl(product.furniClassId, product.productType, product.extraParam);
|
const iconUrl = GetProductIconUrl(product.productClassId, product.productType, product.extraParam);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LayoutGridItem itemImage={ iconUrl } itemCount={ product.productCount } itemUniqueSoldout={ (product.uniqueLimitedSeriesSize && !product.uniqueLimitedItemsLeft) } itemUniqueNumber={ product.uniqueLimitedSeriesSize } { ...rest }>
|
<LayoutGridItem itemImage={ iconUrl } itemCount={ product.productCount } itemUniqueSoldout={ (product.uniqueLimitedItemSeriesSize && !product.uniqueLimitedItemsLeft) } itemUniqueNumber={ product.uniqueLimitedItemSeriesSize } { ...rest }>
|
||||||
{ (product.productType === ProductTypeEnum.ROBOT) &&
|
{ (product.productType === ProductTypeEnum.ROBOT) &&
|
||||||
<AvatarImageView figure={ product.extraParam } direction={ 3 } headOnly={ true } /> }
|
<AvatarImageView figure={ product.extraParam } direction={ 3 } headOnly={ true } /> }
|
||||||
|
{ children }
|
||||||
</LayoutGridItem>
|
</LayoutGridItem>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { CatalogPageMessageOfferData, PurchaseFromCatalogComposer } from '@nitrots/nitro-renderer';
|
import { PurchaseFromCatalogComposer } from '@nitrots/nitro-renderer';
|
||||||
import { FC, useCallback, useEffect, useState } from 'react';
|
import { FC, useCallback, useEffect, useState } from 'react';
|
||||||
import { LocalizeText } from '../../../../../api';
|
import { LocalizeText } from '../../../../../api';
|
||||||
import { Button, ButtonProps } from '../../../../../common/Button';
|
import { Button, ButtonProps } from '../../../../../common/Button';
|
||||||
@ -9,10 +9,11 @@ import { SendMessageHook } from '../../../../../hooks/messages/message-event';
|
|||||||
import { LoadingSpinnerView } from '../../../../../layout';
|
import { LoadingSpinnerView } from '../../../../../layout';
|
||||||
import { GetCurrencyAmount } from '../../../../../views/purse/common/CurrencyHelper';
|
import { GetCurrencyAmount } from '../../../../../views/purse/common/CurrencyHelper';
|
||||||
import { CatalogPurchaseState } from '../../../common/CatalogPurchaseState';
|
import { CatalogPurchaseState } from '../../../common/CatalogPurchaseState';
|
||||||
|
import { IPurchasableOffer } from '../../../common/IPurchasableOffer';
|
||||||
|
|
||||||
export interface CatalogPurchaseButtonViewProps extends ButtonProps
|
export interface CatalogPurchaseButtonViewProps extends ButtonProps
|
||||||
{
|
{
|
||||||
offer: CatalogPageMessageOfferData;
|
offer: IPurchasableOffer;
|
||||||
pageId: number;
|
pageId: number;
|
||||||
extra?: string;
|
extra?: string;
|
||||||
quantity?: number;
|
quantity?: number;
|
||||||
@ -88,21 +89,21 @@ export const CatalogPurchaseButtonView: FC<CatalogPurchaseButtonViewProps> = pro
|
|||||||
}
|
}
|
||||||
}, [ purchaseState, pendingApproval, isPurchaseAllowed, purchase ]);
|
}, [ purchaseState, pendingApproval, isPurchaseAllowed, purchase ]);
|
||||||
|
|
||||||
const product = offer.products[0];
|
const product = offer.product;
|
||||||
|
|
||||||
if(product && product.uniqueLimitedItem && !product.uniqueLimitedItemsLeft)
|
if(product && product.isUniqueLimitedItem && !product.uniqueLimitedItemsLeft)
|
||||||
{
|
{
|
||||||
return <Button variant="danger" size="sm" disabled>{ LocalizeText('catalog.alert.limited_edition_sold_out.title') }</Button>;
|
return <Button variant="danger" size="sm" disabled>{ LocalizeText('catalog.alert.limited_edition_sold_out.title') }</Button>;
|
||||||
}
|
}
|
||||||
|
|
||||||
if((offer.priceCredits * quantity) > GetCurrencyAmount(-1))
|
if((offer.priceInCredits * quantity) > GetCurrencyAmount(-1))
|
||||||
{
|
{
|
||||||
return <Button variant="danger" size="sm" disabled>{ LocalizeText('catalog.alert.notenough.title') }</Button>;
|
return <Button variant="danger" size="sm" disabled>{ LocalizeText('catalog.alert.notenough.title') }</Button>;
|
||||||
}
|
}
|
||||||
|
|
||||||
if((offer.priceActivityPoints * quantity) > GetCurrencyAmount(offer.priceActivityPointsType))
|
if((offer.priceInActivityPoints * quantity) > GetCurrencyAmount(offer.activityPointType))
|
||||||
{
|
{
|
||||||
return <Button variant="danger" size="sm" disabled>{ LocalizeText('catalog.alert.notenough.activitypoints.title.' + offer.priceActivityPointsType) }</Button>;
|
return <Button variant="danger" size="sm" disabled>{ LocalizeText('catalog.alert.notenough.activitypoints.title.' + offer.activityPointType) }</Button>;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(purchaseState)
|
switch(purchaseState)
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import { CatalogPageMessageOfferData } from '@nitrots/nitro-renderer';
|
|
||||||
import { FC } from 'react';
|
import { FC } from 'react';
|
||||||
import { LocalizeText } from '../../../../../api';
|
import { LocalizeText } from '../../../../../api';
|
||||||
import { Button, ButtonProps } from '../../../../../common/Button';
|
import { Button, ButtonProps } from '../../../../../common/Button';
|
||||||
import { CatalogInitGiftEvent } from '../../../../../events/catalog/CatalogInitGiftEvent';
|
import { CatalogInitGiftEvent } from '../../../../../events/catalog/CatalogInitGiftEvent';
|
||||||
import { dispatchUiEvent } from '../../../../../hooks';
|
import { dispatchUiEvent } from '../../../../../hooks';
|
||||||
|
import { IPurchasableOffer } from '../../../common/IPurchasableOffer';
|
||||||
|
|
||||||
export interface CatalogPurchaseGiftButtonViewProps extends ButtonProps
|
export interface CatalogPurchaseGiftButtonViewProps extends ButtonProps
|
||||||
{
|
{
|
||||||
offer: CatalogPageMessageOfferData;
|
offer: IPurchasableOffer;
|
||||||
pageId: number;
|
pageId: number;
|
||||||
extra?: string;
|
extra?: string;
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,18 @@
|
|||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { CatalogPageMessageOfferData } from '@nitrots/nitro-renderer';
|
|
||||||
import { FC, useEffect, useState } from 'react';
|
import { FC, useEffect, useState } from 'react';
|
||||||
import { LocalizeText } from '../../../../../api';
|
import { LocalizeText } from '../../../../../api';
|
||||||
import { Column } from '../../../../../common/Column';
|
import { Column } from '../../../../../common/Column';
|
||||||
import { Flex } from '../../../../../common/Flex';
|
import { Flex } from '../../../../../common/Flex';
|
||||||
import { Text } from '../../../../../common/Text';
|
import { Text } from '../../../../../common/Text';
|
||||||
import { CurrencyIcon } from '../../../../../views/shared/currency-icon/CurrencyIcon';
|
import { CurrencyIcon } from '../../../../../views/shared/currency-icon/CurrencyIcon';
|
||||||
|
import { IPurchasableOffer } from '../../../common/IPurchasableOffer';
|
||||||
|
import { Offer } from '../../../common/Offer';
|
||||||
import { CatalogPurchaseButtonView } from './CatalogPurchaseButtonView';
|
import { CatalogPurchaseButtonView } from './CatalogPurchaseButtonView';
|
||||||
import { CatalogPurchaseGiftButtonView } from './CatalogPurchaseGiftButtonView';
|
import { CatalogPurchaseGiftButtonView } from './CatalogPurchaseGiftButtonView';
|
||||||
|
|
||||||
export interface CatalogPurchaseViewProps
|
export interface CatalogPurchaseViewProps
|
||||||
{
|
{
|
||||||
offer: CatalogPageMessageOfferData;
|
offer: IPurchasableOffer;
|
||||||
pageId: number;
|
pageId: number;
|
||||||
extra?: string;
|
extra?: string;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
@ -54,7 +55,7 @@ export const CatalogPurchaseView: FC<CatalogPurchaseViewProps> = props =>
|
|||||||
setQuantity(1);
|
setQuantity(1);
|
||||||
}, [ offer ]);
|
}, [ offer ]);
|
||||||
|
|
||||||
const extraData = ((extra && extra.length) ? extra : (offer?.products[0]?.extraParam || null));
|
const extraData = ((extra && extra.length) ? extra : (offer.product.extraParam || null));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Column fullWidth grow justifyContent="end">
|
<Column fullWidth grow justifyContent="end">
|
||||||
@ -69,21 +70,22 @@ export const CatalogPurchaseView: FC<CatalogPurchaseViewProps> = props =>
|
|||||||
</Flex> }
|
</Flex> }
|
||||||
</div>
|
</div>
|
||||||
<Column gap={ 1 }>
|
<Column gap={ 1 }>
|
||||||
{ (offer.priceCredits > 0) &&
|
{ ((offer.priceType === Offer.PRICE_TYPE_CREDITS_ACTIVITYPOINTS) || (offer.priceType === Offer.PRICE_TYPE_CREDITS)) &&
|
||||||
<Flex alignItems="center" justifyContent="end" gap={ 1 }>
|
<Flex alignItems="center" justifyContent="end" gap={ 1 }>
|
||||||
<Text>{ offer.priceCredits * quantity }</Text>
|
<Text>{ offer.priceInCredits * quantity }</Text>
|
||||||
<CurrencyIcon type={ -1 } />
|
<CurrencyIcon type={ -1 } />
|
||||||
</Flex> }
|
</Flex> }
|
||||||
{ (offer.priceActivityPoints > 0) &&
|
{ ((offer.priceType === Offer.PRICE_TYPE_CREDITS_ACTIVITYPOINTS) || (offer.priceType === Offer.PRICE_TYPE_ACTIVITYPOINTS)) &&
|
||||||
<Flex alignItems="center" justifyContent="end" gap={ 1 }>
|
<Flex alignItems="center" justifyContent="end" gap={ 1 }>
|
||||||
<Text>{ offer.priceActivityPoints * quantity }</Text>
|
<Text>{ offer.priceInActivityPoints * quantity }</Text>
|
||||||
<CurrencyIcon type={ offer.priceActivityPointsType } />
|
<CurrencyIcon type={ offer.activityPointType } />
|
||||||
</Flex> }
|
</Flex> }
|
||||||
</Column>
|
</Column>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Column gap={ 1 }>
|
<Column gap={ 1 }>
|
||||||
<CatalogPurchaseButtonView offer={ offer } pageId={ pageId } extra={ extraData } quantity={ quantity } disabled={ disabled } />
|
<CatalogPurchaseButtonView offer={ offer } pageId={ pageId } extra={ extraData } quantity={ quantity } disabled={ disabled } />
|
||||||
{ offer.giftable && <CatalogPurchaseGiftButtonView offer={ offer } pageId={ pageId } extra={ extraData } disabled={ disabled } /> }
|
{ offer.giftable &&
|
||||||
|
<CatalogPurchaseGiftButtonView offer={ offer } pageId={ pageId } extra={ extraData } disabled={ disabled } /> }
|
||||||
</Column>
|
</Column>
|
||||||
</Column>
|
</Column>
|
||||||
);
|
);
|
||||||
|
@ -1,49 +0,0 @@
|
|||||||
import { IFurnitureData, RoomPreviewer } from '@nitrots/nitro-renderer';
|
|
||||||
import { FC } from 'react';
|
|
||||||
import { Base } from '../../../../../common/Base';
|
|
||||||
import { Column } from '../../../../../common/Column';
|
|
||||||
import { Grid } from '../../../../../common/Grid';
|
|
||||||
import { Text } from '../../../../../common/Text';
|
|
||||||
import { LimitedEditionCompletePlateView } from '../../../../../views/shared/limited-edition/LimitedEditionCompletePlateView';
|
|
||||||
import { GetOfferName } from '../../../common/CatalogUtilities';
|
|
||||||
import { useCatalogContext } from '../../../context/CatalogContext';
|
|
||||||
import { CatalogRoomPreviewerView } from '../../catalog-room-previewer/CatalogRoomPreviewerView';
|
|
||||||
import { CatalogPurchaseView } from '../purchase/CatalogPurchaseView';
|
|
||||||
import { CatalogSearchResultOffersView } from './CatalogSearchResultOffersView';
|
|
||||||
|
|
||||||
export interface CatalogLayoutSearchResultViewProps
|
|
||||||
{
|
|
||||||
roomPreviewer: RoomPreviewer;
|
|
||||||
furnitureDatas: IFurnitureData[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export const CatalogLayoutSearchResultView: FC<CatalogLayoutSearchResultViewProps> = props =>
|
|
||||||
{
|
|
||||||
const { roomPreviewer = null, furnitureDatas = null } = props;
|
|
||||||
const { catalogState } = useCatalogContext();
|
|
||||||
const { activeOffer = null } = catalogState;
|
|
||||||
|
|
||||||
const product = ((activeOffer && activeOffer.products[0]) || null);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Grid>
|
|
||||||
<Column size={ 7 } overflow="hidden">
|
|
||||||
<CatalogSearchResultOffersView offers={ furnitureDatas } />
|
|
||||||
</Column>
|
|
||||||
{ product &&
|
|
||||||
<Column size={ 5 } overflow="hidden">
|
|
||||||
<Column overflow="hidden" position="relative" gap={ 0 }>
|
|
||||||
{ roomPreviewer && <CatalogRoomPreviewerView roomPreviewer={ roomPreviewer } height={ 140 } /> }
|
|
||||||
{ product.uniqueLimitedItem &&
|
|
||||||
<Base fullWidth position="absolute" className="top-1">
|
|
||||||
<LimitedEditionCompletePlateView className="mx-auto" uniqueLimitedItemsLeft={ product.uniqueLimitedItemsLeft } uniqueLimitedSeriesSize={ product.uniqueLimitedSeriesSize } />
|
|
||||||
</Base> }
|
|
||||||
</Column>
|
|
||||||
<Column grow>
|
|
||||||
<Text grow truncate>{ GetOfferName(activeOffer) }</Text>
|
|
||||||
<CatalogPurchaseView offer={ activeOffer } pageId={ -1 } />
|
|
||||||
</Column>
|
|
||||||
</Column> }
|
|
||||||
</Grid>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
import { GetProductOfferComposer, IFurnitureData, MouseEventType } from '@nitrots/nitro-renderer';
|
|
||||||
import { FC, MouseEvent, useCallback } from 'react';
|
|
||||||
import { LayoutGridItem, LayoutGridItemProps } from '../../../../../common/layout/LayoutGridItem';
|
|
||||||
import { SendMessageHook } from '../../../../../hooks/messages/message-event';
|
|
||||||
import { AvatarImageView } from '../../../../../views/shared/avatar-image/AvatarImageView';
|
|
||||||
import { GetProductIconUrl } from '../../../common/GetProuductIconUrl';
|
|
||||||
import { ProductTypeEnum } from '../../../common/ProductTypeEnum';
|
|
||||||
|
|
||||||
export interface CatalogSearchResultOfferViewProps extends LayoutGridItemProps
|
|
||||||
{
|
|
||||||
offer: IFurnitureData;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const CatalogSearchResultOfferView: FC<CatalogSearchResultOfferViewProps> = props =>
|
|
||||||
{
|
|
||||||
const { offer = null, ...rest } = props;
|
|
||||||
|
|
||||||
const onMouseEvent = useCallback((event: MouseEvent) =>
|
|
||||||
{
|
|
||||||
switch(event.type)
|
|
||||||
{
|
|
||||||
case MouseEventType.MOUSE_DOWN:
|
|
||||||
SendMessageHook(new GetProductOfferComposer(offer.purchaseOfferId));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}, [ offer ]);
|
|
||||||
|
|
||||||
if(!offer) return null;
|
|
||||||
|
|
||||||
const iconUrl = GetProductIconUrl(offer.id, offer.type, offer.customParams);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<LayoutGridItem itemImage={ iconUrl } onMouseDown={ onMouseEvent } { ...rest }>
|
|
||||||
{ (offer.type === ProductTypeEnum.ROBOT) &&
|
|
||||||
<AvatarImageView figure={ offer.customParams } direction={ 3 } headOnly={ true } /> }
|
|
||||||
</LayoutGridItem>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,37 +0,0 @@
|
|||||||
import { GetProductOfferComposer, IFurnitureData } from '@nitrots/nitro-renderer';
|
|
||||||
import { FC, useEffect } from 'react';
|
|
||||||
import { Grid, GridProps } from '../../../../../common/Grid';
|
|
||||||
import { SendMessageHook } from '../../../../../hooks/messages/message-event';
|
|
||||||
import { useCatalogContext } from '../../../context/CatalogContext';
|
|
||||||
import { CatalogSearchResultOfferView } from './CatalogSearchResultOfferView';
|
|
||||||
|
|
||||||
export interface CatalogSearchResultOffersViewProps extends GridProps
|
|
||||||
{
|
|
||||||
offers: IFurnitureData[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export const CatalogSearchResultOffersView: FC<CatalogSearchResultOffersViewProps> = props =>
|
|
||||||
{
|
|
||||||
const { offers = [], children = null, ...rest } = props;
|
|
||||||
const { catalogState = null } = useCatalogContext();
|
|
||||||
const { activeOffer = null } = catalogState;
|
|
||||||
|
|
||||||
useEffect(() =>
|
|
||||||
{
|
|
||||||
if(!offers || !offers.length) return;
|
|
||||||
|
|
||||||
SendMessageHook(new GetProductOfferComposer(offers[0].purchaseOfferId));
|
|
||||||
}, [ offers ]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Grid grow columnCount={ 5 } overflow="auto" { ...rest }>
|
|
||||||
{ offers && (offers.length > 0) && offers.map((offer, index) =>
|
|
||||||
{
|
|
||||||
const isActive = (activeOffer && (activeOffer.products[0].furniClassId === offer.id));
|
|
||||||
|
|
||||||
return <CatalogSearchResultOfferView key={ index } itemActive={ isActive } offer={ offer } />
|
|
||||||
})}
|
|
||||||
{ children }
|
|
||||||
</Grid>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,18 +1,24 @@
|
|||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { IFurnitureData, INodeData } from '@nitrots/nitro-renderer';
|
import { IFurnitureData } from '@nitrots/nitro-renderer';
|
||||||
import { FC, useCallback, useEffect, useState } from 'react';
|
import { FC, useCallback, useEffect, useState } from 'react';
|
||||||
import { GetSessionDataManager, LocalizeText } from '../../../../api';
|
import { GetSessionDataManager, LocalizeText } from '../../../../api';
|
||||||
import { Button } from '../../../../common/Button';
|
import { Button } from '../../../../common/Button';
|
||||||
import { Flex } from '../../../../common/Flex';
|
import { Flex } from '../../../../common/Flex';
|
||||||
|
import { BatchUpdates } from '../../../../hooks';
|
||||||
|
import { CatalogPage } from '../../common/CatalogPage';
|
||||||
|
import { CatalogType } from '../../common/CatalogType';
|
||||||
import { GetOfferNodes } from '../../common/CatalogUtilities';
|
import { GetOfferNodes } from '../../common/CatalogUtilities';
|
||||||
|
import { FurnitureOffer } from '../../common/FurnitureOffer';
|
||||||
|
import { ICatalogPage } from '../../common/ICatalogPage';
|
||||||
|
import { IPurchasableOffer } from '../../common/IPurchasableOffer';
|
||||||
|
import { PageLocalization } from '../../common/PageLocalization';
|
||||||
import { useCatalogContext } from '../../context/CatalogContext';
|
import { useCatalogContext } from '../../context/CatalogContext';
|
||||||
import { CatalogActions } from '../../reducers/CatalogReducer';
|
|
||||||
|
|
||||||
export const CatalogSearchView: FC<{}> = props =>
|
export const CatalogSearchView: FC<{}> = props =>
|
||||||
{
|
{
|
||||||
const [ searchValue, setSearchValue ] = useState('');
|
const [ searchValue, setSearchValue ] = useState('');
|
||||||
const { catalogState = null, dispatchCatalogState = null } = useCatalogContext();
|
const { currentType = null, setActiveNodes = null, currentOffers = null, setCurrentPage = null, catalogState = null, dispatchCatalogState = null } = useCatalogContext();
|
||||||
const { offerRoot = null, searchResult = null } = catalogState;
|
const { searchResult = null } = catalogState;
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
@ -26,73 +32,60 @@ export const CatalogSearchView: FC<{}> = props =>
|
|||||||
|
|
||||||
const processSearch = useCallback((search: string) =>
|
const processSearch = useCallback((search: string) =>
|
||||||
{
|
{
|
||||||
if(!search || !search.length || !offerRoot)
|
search = search.toLocaleLowerCase().replace(' ', '');
|
||||||
{
|
|
||||||
dispatchCatalogState({
|
|
||||||
type: CatalogActions.SET_SEARCH_RESULT,
|
|
||||||
payload: {
|
|
||||||
searchResult: null
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return;
|
if(!search || !search.length) return;
|
||||||
}
|
|
||||||
|
|
||||||
search = search.toLocaleLowerCase();
|
const furnitureDatas = GetSessionDataManager().getAllFurnitureData({
|
||||||
|
|
||||||
const furnitureData = GetSessionDataManager().getAllFurnitureData({
|
|
||||||
loadFurnitureData: null
|
loadFurnitureData: null
|
||||||
});
|
});
|
||||||
|
|
||||||
if(!furnitureData) return;
|
if(!furnitureDatas || !furnitureDatas.length) return;
|
||||||
|
|
||||||
const foundPages: INodeData[] = [];
|
|
||||||
const foundFurniture: IFurnitureData[] = [];
|
const foundFurniture: IFurnitureData[] = [];
|
||||||
|
const foundFurniLines: string[] = [];
|
||||||
|
|
||||||
for(const furniture of furnitureData)
|
for(const furniture of furnitureDatas)
|
||||||
{
|
{
|
||||||
if((furniture.purchaseOfferId === -1) && (furniture.rentOfferId === -1)) continue;
|
if((currentType === CatalogType.BUILDER) && !furniture.availableForBuildersClub) continue;
|
||||||
|
|
||||||
const pages = [
|
if((currentType === CatalogType.NORMAL) && furniture.excludeDynamic) continue;
|
||||||
...GetOfferNodes(offerRoot, furniture.purchaseOfferId),
|
|
||||||
...GetOfferNodes(offerRoot, furniture.rentOfferId)
|
const searchValues = [ furniture.className, furniture.name, furniture.description ].join(' ').replace(/ /gi, '').toLowerCase();
|
||||||
|
|
||||||
|
if((currentType === CatalogType.BUILDER) && (furniture.purchaseOfferId === -1) && (furniture.rentOfferId === -1))
|
||||||
|
{
|
||||||
|
if((furniture.furniLine !== '') && (foundFurniLines.indexOf(furniture.furniLine) < 0))
|
||||||
|
{
|
||||||
|
if(searchValues.indexOf(search) >= 0) foundFurniLines.push(furniture.furniLine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const foundNodes = [
|
||||||
|
...GetOfferNodes(currentOffers, furniture.purchaseOfferId),
|
||||||
|
...GetOfferNodes(currentOffers, furniture.rentOfferId)
|
||||||
];
|
];
|
||||||
|
|
||||||
if(!pages.length) continue;
|
if(foundNodes.length)
|
||||||
|
|
||||||
const searchValue = [ furniture.className, furniture.name ].join(' ').toLocaleLowerCase();
|
|
||||||
|
|
||||||
if(searchValue.indexOf(search) === -1) continue;
|
|
||||||
|
|
||||||
foundPages.push(...pages);
|
|
||||||
foundFurniture.push(furniture);
|
|
||||||
}
|
|
||||||
|
|
||||||
const uniquePages = foundPages.filter((value, index, self) =>
|
|
||||||
{
|
{
|
||||||
return (self.indexOf(value) === index);
|
if(searchValues.indexOf(search) >= 0) foundFurniture.push(furniture);
|
||||||
});
|
|
||||||
|
|
||||||
const catalogPage: INodeData = {
|
if(searchValues.length === 250) break;
|
||||||
visible: true,
|
|
||||||
icon: 0,
|
|
||||||
pageId: -1,
|
|
||||||
pageName: LocalizeText('generic.search'),
|
|
||||||
localization: LocalizeText('generic.search'),
|
|
||||||
children: [ ...uniquePages ],
|
|
||||||
offerIds: []
|
|
||||||
};
|
|
||||||
|
|
||||||
dispatchCatalogState({
|
|
||||||
type: CatalogActions.SET_SEARCH_RESULT,
|
|
||||||
payload: {
|
|
||||||
searchResult: {
|
|
||||||
page: catalogPage,
|
|
||||||
furniture: foundFurniture
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const offers: IPurchasableOffer[] = [];
|
||||||
|
|
||||||
|
for(const furniture of foundFurniture) offers.push(new FurnitureOffer(furniture));
|
||||||
|
|
||||||
|
BatchUpdates(() =>
|
||||||
|
{
|
||||||
|
setCurrentPage((new CatalogPage(-1, 'default_3x3', new PageLocalization([], []), offers, false, 1) as ICatalogPage));
|
||||||
|
setActiveNodes([]);
|
||||||
});
|
});
|
||||||
}, [ offerRoot, dispatchCatalogState ]);
|
}, [ currentOffers, currentType, setCurrentPage, setActiveNodes ]);
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
|
35
src/components/catalog/views/tabs/CatalogTabsView.tsx
Normal file
35
src/components/catalog/views/tabs/CatalogTabsView.tsx
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import { FC } from 'react';
|
||||||
|
import { NitroCardTabsItemView } from '../../../../layout';
|
||||||
|
import { ICatalogNode } from '../../common/ICatalogNode';
|
||||||
|
|
||||||
|
interface CatalogTabsViewsProps
|
||||||
|
{
|
||||||
|
node: ICatalogNode;
|
||||||
|
currentTab: ICatalogNode;
|
||||||
|
setCurrentTab: (node: ICatalogNode) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CatalogTabsViews: FC<CatalogTabsViewsProps> = props =>
|
||||||
|
{
|
||||||
|
const { node = null, currentTab = null, setCurrentTab = null } = props;
|
||||||
|
|
||||||
|
const selectNode = (node: ICatalogNode) =>
|
||||||
|
{
|
||||||
|
setCurrentTab(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{ node && (node.children.length > 0) && node.children.map(child =>
|
||||||
|
{
|
||||||
|
if(!child.isVisible) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<NitroCardTabsItemView key={ child.pageId } isActive={ (currentTab === child) } onClick={ event => selectNode(child) }>
|
||||||
|
{ child.localization }
|
||||||
|
</NitroCardTabsItemView>
|
||||||
|
);
|
||||||
|
}) }
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
27
src/events/catalog/CatalogPageOpenedEvent.ts
Normal file
27
src/events/catalog/CatalogPageOpenedEvent.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import { NitroEvent } from '@nitrots/nitro-renderer';
|
||||||
|
|
||||||
|
export class CatalogPageOpenedEvent extends NitroEvent
|
||||||
|
{
|
||||||
|
public static CATALOG_PAGE_OPENED: string = 'CPOE_CATALOG_PAGE_OPENED';
|
||||||
|
|
||||||
|
private _pageId: number;
|
||||||
|
private _localization: string;
|
||||||
|
|
||||||
|
constructor(pageId: number, localization: string)
|
||||||
|
{
|
||||||
|
super(CatalogPageOpenedEvent.CATALOG_PAGE_OPENED);
|
||||||
|
|
||||||
|
this._pageId = pageId;
|
||||||
|
this._localization = localization;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get pageId(): number
|
||||||
|
{
|
||||||
|
return this._pageId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get localization(): string
|
||||||
|
{
|
||||||
|
return this._localization;
|
||||||
|
}
|
||||||
|
}
|
21
src/events/catalog/CatalogSelectProductEvent.ts
Normal file
21
src/events/catalog/CatalogSelectProductEvent.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import { NitroEvent } from '@nitrots/nitro-renderer';
|
||||||
|
import { IPurchasableOffer } from '../../components/catalog/common/IPurchasableOffer';
|
||||||
|
|
||||||
|
export class CatalogSelectProductEvent extends NitroEvent
|
||||||
|
{
|
||||||
|
public static SELECT_PRODUCT: string = 'CSPE_SELECT_PRODUCT';
|
||||||
|
|
||||||
|
private _offer: IPurchasableOffer;
|
||||||
|
|
||||||
|
constructor(offer: IPurchasableOffer)
|
||||||
|
{
|
||||||
|
super(CatalogSelectProductEvent.SELECT_PRODUCT);
|
||||||
|
|
||||||
|
this._offer = offer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get offer(): IPurchasableOffer
|
||||||
|
{
|
||||||
|
return this._offer;
|
||||||
|
}
|
||||||
|
}
|
@ -1,13 +1,14 @@
|
|||||||
import { CatalogPageMessageOfferData, IObjectData, NitroEvent } from '@nitrots/nitro-renderer';
|
import { IObjectData, NitroEvent } from '@nitrots/nitro-renderer';
|
||||||
|
import { IPurchasableOffer } from '../../components/catalog/common/IPurchasableOffer';
|
||||||
|
|
||||||
export class SetRoomPreviewerStuffDataEvent extends NitroEvent
|
export class SetRoomPreviewerStuffDataEvent extends NitroEvent
|
||||||
{
|
{
|
||||||
public static UPDATE_STUFF_DATA: string = 'SRPSA_UPDATE_STUFF_DATA';
|
public static UPDATE_STUFF_DATA: string = 'SRPSA_UPDATE_STUFF_DATA';
|
||||||
|
|
||||||
private _offer: CatalogPageMessageOfferData;
|
private _offer: IPurchasableOffer;
|
||||||
private _stuffData: IObjectData;
|
private _stuffData: IObjectData;
|
||||||
|
|
||||||
constructor(offer: CatalogPageMessageOfferData, stuffData: IObjectData)
|
constructor(offer: IPurchasableOffer, stuffData: IObjectData)
|
||||||
{
|
{
|
||||||
super(SetRoomPreviewerStuffDataEvent.UPDATE_STUFF_DATA);
|
super(SetRoomPreviewerStuffDataEvent.UPDATE_STUFF_DATA);
|
||||||
|
|
||||||
@ -15,7 +16,7 @@ export class SetRoomPreviewerStuffDataEvent extends NitroEvent
|
|||||||
this._stuffData = stuffData;
|
this._stuffData = stuffData;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get offer(): CatalogPageMessageOfferData
|
public get offer(): IPurchasableOffer
|
||||||
{
|
{
|
||||||
return this._offer;
|
return this._offer;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
export * from './CatalogEvent';
|
export * from './CatalogEvent';
|
||||||
export * from './CatalogNameResultEvent';
|
export * from './CatalogNameResultEvent';
|
||||||
|
export * from './CatalogPageOpenedEvent';
|
||||||
export * from './CatalogPurchasedEvent';
|
export * from './CatalogPurchasedEvent';
|
||||||
export * from './CatalogPurchaseFailureEvent';
|
export * from './CatalogPurchaseFailureEvent';
|
||||||
export * from './CatalogPurchaseSoldOutEvent';
|
export * from './CatalogPurchaseSoldOutEvent';
|
||||||
|
export * from './CatalogSelectProductEvent';
|
||||||
export * from './SetRoomPreviewerStuffDataEvent';
|
export * from './SetRoomPreviewerStuffDataEvent';
|
||||||
|
Loading…
Reference in New Issue
Block a user