mirror of
https://github.com/billsonnn/nitro-react.git
synced 2025-01-31 10:22:36 +01:00
More catalog updates
This commit is contained in:
parent
4c1130ba0b
commit
2fc709511c
@ -8,7 +8,7 @@ import { CatalogEvent } from '../../events';
|
||||
import { BatchUpdates } from '../../hooks';
|
||||
import { useUiEvent } from '../../hooks/events/ui/ui-event';
|
||||
import { SendMessageHook } from '../../hooks/messages/message-event';
|
||||
import { NitroCardContentView, NitroCardHeaderView, NitroCardTabsView, NitroCardView } from '../../layout';
|
||||
import { NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../layout';
|
||||
import { CatalogMessageHandler } from './CatalogMessageHandler';
|
||||
import { CatalogPage } from './common/CatalogPage';
|
||||
import { CatalogType } from './common/CatalogType';
|
||||
@ -24,7 +24,6 @@ import { CatalogGiftView } from './views/gift/CatalogGiftView';
|
||||
import { CatalogNavigationView } from './views/navigation/CatalogNavigationView';
|
||||
import { CatalogPageView } from './views/page/CatalogPageView';
|
||||
import { MarketplacePostOfferView } from './views/page/layout/marketplace/MarketplacePostOfferView';
|
||||
import { CatalogTabsViews } from './views/tabs/CatalogTabsView';
|
||||
|
||||
const DUMMY_PAGE_ID_FOR_OFFER_SEARCH: number = -12345678;
|
||||
const REQUESTED_PAGE = new RequestedPage();
|
||||
@ -32,14 +31,14 @@ const REQUESTED_PAGE = new RequestedPage();
|
||||
export const CatalogView: FC<{}> = props =>
|
||||
{
|
||||
const [ isVisible, setIsVisible ] = useState(false);
|
||||
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);
|
||||
const [ rootNode, setRootNode ] = useState<ICatalogNode>(null);
|
||||
const [ currentOffers, setCurrentOffers ] = useState<Map<number, ICatalogNode[]>>(null);
|
||||
const [ offersToNodes, setOffersToNodes ] = useState<Map<number, ICatalogNode[]>>(null);
|
||||
const [ currentPage, setCurrentPage ] = useState<ICatalogPage>(null);
|
||||
const [ currentOffer, setCurrentOffer ] = useState<IPurchasableOffer>(null);
|
||||
const [ purchasableOffer, setPurchasableOffer ] = useState<IPurchasableOffer>(null);
|
||||
@ -57,7 +56,7 @@ export const CatalogView: FC<{}> = props =>
|
||||
setPageId(-1);
|
||||
setPreviousPageId(-1);
|
||||
setRootNode(null);
|
||||
setCurrentOffers(null);
|
||||
setOffersToNodes(null);
|
||||
setCurrentPage(null);
|
||||
setCurrentOffer(null);
|
||||
setPurchasableOffer(null);
|
||||
@ -65,11 +64,27 @@ export const CatalogView: FC<{}> = props =>
|
||||
setActiveNodes([]);
|
||||
setSearchResult(null);
|
||||
setFrontPageItems([]);
|
||||
setIsInitialized(false);
|
||||
setIsVisible(true);
|
||||
});
|
||||
}, []);
|
||||
|
||||
const getNodesByOfferId = useCallback((offerId: number, flag: boolean = false) =>
|
||||
{
|
||||
if(!offersToNodes || !offersToNodes.size) return null;
|
||||
|
||||
if(flag)
|
||||
{
|
||||
const nodes: ICatalogNode[] = [];
|
||||
const offers = offersToNodes.get(offerId);
|
||||
|
||||
if(offers && offers.length) for(const offer of offers) (offer.isVisible && nodes.push(offer));
|
||||
|
||||
if(nodes.length) return nodes;
|
||||
}
|
||||
|
||||
return offersToNodes.get(offerId);
|
||||
}, [ offersToNodes ]);
|
||||
|
||||
const loadCatalogPage = useCallback((pageId: number, offerId: number) =>
|
||||
{
|
||||
if(pageId < 0) return;
|
||||
@ -80,7 +95,7 @@ export const CatalogView: FC<{}> = props =>
|
||||
setPageId(pageId);
|
||||
});
|
||||
|
||||
SendMessageHook(new GetCatalogPageComposer(pageId, offerId, currentType));
|
||||
if(pageId > -1) SendMessageHook(new GetCatalogPageComposer(pageId, offerId, currentType));
|
||||
}, [ currentType ]);
|
||||
|
||||
const selectOffer = useCallback((offerId: number) =>
|
||||
@ -123,39 +138,85 @@ export const CatalogView: FC<{}> = props =>
|
||||
|
||||
const activateNode = useCallback((targetNode: ICatalogNode, offerId: number = -1) =>
|
||||
{
|
||||
if(targetNode.parent.pageName === 'root')
|
||||
{
|
||||
if(targetNode.children.length)
|
||||
{
|
||||
for(const child of targetNode.children)
|
||||
{
|
||||
if(!child.isVisible) continue;
|
||||
|
||||
targetNode = child;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const nodes: ICatalogNode[] = [];
|
||||
|
||||
let node = targetNode;
|
||||
|
||||
while(node && node.pageName !== 'root')
|
||||
{
|
||||
nodes.push(node);
|
||||
|
||||
node = node.parent;
|
||||
}
|
||||
|
||||
nodes.reverse();
|
||||
|
||||
setActiveNodes(prevValue =>
|
||||
{
|
||||
const isActive = (prevValue.indexOf(targetNode) >= 0);
|
||||
const isOpen = targetNode.isOpen;
|
||||
const newNodes: ICatalogNode[] = [];
|
||||
|
||||
for(const n of prevValue)
|
||||
for(const existing of prevValue)
|
||||
{
|
||||
n.deactivate();
|
||||
existing.deactivate();
|
||||
|
||||
if(n.depth < targetNode.depth)
|
||||
{
|
||||
newNodes.push(n);
|
||||
}
|
||||
else
|
||||
{
|
||||
n.close();
|
||||
}
|
||||
if(nodes.indexOf(existing) === -1) existing.close();
|
||||
}
|
||||
|
||||
targetNode.activate();
|
||||
for(const n of nodes)
|
||||
{
|
||||
n.activate();
|
||||
|
||||
if(n === targetNode.parent) n.open();
|
||||
}
|
||||
|
||||
if(isActive && isOpen) targetNode.close();
|
||||
else targetNode.open();
|
||||
|
||||
if(newNodes.indexOf(targetNode) < 0) newNodes.push(targetNode);
|
||||
|
||||
return newNodes;
|
||||
return nodes;
|
||||
});
|
||||
|
||||
if(targetNode.pageId > -1) loadCatalogPage(targetNode.pageId, offerId);
|
||||
}, [ setActiveNodes, loadCatalogPage ]);
|
||||
|
||||
const openPageByOfferId = useCallback((offerId: number) =>
|
||||
{
|
||||
BatchUpdates(() =>
|
||||
{
|
||||
setSearchResult(null);
|
||||
|
||||
if(!isVisible)
|
||||
{
|
||||
REQUESTED_PAGE.requestedByOfferId = offerId;
|
||||
|
||||
setIsVisible(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
const nodes = getNodesByOfferId(offerId);
|
||||
|
||||
if(!nodes || !nodes.length) return;
|
||||
|
||||
activateNode(nodes[0], offerId);
|
||||
}
|
||||
});
|
||||
}, [ isVisible, getNodesByOfferId, activateNode ]);
|
||||
|
||||
const onCatalogEvent = useCallback((event: CatalogEvent) =>
|
||||
{
|
||||
switch(event.type)
|
||||
@ -193,7 +254,7 @@ export const CatalogView: FC<{}> = props =>
|
||||
switch(parts[2])
|
||||
{
|
||||
case 'offerId':
|
||||
|
||||
openPageByOfferId(parseInt(parts[3]));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -205,7 +266,7 @@ export const CatalogView: FC<{}> = props =>
|
||||
|
||||
return;
|
||||
}
|
||||
}, []);
|
||||
}, [ openPageByOfferId ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
@ -236,73 +297,48 @@ export const CatalogView: FC<{}> = props =>
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if(!isVisible) return;
|
||||
if(!isVisible || rootNode) return;
|
||||
|
||||
if(!isInitialized)
|
||||
{
|
||||
SendMessageHook(new GetMarketplaceConfigurationMessageComposer());
|
||||
SendMessageHook(new GetGiftWrappingConfigurationComposer());
|
||||
SendMessageHook(new GetClubGiftInfo());
|
||||
SendMessageHook(new GetCatalogIndexComposer(currentType));
|
||||
}
|
||||
}, [ isVisible, isInitialized, currentType ]);
|
||||
SendMessageHook(new GetMarketplaceConfigurationMessageComposer());
|
||||
SendMessageHook(new GetGiftWrappingConfigurationComposer());
|
||||
SendMessageHook(new GetClubGiftInfo());
|
||||
SendMessageHook(new GetCatalogIndexComposer(currentType));
|
||||
}, [ isVisible, rootNode, currentType ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if(!rootNode) return;
|
||||
|
||||
setIsInitialized(true);
|
||||
if(!isVisible || !rootNode) return;
|
||||
|
||||
switch(REQUESTED_PAGE.requestType)
|
||||
{
|
||||
case RequestedPage.REQUEST_TYPE_NONE:
|
||||
BatchUpdates(() =>
|
||||
if(activeNodes && activeNodes.length) return;
|
||||
|
||||
if(rootNode.isBranch)
|
||||
{
|
||||
setIsInitialized(true);
|
||||
|
||||
if(rootNode.isBranch)
|
||||
for(const child of rootNode.children)
|
||||
{
|
||||
for(const child of rootNode.children)
|
||||
if(child && child.isVisible)
|
||||
{
|
||||
if(child && child.isVisible)
|
||||
{
|
||||
setCurrentTab(child);
|
||||
activateNode(child);
|
||||
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return;
|
||||
case RequestedPage.REQUEST_TYPE_ID:
|
||||
REQUESTED_PAGE.resetRequest();
|
||||
return;
|
||||
case RequestedPage.REQUEST_TYPE_OFFER:
|
||||
openPageByOfferId(REQUESTED_PAGE.requestedByOfferId);
|
||||
REQUESTED_PAGE.resetRequest();
|
||||
return;
|
||||
case RequestedPage.REQUEST_TYPE_NAME:
|
||||
REQUESTED_PAGE.resetRequest();
|
||||
return;
|
||||
}
|
||||
}, [ rootNode ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if(!currentTab) return;
|
||||
|
||||
if(currentTab.children.length)
|
||||
{
|
||||
for(const child of currentTab.children)
|
||||
{
|
||||
if(!child.isVisible) continue;
|
||||
|
||||
activateNode(child);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
loadCatalogPage(currentTab.pageId, -1);
|
||||
}
|
||||
}, [ currentTab, activateNode, loadCatalogPage ]);
|
||||
}, [ isVisible, rootNode, activeNodes, activateNode, openPageByOfferId ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
@ -312,18 +348,33 @@ export const CatalogView: FC<{}> = props =>
|
||||
}, [ currentPage ]);
|
||||
|
||||
return (
|
||||
<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 } }>
|
||||
<CatalogContextProvider value={ { isVisible, isBusy, setIsBusy, pageId, currentType, setCurrentType, rootNode, setRootNode, currentOffers: offersToNodes, setCurrentOffers: setOffersToNodes, currentPage, setCurrentPage, currentOffer, setCurrentOffer, purchasableOffer, setPurchasableOffer, activeNodes, setActiveNodes, searchResult, setSearchResult, frontPageItems, setFrontPageItems, roomPreviewer, resetState, loadCatalogPage, showCatalogPage, activateNode, catalogState, dispatchCatalogState } }>
|
||||
<CatalogMessageHandler />
|
||||
{ isVisible &&
|
||||
<NitroCardView uniqueKey="catalog" className="nitro-catalog">
|
||||
<NitroCardHeaderView headerText={ LocalizeText('catalog.title') } onCloseClick={ event => { setIsVisible(false); } } />
|
||||
<NitroCardTabsView>
|
||||
<CatalogTabsViews node={ rootNode } currentTab={ currentTab } setCurrentTab={ setCurrentTab } />
|
||||
{ rootNode && (rootNode.children.length > 0) && rootNode.children.map(child =>
|
||||
{
|
||||
if(!child.isVisible) return null;
|
||||
|
||||
return (
|
||||
<NitroCardTabsItemView key={ child.pageId } isActive={ child.isActive } onClick={ event =>
|
||||
{
|
||||
if(searchResult) setSearchResult(null);
|
||||
|
||||
activateNode(child);
|
||||
} }>
|
||||
{ child.localization }
|
||||
</NitroCardTabsItemView>
|
||||
);
|
||||
}) }
|
||||
</NitroCardTabsView>
|
||||
<NitroCardContentView>
|
||||
<Grid>
|
||||
<Column size={ 3 } overflow="hidden">
|
||||
<CatalogNavigationView node={ currentTab } />
|
||||
{ activeNodes && (activeNodes.length > 0) &&
|
||||
<CatalogNavigationView node={ activeNodes[0] } /> }
|
||||
</Column>
|
||||
<Column size={ 9 } overflow="hidden">
|
||||
<CatalogPageView page={ currentPage } roomPreviewer={ roomPreviewer } />
|
||||
|
@ -2,11 +2,12 @@ export class RequestedPage
|
||||
{
|
||||
public static REQUEST_TYPE_NONE: number = 0;
|
||||
public static REQUEST_TYPE_ID: number = 1;
|
||||
public static REQUEST_TYPE_NAME: number = 2;
|
||||
public static REQUEST_TYPE_OFFER: number = 2;
|
||||
public static REQUEST_TYPE_NAME: number = 3;
|
||||
|
||||
private _requestType: number;
|
||||
private _requestById: number;
|
||||
private _requestedOfferId: number;
|
||||
private _requestedByOfferId: number;
|
||||
private _requestByName: string;
|
||||
|
||||
constructor()
|
||||
@ -17,7 +18,9 @@ export class RequestedPage
|
||||
public resetRequest():void
|
||||
{
|
||||
this._requestType = RequestedPage.REQUEST_TYPE_NONE;
|
||||
this._requestedOfferId = -1;
|
||||
this._requestById = -1;
|
||||
this._requestedByOfferId = -1;
|
||||
this._requestByName = null;
|
||||
}
|
||||
|
||||
public get requestType(): number
|
||||
@ -36,6 +39,17 @@ export class RequestedPage
|
||||
this._requestById = id;
|
||||
}
|
||||
|
||||
public get requestedByOfferId(): number
|
||||
{
|
||||
return this._requestedByOfferId;
|
||||
}
|
||||
|
||||
public set requestedByOfferId(offerId: number)
|
||||
{
|
||||
this._requestType = RequestedPage.REQUEST_TYPE_OFFER;
|
||||
this._requestedByOfferId = offerId;
|
||||
}
|
||||
|
||||
public get requestByName(): string
|
||||
{
|
||||
return this._requestByName;
|
||||
@ -46,14 +60,4 @@ export class RequestedPage
|
||||
this._requestType = RequestedPage.REQUEST_TYPE_NAME;
|
||||
this._requestByName = name;
|
||||
}
|
||||
|
||||
public get requestedOfferId(): number
|
||||
{
|
||||
return this._requestedOfferId;
|
||||
}
|
||||
|
||||
public set requestedOfferId(offerId: number)
|
||||
{
|
||||
this._requestedOfferId = offerId;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { FC } from 'react';
|
||||
import { Column } from '../../../../../common/Column';
|
||||
import { Flex } from '../../../../../common/Flex';
|
||||
import { Grid } from '../../../../../common/Grid';
|
||||
import { Text } from '../../../../../common/Text';
|
||||
import { CatalogAddOnBadgeWidgetView } from '../widgets/CatalogAddOnBadgeWidgetView';
|
||||
@ -10,24 +11,31 @@ import { CatalogLayoutProps } from './CatalogLayout.types';
|
||||
|
||||
export const CatalogLayoutSingleBundleView: FC<CatalogLayoutProps> = props =>
|
||||
{
|
||||
const { page = null, roomPreviewer = null } = props;
|
||||
const { page = null } = props;
|
||||
|
||||
const imageUrl = page.localization.getImage(1);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Grid>
|
||||
<Column justifyContent="center" size={ 7 } overflow="hidden">
|
||||
<Column justifyContent="between" size={ 7 } overflow="hidden">
|
||||
<Text dangerouslySetInnerHTML={ { __html: page.localization.getText(2) } } />
|
||||
<CatalogBundleGridWidgetView />
|
||||
</Column>
|
||||
<Column size={ 5 } overflow="hidden">
|
||||
<Column fullHeight center position="relative">
|
||||
<CatalogAddOnBadgeWidgetView />
|
||||
<CatalogSimplePriceWidgetView />
|
||||
{ imageUrl && <img className="" alt="" src={ imageUrl } /> }
|
||||
<Column fit overflow="hidden" className="bg-muted p-2 rounded">
|
||||
<CatalogBundleGridWidgetView className="nitro-catalog-layout-bundle-grid" fullWidth />
|
||||
</Column>
|
||||
</Column>
|
||||
<Column size={ 5 } overflow="hidden" gap={ 1 }>
|
||||
<Text center overflow="auto">{ page.localization.getText(1) }</Text>
|
||||
<Flex fullHeight center position="relative" overflow="hidden">
|
||||
{ imageUrl && <img className="" alt="" src={ imageUrl } /> }
|
||||
<CatalogAddOnBadgeWidgetView position="absolute" className="bottom-0 start-0" />
|
||||
</Flex>
|
||||
<Column gap={ 1 } position="relative">
|
||||
<Flex center>
|
||||
<CatalogSimplePriceWidgetView />
|
||||
</Flex>
|
||||
<CatalogPurchaseWidgetView />
|
||||
</Column>
|
||||
<CatalogPurchaseWidgetView />
|
||||
</Column>
|
||||
</Grid>
|
||||
</>
|
||||
|
@ -79,19 +79,14 @@ export const CatalogSearchView: FC<{}> = props =>
|
||||
{
|
||||
setCurrentPage((new CatalogPage(-1, 'default_3x3', new PageLocalization([], []), offers, false, 1) as ICatalogPage));
|
||||
setSearchResult(new SearchResult(search, offers, nodes.filter(node => (node.isVisible))));
|
||||
setActiveNodes([]);
|
||||
setActiveNodes(prevValue => prevValue.slice(0, 1));
|
||||
});
|
||||
}, [ currentOffers, currentType, rootNode, setCurrentPage, setSearchResult, setActiveNodes ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if(!searchValue)
|
||||
{
|
||||
processSearch(searchValue);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(!searchValue) return;
|
||||
|
||||
const timeout = setTimeout(() => processSearch(searchValue), 300);
|
||||
|
||||
return () =>
|
||||
@ -102,7 +97,7 @@ export const CatalogSearchView: FC<{}> = props =>
|
||||
|
||||
return (
|
||||
<Flex gap={ 1 }>
|
||||
<input type="text" className="form-control form-control-sm" placeholder={ LocalizeText('generic.search') } value={ searchValue } onChange={ event => setSearchValue(event.target.value) } />
|
||||
<input type="text" className="form-control form-control-sm" placeholder={ LocalizeText('generic.search') } value={ searchValue } onChange={ event => setSearchValue(event.target.value) } onKeyDown={ event => (event.code === 'Enter') && processSearch(searchValue) } />
|
||||
<Button variant="primary" size="sm">
|
||||
<FontAwesomeIcon icon="search" />
|
||||
</Button>
|
||||
|
@ -13,4 +13,5 @@ export class CatalogEvent extends NitroEvent
|
||||
public static PURCHASE_APPROVED: string = 'CE_PURCHASE_APPROVED';
|
||||
public static INIT_GIFT: string = 'CE_INIT_GIFT';
|
||||
public static CATALOG_RESET: string = 'CE_RESET';
|
||||
public static CATALOG_INVISIBLE_PAGE_VISITED: string = 'CE_CATALOG_INVISIBLE_PAGE_VISITED';
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user