nitro-react/src/components/catalog/CatalogView.tsx

374 lines
13 KiB
TypeScript
Raw Normal View History

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-16 05:56:31 +01:00
import { BatchUpdates, UseMountEffect } 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';
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[]>([]);
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([]);
setFrontPageItems([]);
setIsInitialized(false);
setIsVisible(true);
});
}, []);
2022-01-19 08:22:30 +01:00
const getNodeById = useCallback((id: number, node: ICatalogNode = null) =>
{
if(!node) node = rootNode;
if(!node) return null;
if((node.pageId === id) && (node !== rootNode)) return node;
for(const child of node.children)
{
const n = (getNodeById(id, child) as ICatalogNode);
if(n) return n;
}
return null;
}, [ rootNode ]);
const getNodesByOfferId = useCallback((offerId: number, flag: boolean = false) =>
2022-01-19 00:12:48 +01:00
{
if(!currentOffers || !currentOffers.size) return null;
2022-01-19 08:22:30 +01:00
if(flag)
2022-01-19 00:12:48 +01:00
{
const nodes: ICatalogNode[] = [];
const offers = currentOffers.get(offerId);
if(offers && offers.length)
{
for(const offer of offers) (offer.isVisible && nodes.push(offer));
}
if(nodes.length) return nodes;
}
return currentOffers.get(offerId);
}, [ currentOffers ]);
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-16 05:56:31 +01:00
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 08:22:30 +01:00
const activateNode = useCallback((targetNode: ICatalogNode) =>
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 08:22:30 +01:00
if(targetNode.pageId > -1) loadCatalogPage(targetNode.pageId, -1);
2022-01-19 00:12:48 +01:00
}, [ setActiveNodes, loadCatalogPage ]);
2021-04-22 05:26:30 +02:00
const onCatalogEvent = useCallback((event: CatalogEvent) =>
{
2021-07-29 08:03:30 +02:00
let save = false;
2021-04-22 05:26:30 +02:00
switch(event.type)
{
case CatalogEvent.SHOW_CATALOG:
setIsVisible(true);
return;
2021-05-10 19:11:16 +02:00
case CatalogEvent.HIDE_CATALOG:
2021-07-29 08:03:30 +02:00
save = true;
2021-05-10 19:11:16 +02:00
setIsVisible(false);
return;
2021-04-22 05:26:30 +02:00
case CatalogEvent.TOGGLE_CATALOG:
2021-07-29 08:03:30 +02:00
save = true;
2021-04-22 05:26:30 +02:00
setIsVisible(value => !value);
return;
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
useUiEvent(CatalogEvent.SHOW_CATALOG, onCatalogEvent);
2021-05-10 19:11:16 +02:00
useUiEvent(CatalogEvent.HIDE_CATALOG, onCatalogEvent);
2021-04-22 05:26:30 +02:00
useUiEvent(CatalogEvent.TOGGLE_CATALOG, onCatalogEvent);
2021-06-12 04:53:56 +02:00
useUiEvent(CatalogEvent.CATALOG_RESET, onCatalogEvent);
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])
{
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;
if(!isInitialized) SendMessageHook(new GetCatalogIndexComposer(currentType));
}, [ 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
2022-01-05 18:56:39 +01:00
UseMountEffect(() =>
{
SendMessageHook(new GetMarketplaceConfigurationMessageComposer());
SendMessageHook(new GetGiftWrappingConfigurationComposer());
2022-01-06 00:35:15 +01:00
SendMessageHook(new GetClubGiftInfo());
2022-01-05 18:56:39 +01:00
});
2021-04-22 05:26:30 +02:00
return (
2022-01-19 08:22:30 +01:00
<CatalogContextProvider value={ { isVisible, isBusy, setIsBusy, pageId, currentType, setCurrentType, rootNode, setRootNode, currentOffers, setCurrentOffers, currentPage, setCurrentPage, currentOffer, setCurrentOffer, purchasableOffer, setPurchasableOffer, activeNodes, setActiveNodes, frontPageItems, setFrontPageItems, 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
);
}