nitro-react/src/components/catalog/CatalogView.tsx
2022-01-06 01:32:44 -05:00

238 lines
8.9 KiB
TypeScript

import { GetCatalogIndexComposer, GetCatalogPageComposer, GetGiftWrappingConfigurationComposer, GetMarketplaceConfigurationMessageComposer, ILinkEventTracker, INodeData, RoomPreviewer } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useReducer, useState } from 'react';
import { AddEventLinkTracker, GetRoomEngine, LocalizeText, RemoveLinkEventTracker } from '../../api';
import { CREDITS, PlaySound } from '../../api/utils/PlaySound';
import { Column } from '../../common/Column';
import { Grid } from '../../common/Grid';
import { CatalogEvent } from '../../events';
import { UseMountEffect } from '../../hooks';
import { useUiEvent } from '../../hooks/events/ui/ui-event';
import { SendMessageHook } from '../../hooks/messages/message-event';
import { NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../layout';
import { CatalogMessageHandler } from './CatalogMessageHandler';
import { CatalogMode } from './common/CatalogMode';
import { BuildCatalogPageTree } from './common/CatalogUtilities';
import { CatalogContextProvider } from './context/CatalogContext';
import { CatalogReducer, initialCatalog } from './reducers/CatalogReducer';
import { CatalogGiftView } from './views/gift/CatalogGiftView';
import { ACTIVE_PAGES, CatalogNavigationView } from './views/navigation/CatalogNavigationView';
import { CatalogPageView } from './views/page/CatalogPageView';
import { MarketplacePostOfferView } from './views/page/layout/marketplace/MarketplacePostOfferView';
export const CatalogView: FC<{}> = props =>
{
const [ isVisible, setIsVisible ] = useState(false);
const [ roomPreviewer, setRoomPreviewer ] = useState<RoomPreviewer>(null);
const [ pendingPageLookup, setPendingPageLookup ] = useState<{ value: string, isOffer: boolean }>(null);
const [ pendingTree, setPendingTree ] = useState<INodeData[]>(null);
const [ pendingOpenTree, setPendingOpenTree ] = useState<INodeData[]>(null);
const [ catalogState, dispatchCatalogState ] = useReducer(CatalogReducer, initialCatalog);
const [ currentTab, setCurrentTab ] = useState<INodeData>(null);
const { root = null, pageParser = null, activeOffer = null, searchResult = null } = catalogState;
const saveActivePages = useCallback(() =>
{
setPendingOpenTree(ACTIVE_PAGES.slice());
}, []);
const onCatalogEvent = useCallback((event: CatalogEvent) =>
{
let save = false;
switch(event.type)
{
case CatalogEvent.SHOW_CATALOG:
setIsVisible(true);
return;
case CatalogEvent.HIDE_CATALOG:
save = true;
setIsVisible(false);
return;
case CatalogEvent.TOGGLE_CATALOG:
save = true;
setIsVisible(value => !value);
return;
case CatalogEvent.PURCHASE_SUCCESS:
PlaySound(CREDITS);
return;
}
if(save) saveActivePages();
}, [ saveActivePages ]);
useUiEvent(CatalogEvent.SHOW_CATALOG, onCatalogEvent);
useUiEvent(CatalogEvent.HIDE_CATALOG, onCatalogEvent);
useUiEvent(CatalogEvent.TOGGLE_CATALOG, onCatalogEvent);
useUiEvent(CatalogEvent.CATALOG_RESET, onCatalogEvent);
useUiEvent(CatalogEvent.PURCHASE_SUCCESS, onCatalogEvent);
const linkReceived = useCallback((url: string) =>
{
const parts = url.split('/');
if(parts.length < 2) return;
switch(parts[1])
{
case 'open':
if(parts.length > 2)
{
if(parts.length === 4)
{
switch(parts[2])
{
case 'offerId':
setPendingPageLookup({ value: parts[3], isOffer: true });
return;
}
}
setPendingPageLookup({ value: parts[2], isOffer: false });
}
else
{
setIsVisible(true);
}
return;
}
}, []);
useEffect(() =>
{
const linkTracker: ILinkEventTracker = {
linkReceived,
eventUrlPrefix: 'catalog/'
};
AddEventLinkTracker(linkTracker);
return () => RemoveLinkEventTracker(linkTracker);
}, [ 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(() =>
{
setRoomPreviewer(new RoomPreviewer(GetRoomEngine(), ++RoomPreviewer.PREVIEW_COUNTER));
return () =>
{
setRoomPreviewer(prevValue =>
{
prevValue.dispose();
return null;
});
}
}, []);
UseMountEffect(() =>
{
SendMessageHook(new GetMarketplaceConfigurationMessageComposer());
SendMessageHook(new GetGiftWrappingConfigurationComposer());
});
const currentNavigationPage = ((searchResult && searchResult.page) || currentTab);
const navigationHidden = !!(pageParser && pageParser.frontPageItems.length);
return (
<CatalogContextProvider value={ { catalogState, dispatchCatalogState } }>
<CatalogMessageHandler />
{ isVisible &&
<NitroCardView uniqueKey="catalog" className="nitro-catalog">
<NitroCardHeaderView headerText={ LocalizeText('catalog.title') } onCloseClick={ event => { saveActivePages(); setIsVisible(false); } } />
<NitroCardTabsView>
{ root && root.children.length && root.children.map((page, index) =>
{
if(!page.visible) return null;
return (
<NitroCardTabsItemView key={ index } isActive={ (currentTab === page) } onClick={ event => setCurrentTab(page) }>
{ page.localization }
</NitroCardTabsItemView>
);
}) }
</NitroCardTabsView>
<NitroCardContentView>
<Grid>
{ currentNavigationPage && !navigationHidden &&
<Column size={ 3 } overflow="hidden">
<CatalogNavigationView page={ currentNavigationPage } pendingTree={ pendingTree } setPendingTree={ setPendingTree } />
</Column> }
<Column size={ (navigationHidden ? 12 : 9) } overflow="hidden">
<CatalogPageView roomPreviewer={ roomPreviewer } />
</Column>
</Grid>
</NitroCardContentView>
</NitroCardView> }
<CatalogGiftView />
<MarketplacePostOfferView />
</CatalogContextProvider>
);
}