2022-01-16 05:56:31 +01:00
|
|
|
import { FrontPageItem, GetCatalogIndexComposer, GetCatalogPageComposer, GetClubGiftInfo, GetGiftWrappingConfigurationComposer, GetMarketplaceConfigurationMessageComposer, ILinkEventTracker, RoomPreviewer } from '@nitrots/nitro-renderer';
|
2021-05-05 09:14:54 +02:00
|
|
|
import { FC, useCallback, useEffect, useReducer, useState } from 'react';
|
2021-08-17 05:38:07 +02:00
|
|
|
import { AddEventLinkTracker, GetRoomEngine, LocalizeText, RemoveLinkEventTracker } from '../../api';
|
2021-11-26 06:16:00 +01:00
|
|
|
import { CREDITS, PlaySound } from '../../api/utils/PlaySound';
|
2021-12-04 07:28:34 +01:00
|
|
|
import { Column } from '../../common/Column';
|
|
|
|
import { Grid } from '../../common/Grid';
|
2021-04-22 05:26:30 +02:00
|
|
|
import { CatalogEvent } from '../../events';
|
2022-01-19 21:34:23 +01:00
|
|
|
import { BatchUpdates } from '../../hooks';
|
2021-04-22 05:26:30 +02:00
|
|
|
import { useUiEvent } from '../../hooks/events/ui/ui-event';
|
2021-05-05 09:14:54 +02:00
|
|
|
import { SendMessageHook } from '../../hooks/messages/message-event';
|
2022-01-16 05:56:31 +01:00
|
|
|
import { NitroCardContentView, NitroCardHeaderView, NitroCardTabsView, NitroCardView } from '../../layout';
|
2021-04-22 05:26:30 +02:00
|
|
|
import { CatalogMessageHandler } from './CatalogMessageHandler';
|
2022-01-16 05:56:31 +01:00
|
|
|
import { CatalogPage } from './common/CatalogPage';
|
|
|
|
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';
|
2022-01-19 21:34:23 +01:00
|
|
|
import { SearchResult } from './common/SearchResult';
|
2021-05-05 09:14:54 +02:00
|
|
|
import { CatalogContextProvider } from './context/CatalogContext';
|
2021-07-28 02:01:37 +02:00
|
|
|
import { CatalogReducer, initialCatalog } from './reducers/CatalogReducer';
|
2021-09-17 08:39:58 +02:00
|
|
|
import { CatalogGiftView } from './views/gift/CatalogGiftView';
|
2022-01-16 05:56:31 +01:00
|
|
|
import { CatalogNavigationView } from './views/navigation/CatalogNavigationView';
|
2021-05-05 09:14:54 +02:00
|
|
|
import { CatalogPageView } from './views/page/CatalogPageView';
|
2022-01-06 07:32:44 +01:00
|
|
|
import { MarketplacePostOfferView } from './views/page/layout/marketplace/MarketplacePostOfferView';
|
2022-01-16 05:56:31 +01:00
|
|
|
import { CatalogTabsViews } from './views/tabs/CatalogTabsView';
|
|
|
|
|
|
|
|
const DUMMY_PAGE_ID_FOR_OFFER_SEARCH: number = -12345678;
|
2022-01-19 08:22:30 +01:00
|
|
|
const REQUESTED_PAGE = new RequestedPage();
|
2021-04-22 05:26:30 +02:00
|
|
|
|
2022-01-06 04:07:33 +01:00
|
|
|
export const CatalogView: FC<{}> = props =>
|
2021-04-22 05:26:30 +02:00
|
|
|
{
|
|
|
|
const [ isVisible, setIsVisible ] = useState(false);
|
2022-01-16 05:56:31 +01:00
|
|
|
const [ isInitialized, setIsInitialized ] = useState(false);
|
|
|
|
const [ isBusy, setIsBusy ] = useState(false);
|
|
|
|
const [ forceRefresh, setForceRefresh ] = useState(false);
|
|
|
|
const [ pageId, setPageId ] = useState(-1);
|
|
|
|
const [ previousPageId, setPreviousPageId ] = useState(-1);
|
|
|
|
const [ currentType, setCurrentType ] = useState(CatalogType.NORMAL);
|
2022-01-19 00:12:48 +01:00
|
|
|
const [ rootNode, setRootNode ] = useState<ICatalogNode>(null);
|
2022-01-16 05:56:31 +01:00
|
|
|
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[]>([]);
|
2022-01-19 21:34:23 +01:00
|
|
|
const [ searchResult, setSearchResult ] = useState<SearchResult>(null);
|
2022-01-16 05:56:31 +01:00
|
|
|
const [ frontPageItems, setFrontPageItems ] = useState<FrontPageItem[]>([]);
|
2021-05-10 19:11:16 +02:00
|
|
|
const [ roomPreviewer, setRoomPreviewer ] = useState<RoomPreviewer>(null);
|
2021-05-05 09:14:54 +02:00
|
|
|
const [ catalogState, dispatchCatalogState ] = useReducer(CatalogReducer, initialCatalog);
|
2021-04-22 05:26:30 +02:00
|
|
|
|
2022-01-19 00:12:48 +01:00
|
|
|
const resetState = useCallback(() =>
|
|
|
|
{
|
|
|
|
BatchUpdates(() =>
|
|
|
|
{
|
|
|
|
setPageId(-1);
|
|
|
|
setPreviousPageId(-1);
|
|
|
|
setRootNode(null);
|
|
|
|
setCurrentOffers(null);
|
|
|
|
setCurrentPage(null);
|
|
|
|
setCurrentOffer(null);
|
|
|
|
setPurchasableOffer(null);
|
|
|
|
setCurrentTab(null);
|
|
|
|
setActiveNodes([]);
|
2022-01-19 21:34:23 +01:00
|
|
|
setSearchResult(null);
|
2022-01-19 00:12:48 +01:00
|
|
|
setFrontPageItems([]);
|
|
|
|
setIsInitialized(false);
|
|
|
|
setIsVisible(true);
|
|
|
|
});
|
|
|
|
}, []);
|
|
|
|
|
2022-01-19 08:22:30 +01:00
|
|
|
const loadCatalogPage = useCallback((pageId: number, offerId: number) =>
|
2022-01-16 05:56:31 +01:00
|
|
|
{
|
|
|
|
if(pageId < 0) return;
|
|
|
|
|
|
|
|
BatchUpdates(() =>
|
|
|
|
{
|
|
|
|
setIsBusy(true);
|
|
|
|
setPageId(pageId);
|
|
|
|
});
|
|
|
|
|
|
|
|
SendMessageHook(new GetCatalogPageComposer(pageId, offerId, currentType));
|
|
|
|
}, [ currentType ]);
|
|
|
|
|
|
|
|
const selectOffer = useCallback((offerId: number) =>
|
2021-07-29 08:03:30 +02:00
|
|
|
{
|
2022-01-19 21:34:23 +01:00
|
|
|
if(!currentPage || !currentPage.offers || offerId < 0) return;
|
2022-01-16 05:56:31 +01:00
|
|
|
|
2022-01-19 21:34:23 +01:00
|
|
|
for(const offer of currentPage.offers)
|
|
|
|
{
|
|
|
|
if(offer.offerId !== offerId) continue;
|
|
|
|
|
|
|
|
setCurrentOffer(offer)
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}, [ currentPage ]);
|
2021-07-29 08:03:30 +02:00
|
|
|
|
2022-01-16 05:56:31 +01:00
|
|
|
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 ]);
|
|
|
|
|
2022-01-19 21:34:23 +01:00
|
|
|
const activateNode = useCallback((targetNode: ICatalogNode, offerId: number = -1) =>
|
2022-01-19 00:12:48 +01:00
|
|
|
{
|
|
|
|
setActiveNodes(prevValue =>
|
|
|
|
{
|
|
|
|
const isActive = (prevValue.indexOf(targetNode) >= 0);
|
|
|
|
const isOpen = targetNode.isOpen;
|
|
|
|
const newNodes: ICatalogNode[] = [];
|
|
|
|
|
|
|
|
for(const n of prevValue)
|
|
|
|
{
|
|
|
|
n.deactivate();
|
|
|
|
|
|
|
|
if(n.depth < targetNode.depth)
|
|
|
|
{
|
|
|
|
newNodes.push(n);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
n.close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
targetNode.activate();
|
|
|
|
|
|
|
|
if(isActive && isOpen) targetNode.close();
|
|
|
|
else targetNode.open();
|
|
|
|
|
|
|
|
if(newNodes.indexOf(targetNode) < 0) newNodes.push(targetNode);
|
|
|
|
|
|
|
|
return newNodes;
|
|
|
|
});
|
|
|
|
|
2022-01-19 21:34:23 +01:00
|
|
|
if(targetNode.pageId > -1) loadCatalogPage(targetNode.pageId, offerId);
|
2022-01-19 00:12:48 +01:00
|
|
|
}, [ setActiveNodes, loadCatalogPage ]);
|
|
|
|
|
2021-04-22 05:26:30 +02:00
|
|
|
const onCatalogEvent = useCallback((event: CatalogEvent) =>
|
|
|
|
{
|
|
|
|
switch(event.type)
|
|
|
|
{
|
2021-11-26 04:32:51 +01:00
|
|
|
case CatalogEvent.PURCHASE_SUCCESS:
|
2021-11-26 06:16:00 +01:00
|
|
|
PlaySound(CREDITS);
|
2021-11-26 04:32:51 +01:00
|
|
|
return;
|
2021-04-22 05:26:30 +02:00
|
|
|
}
|
2022-01-16 05:56:31 +01:00
|
|
|
}, []);
|
2021-04-22 05:26:30 +02:00
|
|
|
|
2021-11-26 04:32:51 +01:00
|
|
|
useUiEvent(CatalogEvent.PURCHASE_SUCCESS, onCatalogEvent);
|
2021-04-22 05:26:30 +02:00
|
|
|
|
2021-07-23 07:04:12 +02:00
|
|
|
const linkReceived = useCallback((url: string) =>
|
|
|
|
{
|
|
|
|
const parts = url.split('/');
|
|
|
|
|
|
|
|
if(parts.length < 2) return;
|
|
|
|
|
|
|
|
switch(parts[1])
|
|
|
|
{
|
2022-01-19 21:34:23 +01:00
|
|
|
case 'show':
|
|
|
|
setIsVisible(true);
|
|
|
|
return;
|
|
|
|
case 'hide':
|
|
|
|
setIsVisible(false);
|
|
|
|
return;
|
|
|
|
case 'toggle':
|
|
|
|
setIsVisible(prevValue => !prevValue);
|
|
|
|
return;
|
2021-07-23 07:04:12 +02:00
|
|
|
case 'open':
|
|
|
|
if(parts.length > 2)
|
|
|
|
{
|
2021-07-29 02:13:40 +02:00
|
|
|
if(parts.length === 4)
|
|
|
|
{
|
|
|
|
switch(parts[2])
|
|
|
|
{
|
|
|
|
case 'offerId':
|
2022-01-19 08:22:30 +01:00
|
|
|
|
2021-07-29 02:13:40 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2021-07-23 07:04:12 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
setIsVisible(true);
|
|
|
|
}
|
2021-07-29 02:13:40 +02:00
|
|
|
|
2021-07-23 07:04:12 +02:00
|
|
|
return;
|
|
|
|
}
|
2021-07-25 07:33:30 +02:00
|
|
|
}, []);
|
2021-07-23 07:04:12 +02:00
|
|
|
|
|
|
|
useEffect(() =>
|
|
|
|
{
|
|
|
|
const linkTracker: ILinkEventTracker = {
|
|
|
|
linkReceived,
|
|
|
|
eventUrlPrefix: 'catalog/'
|
|
|
|
};
|
|
|
|
|
|
|
|
AddEventLinkTracker(linkTracker);
|
|
|
|
|
|
|
|
return () => RemoveLinkEventTracker(linkTracker);
|
2021-07-29 08:03:30 +02:00
|
|
|
}, [ linkReceived ]);
|
2021-07-23 07:04:12 +02:00
|
|
|
|
2021-05-05 09:14:54 +02:00
|
|
|
useEffect(() =>
|
2021-04-22 05:26:30 +02:00
|
|
|
{
|
2022-01-16 05:56:31 +01:00
|
|
|
setRoomPreviewer(new RoomPreviewer(GetRoomEngine(), ++RoomPreviewer.PREVIEW_COUNTER));
|
2021-07-23 19:23:31 +02:00
|
|
|
|
2022-01-16 05:56:31 +01:00
|
|
|
return () =>
|
2021-05-05 09:14:54 +02:00
|
|
|
{
|
2022-01-16 05:56:31 +01:00
|
|
|
setRoomPreviewer(prevValue =>
|
|
|
|
{
|
|
|
|
prevValue.dispose();
|
2021-07-28 02:01:37 +02:00
|
|
|
|
2022-01-16 05:56:31 +01:00
|
|
|
return null;
|
|
|
|
});
|
2021-05-05 09:14:54 +02:00
|
|
|
}
|
2022-01-16 05:56:31 +01:00
|
|
|
}, []);
|
2021-07-23 07:04:12 +02:00
|
|
|
|
2022-01-16 05:56:31 +01:00
|
|
|
useEffect(() =>
|
|
|
|
{
|
2022-01-19 00:12:48 +01:00
|
|
|
if(!isVisible) return;
|
|
|
|
|
2022-01-19 21:34:23 +01:00
|
|
|
if(!isInitialized)
|
|
|
|
{
|
|
|
|
SendMessageHook(new GetMarketplaceConfigurationMessageComposer());
|
|
|
|
SendMessageHook(new GetGiftWrappingConfigurationComposer());
|
|
|
|
SendMessageHook(new GetClubGiftInfo());
|
|
|
|
SendMessageHook(new GetCatalogIndexComposer(currentType));
|
|
|
|
}
|
2022-01-19 00:12:48 +01:00
|
|
|
}, [ isVisible, isInitialized, currentType ]);
|
|
|
|
|
|
|
|
useEffect(() =>
|
|
|
|
{
|
|
|
|
if(!rootNode) return;
|
|
|
|
|
2022-01-19 08:22:30 +01:00
|
|
|
setIsInitialized(true);
|
2022-01-19 00:12:48 +01:00
|
|
|
|
2022-01-19 08:22:30 +01:00
|
|
|
switch(REQUESTED_PAGE.requestType)
|
|
|
|
{
|
|
|
|
case RequestedPage.REQUEST_TYPE_NONE:
|
|
|
|
BatchUpdates(() =>
|
2022-01-19 00:12:48 +01:00
|
|
|
{
|
2022-01-19 08:22:30 +01:00
|
|
|
setIsInitialized(true);
|
|
|
|
|
|
|
|
if(rootNode.isBranch)
|
2022-01-19 00:12:48 +01:00
|
|
|
{
|
2022-01-19 08:22:30 +01:00
|
|
|
for(const child of rootNode.children)
|
|
|
|
{
|
|
|
|
if(child && child.isVisible)
|
|
|
|
{
|
|
|
|
setCurrentTab(child);
|
2022-01-19 00:12:48 +01:00
|
|
|
|
2022-01-19 08:22:30 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2022-01-19 00:12:48 +01:00
|
|
|
}
|
2022-01-19 08:22:30 +01:00
|
|
|
});
|
|
|
|
return;
|
2022-01-16 05:56:31 +01:00
|
|
|
case RequestedPage.REQUEST_TYPE_ID:
|
2022-01-19 08:22:30 +01:00
|
|
|
REQUESTED_PAGE.resetRequest();
|
2021-07-23 19:23:31 +02:00
|
|
|
return;
|
2022-01-16 05:56:31 +01:00
|
|
|
case RequestedPage.REQUEST_TYPE_NAME:
|
2022-01-19 08:22:30 +01:00
|
|
|
REQUESTED_PAGE.resetRequest();
|
2022-01-16 05:56:31 +01:00
|
|
|
return;
|
|
|
|
}
|
2022-01-19 08:22:30 +01:00
|
|
|
}, [ rootNode ]);
|
2021-07-23 19:23:31 +02:00
|
|
|
|
2022-01-16 05:56:31 +01:00
|
|
|
useEffect(() =>
|
|
|
|
{
|
2022-01-19 00:12:48 +01:00
|
|
|
if(!currentTab) return;
|
2021-07-23 19:23:31 +02:00
|
|
|
|
2022-01-19 00:12:48 +01:00
|
|
|
if(currentTab.children.length)
|
2022-01-16 05:56:31 +01:00
|
|
|
{
|
2022-01-19 00:12:48 +01:00
|
|
|
for(const child of currentTab.children)
|
2021-07-28 02:01:37 +02:00
|
|
|
{
|
2022-01-19 00:12:48 +01:00
|
|
|
if(!child.isVisible) continue;
|
2021-07-28 02:01:37 +02:00
|
|
|
|
2022-01-19 08:22:30 +01:00
|
|
|
activateNode(child);
|
2021-07-28 02:01:37 +02:00
|
|
|
|
2022-01-19 00:12:48 +01:00
|
|
|
return;
|
2021-07-28 02:01:37 +02:00
|
|
|
}
|
2021-07-23 19:23:31 +02:00
|
|
|
}
|
2022-01-19 00:12:48 +01:00
|
|
|
else
|
|
|
|
{
|
2022-01-19 08:22:30 +01:00
|
|
|
loadCatalogPage(currentTab.pageId, -1);
|
2022-01-19 00:12:48 +01:00
|
|
|
}
|
2022-01-19 08:22:30 +01:00
|
|
|
}, [ currentTab, activateNode, loadCatalogPage ]);
|
2021-05-10 19:11:16 +02:00
|
|
|
|
2021-06-12 04:53:56 +02:00
|
|
|
useEffect(() =>
|
|
|
|
{
|
2022-01-16 05:56:31 +01:00
|
|
|
if(!currentPage) return;
|
2021-06-12 04:53:56 +02:00
|
|
|
|
2022-01-16 05:56:31 +01:00
|
|
|
setCurrentOffer(null);
|
|
|
|
}, [ currentPage ]);
|
2021-06-12 04:53:56 +02:00
|
|
|
|
2021-04-22 05:26:30 +02:00
|
|
|
return (
|
2022-01-19 21:34:23 +01:00
|
|
|
<CatalogContextProvider value={ { isVisible, isBusy, setIsBusy, pageId, currentType, setCurrentType, rootNode, setRootNode, currentOffers, setCurrentOffers, currentPage, setCurrentPage, currentOffer, setCurrentOffer, purchasableOffer, setPurchasableOffer, activeNodes, setActiveNodes, searchResult, setSearchResult, frontPageItems, setFrontPageItems, roomPreviewer, resetState, loadCatalogPage, showCatalogPage, activateNode, catalogState, dispatchCatalogState } }>
|
2021-06-12 04:53:56 +02:00
|
|
|
<CatalogMessageHandler />
|
2021-05-05 09:14:54 +02:00
|
|
|
{ isVisible &&
|
2021-08-09 18:15:08 +02:00
|
|
|
<NitroCardView uniqueKey="catalog" className="nitro-catalog">
|
2022-01-16 05:56:31 +01:00
|
|
|
<NitroCardHeaderView headerText={ LocalizeText('catalog.title') } onCloseClick={ event => { setIsVisible(false); } } />
|
2021-05-05 09:14:54 +02:00
|
|
|
<NitroCardTabsView>
|
2022-01-19 00:12:48 +01:00
|
|
|
<CatalogTabsViews node={ rootNode } currentTab={ currentTab } setCurrentTab={ setCurrentTab } />
|
2021-05-05 09:14:54 +02:00
|
|
|
</NitroCardTabsView>
|
|
|
|
<NitroCardContentView>
|
2021-12-04 07:28:34 +01:00
|
|
|
<Grid>
|
2022-01-16 05:56:31 +01:00
|
|
|
<Column size={ 3 } overflow="hidden">
|
|
|
|
<CatalogNavigationView node={ currentTab } />
|
|
|
|
</Column>
|
|
|
|
<Column size={ 9 } overflow="hidden">
|
|
|
|
<CatalogPageView page={ currentPage } roomPreviewer={ roomPreviewer } />
|
2021-12-04 07:28:34 +01:00
|
|
|
</Column>
|
|
|
|
</Grid>
|
2021-05-05 09:14:54 +02:00
|
|
|
</NitroCardContentView>
|
|
|
|
</NitroCardView> }
|
2021-09-17 08:39:58 +02:00
|
|
|
<CatalogGiftView />
|
2021-12-23 02:48:01 +01:00
|
|
|
<MarketplacePostOfferView />
|
2021-05-05 09:14:54 +02:00
|
|
|
</CatalogContextProvider>
|
2021-04-22 05:26:30 +02:00
|
|
|
);
|
|
|
|
}
|