Update catalog

This commit is contained in:
Bill 2021-09-29 22:31:31 -04:00
parent 33aac67bbe
commit eadb3d5d1e
24 changed files with 341 additions and 282 deletions

View File

@ -4,7 +4,7 @@ import { AddEventLinkTracker, GetRoomEngine, LocalizeText, RemoveLinkEventTracke
import { CatalogEvent } from '../../events'; 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 { NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../layout'; import { NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView, NitroLayoutGrid, NitroLayoutGridColumn } from '../../layout';
import { CatalogMessageHandler } from './CatalogMessageHandler'; import { CatalogMessageHandler } from './CatalogMessageHandler';
import { CatalogMode, CatalogViewProps } from './CatalogView.types'; import { CatalogMode, CatalogViewProps } from './CatalogView.types';
import { BuildCatalogPageTree } from './common/CatalogUtilities'; import { BuildCatalogPageTree } from './common/CatalogUtilities';
@ -184,7 +184,7 @@ export const CatalogView: FC<CatalogViewProps> = props =>
}, []); }, []);
const currentNavigationPage = ((searchResult && searchResult.page) || currentTab); const currentNavigationPage = ((searchResult && searchResult.page) || currentTab);
const navigationHidden = (pageParser && pageParser.frontPageItems.length); const navigationHidden = !!(pageParser && pageParser.frontPageItems.length);
return ( return (
<CatalogContextProvider value={ { catalogState, dispatchCatalogState } }> <CatalogContextProvider value={ { catalogState, dispatchCatalogState } }>
@ -203,15 +203,15 @@ export const CatalogView: FC<CatalogViewProps> = props =>
}) } }) }
</NitroCardTabsView> </NitroCardTabsView>
<NitroCardContentView> <NitroCardContentView>
<div className="row h-100"> <NitroLayoutGrid>
{ currentNavigationPage && !navigationHidden && { currentNavigationPage && !navigationHidden &&
<div className="col-3 h-100"> <NitroLayoutGridColumn size={ 3 }>
<CatalogNavigationView page={ currentNavigationPage } pendingTree={ pendingTree } setPendingTree={ setPendingTree } /> <CatalogNavigationView page={ currentNavigationPage } pendingTree={ pendingTree } setPendingTree={ setPendingTree } />
</div> } </NitroLayoutGridColumn> }
<div className="col h-100"> <NitroLayoutGridColumn size={ (navigationHidden ? 12 : 9) }>
<CatalogPageView roomPreviewer={ roomPreviewer } /> <CatalogPageView roomPreviewer={ roomPreviewer } />
</div> </NitroLayoutGridColumn>
</div> </NitroLayoutGrid>
</NitroCardContentView> </NitroCardContentView>
</NitroCardView> } </NitroCardView> }
<CatalogGiftView /> <CatalogGiftView />

View File

@ -1,4 +1,4 @@
.nitro-catalog-navigation-grid { .nitro-catalog-navigation-grid-container {
border-radius: 0.25rem; border-radius: 0.25rem;
border-color: #B6BEC5 !important; border-color: #B6BEC5 !important;
background-color: #CDD3D9; background-color: #CDD3D9;

View File

@ -1,6 +1,6 @@
import { INodeData } from '@nitrots/nitro-renderer'; import { INodeData } from '@nitrots/nitro-renderer';
import { FC, useEffect } from 'react'; import { FC, useEffect } from 'react';
import { NitroCardGridView } from '../../../../layout'; import { NitroCardGridView, NitroLayoutFlexColumn } from '../../../../layout';
import { CatalogSearchView } from '../search/CatalogSearchView'; import { CatalogSearchView } from '../search/CatalogSearchView';
import { CatalogNavigationViewProps } from './CatalogNavigationView.types'; import { CatalogNavigationViewProps } from './CatalogNavigationView.types';
import { CatalogNavigationSetView } from './set/CatalogNavigationSetView'; import { CatalogNavigationSetView } from './set/CatalogNavigationSetView';
@ -24,15 +24,13 @@ export const CatalogNavigationView: FC<CatalogNavigationViewProps> = props =>
}, [ page ]); }, [ page ]);
return ( return (
<div className="row h-100"> <NitroLayoutFlexColumn gap={ 2 } overflow="auto">
<div className="d-flex flex-column col gap-2 h-100">
<CatalogSearchView /> <CatalogSearchView />
<div className="d-flex flex-column overflow-hidden nitro-catalog-navigation-grid p-1 h-100"> <NitroLayoutFlexColumn className="nitro-catalog-navigation-grid-container p-1" overflow="hidden">
<NitroCardGridView columns={ 1 } gap={ 1 }> <NitroCardGridView columns={ 1 } gap={ 1 }>
<CatalogNavigationSetView page={ page } isFirstSet={ true } pendingTree={ pendingTree } setPendingTree={ setPendingTree } /> <CatalogNavigationSetView page={ page } isFirstSet={ true } pendingTree={ pendingTree } setPendingTree={ setPendingTree } />
</NitroCardGridView> </NitroCardGridView>
</div> </NitroLayoutFlexColumn>
</div> </NitroLayoutFlexColumn>
</div>
); );
} }

View File

@ -1,4 +1,5 @@
import { FC } from 'react'; import { FC } from 'react';
import { NitroLayoutFlexColumn } from '../../../../layout';
import { GetCatalogPageImage, GetCatalogPageText } from '../../common/CatalogUtilities'; import { GetCatalogPageImage, GetCatalogPageText } from '../../common/CatalogUtilities';
import { CatalogPageDetailsViewProps } from './CatalogPageDetailsView.types'; import { CatalogPageDetailsViewProps } from './CatalogPageDetailsView.types';
@ -11,9 +12,9 @@ export const CatalogPageDetailsView: FC<CatalogPageDetailsViewProps> = props =>
const imageUrl = GetCatalogPageImage(pageParser, 1); const imageUrl = GetCatalogPageImage(pageParser, 1);
return ( return (
<div className="d-flex flex-column justify-content-center align-items-center overflow-hidden h-100"> <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: GetCatalogPageText(pageParser, 0) } } />
</div> </NitroLayoutFlexColumn>
); );
} }

View File

@ -4,6 +4,8 @@ import { LocalizeText } from '../../../../../../api';
import { InventoryBadgesUpdatedEvent, SetRoomPreviewerStuffDataEvent } from '../../../../../../events'; import { InventoryBadgesUpdatedEvent, SetRoomPreviewerStuffDataEvent } from '../../../../../../events';
import { InventoryBadgesRequestEvent } from '../../../../../../events/inventory/InventoryBadgesRequestEvent'; import { InventoryBadgesRequestEvent } from '../../../../../../events/inventory/InventoryBadgesRequestEvent';
import { dispatchUiEvent, useUiEvent } from '../../../../../../hooks'; import { dispatchUiEvent, useUiEvent } from '../../../../../../hooks';
import { NitroLayoutFlexColumn, NitroLayoutGrid, NitroLayoutGridColumn } from '../../../../../../layout';
import { NitroLayoutBase } from '../../../../../../layout/base';
import { NitroCardGridItemView } from '../../../../../../layout/card/grid/item/NitroCardGridItemView'; import { NitroCardGridItemView } from '../../../../../../layout/card/grid/item/NitroCardGridItemView';
import { NitroCardGridView } from '../../../../../../layout/card/grid/NitroCardGridView'; import { NitroCardGridView } from '../../../../../../layout/card/grid/NitroCardGridView';
import { BadgeImageView } from '../../../../../shared/badge-image/BadgeImageView'; import { BadgeImageView } from '../../../../../shared/badge-image/BadgeImageView';
@ -53,11 +55,11 @@ export const CatalogLayoutBadgeDisplayView: FC<CatalogLayoutBadgeDisplayViewProp
}, [ currentBadge, activeOffer, roomPreviewer ]); }, [ currentBadge, activeOffer, roomPreviewer ]);
return ( return (
<div className="row h-100"> <NitroLayoutGrid>
<div className="d-flex flex-column col-7 gap-2 h-100"> <NitroLayoutGridColumn size={ 7 }>
<CatalogPageOffersView className="flex-shrink-0" offers={ pageParser.offers } /> <CatalogPageOffersView className="flex-shrink-0" offers={ pageParser.offers } />
<div className="d-flex flex-column overflow-hidden"> <NitroLayoutFlexColumn gap={ 1 } overflow="hidden">
<div className="text-black fw-bold">{ LocalizeText('catalog_selectbadge') }</div> <NitroLayoutBase className="flex-shrink-0 fw-bold text-black text-truncate">{ LocalizeText('catalog_selectbadge') }</NitroLayoutBase>
<NitroCardGridView> <NitroCardGridView>
{ badges && (badges.length > 0) && badges.map(code => { badges && (badges.length > 0) && badges.map(code =>
{ {
@ -68,11 +70,11 @@ export const CatalogLayoutBadgeDisplayView: FC<CatalogLayoutBadgeDisplayViewProp
); );
}) } }) }
</NitroCardGridView> </NitroCardGridView>
</div> </NitroLayoutFlexColumn>
</div> </NitroLayoutGridColumn>
<div className="position-relative d-flex flex-column col-5"> <NitroLayoutGridColumn size={ 5 }>
<CatalogProductPreviewView pageParser={ pageParser } activeOffer={ activeOffer } roomPreviewer={ roomPreviewer } extra={ currentBadge } disabled={ !currentBadge } /> <CatalogProductPreviewView pageParser={ pageParser } activeOffer={ activeOffer } roomPreviewer={ roomPreviewer } extra={ currentBadge } disabled={ !currentBadge } />
</div> </NitroLayoutGridColumn>
</div> </NitroLayoutGrid>
); );
} }

View File

@ -1,4 +1,5 @@
import { FC } from 'react'; import { FC } from 'react';
import { NitroLayoutGrid, NitroLayoutGridColumn } from '../../../../../../layout';
import { useCatalogContext } from '../../../../context/CatalogContext'; import { useCatalogContext } from '../../../../context/CatalogContext';
import { CatalogPageOffersView } from '../../offers/CatalogPageOffersView'; import { CatalogPageOffersView } from '../../offers/CatalogPageOffersView';
import { CatalogProductPreviewView } from '../../product-preview/CatalogProductPreviewView'; import { CatalogProductPreviewView } from '../../product-preview/CatalogProductPreviewView';
@ -13,13 +14,13 @@ export const CatalogLayoutDefaultView: FC<CatalogLayoutDefaultViewProps> = props
const product = ((activeOffer && activeOffer.products[0]) || null); const product = ((activeOffer && activeOffer.products[0]) || null);
return ( return (
<div className="row h-100"> <NitroLayoutGrid>
<div className="d-flex flex-column col-7 h-100"> <NitroLayoutGridColumn size={ 7 }>
<CatalogPageOffersView offers={ pageParser.offers } /> <CatalogPageOffersView offers={ pageParser.offers } />
</div> </NitroLayoutGridColumn>
<div className="position-relative d-flex flex-column col-5 gap-2 h-100 overflow-hidden"> <NitroLayoutGridColumn size={ 5 }>
<CatalogProductPreviewView pageParser={ pageParser } activeOffer={ activeOffer } roomPreviewer={ roomPreviewer } /> <CatalogProductPreviewView pageParser={ pageParser } activeOffer={ activeOffer } roomPreviewer={ roomPreviewer } />
</div> </NitroLayoutGridColumn>
</div> </NitroLayoutGrid>
); );
} }

View File

@ -1,9 +1,4 @@
.nitro-catalog-layout-frontpage4 { .nitro-front-page-item {
max-height:600px;
.front-page-item {
position: relative;
border-radius: $border-radius;
background-position: center; background-position: center;
background-repeat: no-repeat; background-repeat: no-repeat;
cursor: pointer; cursor: pointer;
@ -19,5 +14,4 @@
bottom: 0; bottom: 0;
text-shadow: 2px 2px rgba(0, 0, 0, .2); text-shadow: 2px 2px rgba(0, 0, 0, .2);
} }
}
} }

View File

@ -1,9 +1,11 @@
import { FrontPageItem } from '@nitrots/nitro-renderer'; import { FrontPageItem } from '@nitrots/nitro-renderer';
import { FC, useCallback, useMemo } from 'react'; import { FC, useCallback, useMemo } from 'react';
import { CreateLinkEvent, GetConfiguration } from '../../../../../../api'; import { CreateLinkEvent, GetConfiguration } from '../../../../../../api';
import { NitroLayoutGrid, NitroLayoutGridColumn } from '../../../../../../layout';
import { GetCatalogPageText } from '../../../../common/CatalogUtilities'; import { GetCatalogPageText } from '../../../../common/CatalogUtilities';
import { CatalogRedeemVoucherView } from '../../redeem-voucher/CatalogRedeemVoucherView'; import { CatalogRedeemVoucherView } from '../../redeem-voucher/CatalogRedeemVoucherView';
import { CatalogLayoutFrontpage4ViewProps } from './CatalogLayoutFrontpage4View.types'; import { CatalogLayoutFrontpage4ViewProps } from './CatalogLayoutFrontpage4View.types';
import { CatalogLayoutFrontPageItemView } from './item/CatalogLayoutFrontPageItemView';
export const CatalogLayoutFrontpage4View: FC<CatalogLayoutFrontpage4ViewProps> = props => export const CatalogLayoutFrontpage4View: FC<CatalogLayoutFrontpage4ViewProps> = props =>
{ {
@ -31,28 +33,20 @@ export const CatalogLayoutFrontpage4View: FC<CatalogLayoutFrontpage4ViewProps> =
if(!pageParser) return null; if(!pageParser) return null;
return ( return (
<div className="row h-100 nitro-catalog-layout-frontpage4"> <NitroLayoutGrid>
<div className="col-4"> <NitroLayoutGridColumn size={ 4 }>
{ pageParser.frontPageItems[0] && { pageParser.frontPageItems[0] &&
<div className="front-page-item h-100" style={ { backgroundImage: `url('${ imageLibraryUrl }${ pageParser.frontPageItems[0].itemPromoImage }')` }} onClick={ event => selectItem(pageParser.frontPageItems[0]) }> <CatalogLayoutFrontPageItemView item={ pageParser.frontPageItems[0] } onClick={ event => selectItem(pageParser.frontPageItems[0]) } /> }
<div className="front-page-item-caption">{ pageParser.frontPageItems[0].itemName }</div> </NitroLayoutGridColumn>
</div> } <NitroLayoutGridColumn size={ 8 }>
</div>
<div className="d-flex col-8 flex-column">
{ pageParser.frontPageItems[1] && { pageParser.frontPageItems[1] &&
<div className="front-page-item h-100 mb-2" style={ { backgroundImage: `url('${ imageLibraryUrl }${ pageParser.frontPageItems[1].itemPromoImage }')` }} onClick={ event => selectItem(pageParser.frontPageItems[1]) }> <CatalogLayoutFrontPageItemView item={ pageParser.frontPageItems[1] } onClick={ event => selectItem(pageParser.frontPageItems[1]) } /> }
<div className="front-page-item-caption">{ pageParser.frontPageItems[1].itemName }</div>
</div> }
{ pageParser.frontPageItems[2] && { pageParser.frontPageItems[2] &&
<div className="front-page-item h-100 mb-2" style={ { backgroundImage: `url('${ imageLibraryUrl }${ pageParser.frontPageItems[2].itemPromoImage }')` }} onClick={ event => selectItem(pageParser.frontPageItems[2]) }> <CatalogLayoutFrontPageItemView item={ pageParser.frontPageItems[2] } onClick={ event => selectItem(pageParser.frontPageItems[2]) } /> }
<div className="front-page-item-caption">{ pageParser.frontPageItems[2].itemName }</div>
</div> }
{ pageParser.frontPageItems[3] && { pageParser.frontPageItems[3] &&
<div className="front-page-item h-100" style={ { backgroundImage: `url('${ imageLibraryUrl }${ pageParser.frontPageItems[3].itemPromoImage }')` }} onClick={ event => selectItem(pageParser.frontPageItems[3]) }> <CatalogLayoutFrontPageItemView item={ pageParser.frontPageItems[3] } onClick={ event => selectItem(pageParser.frontPageItems[3]) } /> }
<div className="front-page-item-caption">{ pageParser.frontPageItems[3].itemName }</div>
</div> }
<CatalogRedeemVoucherView text={ GetCatalogPageText(pageParser, 1) } /> <CatalogRedeemVoucherView text={ GetCatalogPageText(pageParser, 1) } />
</div> </NitroLayoutGridColumn>
</div> </NitroLayoutGrid>
); );
} }

View File

@ -0,0 +1,35 @@
import { FC, useMemo } from 'react';
import { GetConfiguration } from '../../../../../../../api';
import { NitroLayoutBase } from '../../../../../../../layout/base';
import { CatalogLayoutFrontPageItemViewProps } from './CatalogLayoutFrontPageItemView.types';
export const CatalogLayoutFrontPageItemView: FC<CatalogLayoutFrontPageItemViewProps> = props =>
{
const { item = null, className = '', style = null, ...rest } = props;
const getClassName = useMemo(() =>
{
let newClassName = 'position-relative rounded h-100 nitro-front-page-item';
if(className && className.length) newClassName += ' ' + className;
return newClassName;
}, [ className ]);
const getStyle = useMemo(() =>
{
const newStyle = { ...style };
newStyle.backgroundImage = `url('${ GetConfiguration<string>('image.library.url') }${ item.itemPromoImage }')`;
return newStyle;
}, [ style, item ]);
if(!item) return null;
return (
<NitroLayoutBase className={ getClassName } style={ getStyle } { ...rest }>
<div className="front-page-item-caption">{ item.itemName }</div>
</NitroLayoutBase>
);
}

View File

@ -0,0 +1,7 @@
import { FrontPageItem } from '@nitrots/nitro-renderer';
import { DetailedHTMLProps, HTMLAttributes } from 'react';
export interface CatalogLayoutFrontPageItemViewProps extends DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>
{
item: FrontPageItem;
}

View File

@ -1,25 +1,28 @@
import { CatalogGroupsComposer, StringDataType } from '@nitrots/nitro-renderer'; import { CatalogGroupsComposer, StringDataType } from '@nitrots/nitro-renderer';
import { FC, useEffect, useState } from 'react'; import { FC, useEffect, useMemo, useState } from 'react';
import { LocalizeText } from '../../../../../../api';
import { SetRoomPreviewerStuffDataEvent } from '../../../../../../events'; import { SetRoomPreviewerStuffDataEvent } from '../../../../../../events';
import { dispatchUiEvent } from '../../../../../../hooks'; import { dispatchUiEvent } from '../../../../../../hooks';
import { SendMessageHook } from '../../../../../../hooks/messages'; import { SendMessageHook } from '../../../../../../hooks/messages';
import { BadgeImageView } from '../../../../../shared/badge-image/BadgeImageView'; import { NitroLayoutGrid, NitroLayoutGridColumn } from '../../../../../../layout';
import { GetOfferName } from '../../../../common/CatalogUtilities';
import { useCatalogContext } from '../../../../context/CatalogContext'; import { useCatalogContext } from '../../../../context/CatalogContext';
import { CatalogRoomPreviewerView } from '../../../catalog-room-previewer/CatalogRoomPreviewerView'; import { CatalogSelectGroupView } from '../../../select-group/CatalogSelectGroupView';
import { CatalogPageOffersView } from '../../offers/CatalogPageOffersView'; import { CatalogPageOffersView } from '../../offers/CatalogPageOffersView';
import { CatalogPurchaseView } from '../../purchase/CatalogPurchaseView'; import { CatalogProductPreviewView } from '../../product-preview/CatalogProductPreviewView';
import { CatalogLayoutGuildCustomFurniViewProps } from './CatalogLayoutGuildCustomFurniView.types'; import { CatalogLayoutGuildCustomFurniViewProps } from './CatalogLayoutGuildCustomFurniView.types';
export const CatalogLayouGuildCustomFurniView: FC<CatalogLayoutGuildCustomFurniViewProps> = props => export const CatalogLayouGuildCustomFurniView: FC<CatalogLayoutGuildCustomFurniViewProps> = props =>
{ {
const { roomPreviewer = null, pageParser = null } = props; const { roomPreviewer = null, pageParser = null } = props;
const [ selectedGroupIndex, setSelectedGroupIndex ] = useState<number>(0);
const { catalogState = null } = useCatalogContext(); const { catalogState = null } = useCatalogContext();
const { activeOffer = null, groups = null } = catalogState; const { activeOffer = null, groups = null } = catalogState;
const [ selectedGroupIndex, setSelectedGroupIndex ] = useState<number>(0); const selectedGroup = useMemo(() =>
{
if(!groups || !groups.length) return;
return groups[selectedGroupIndex];
}, [ groups, selectedGroupIndex ]);
useEffect(() => useEffect(() =>
{ {
@ -45,40 +48,16 @@ export const CatalogLayouGuildCustomFurniView: FC<CatalogLayoutGuildCustomFurniV
if(!groups) return null; if(!groups) return null;
const product = ((activeOffer && activeOffer.products[0]) || null);
return ( return (
<div className="row h-100 nitro-catalog-layout-guild-custom-furni"> <NitroLayoutGrid>
<div className="d-flex flex-column col-7 h-100"> <NitroLayoutGridColumn size={ 7 }>
<CatalogPageOffersView offers={ pageParser.offers } /> <CatalogPageOffersView offers={ pageParser.offers } />
</div> </NitroLayoutGridColumn>
{ product && <NitroLayoutGridColumn size={ 5 }>
<div className="col position-relative d-flex flex-column"> <CatalogProductPreviewView pageParser={ pageParser } activeOffer={ activeOffer } roomPreviewer={ roomPreviewer } badgeCode={ ((selectedGroup && selectedGroup.badgeCode) || null) } extra={ groups[selectedGroupIndex] ? groups[selectedGroupIndex].groupId.toString() : '' } disabled={ !(!!groups[selectedGroupIndex]) }>
{ groups[selectedGroupIndex] && <div className="position-absolute" style={{ width: '50px', height: '50px', zIndex: 1 }}> <CatalogSelectGroupView selectedGroupIndex={ selectedGroupIndex } setSelectedGroupIndex={ setSelectedGroupIndex } />
<BadgeImageView badgeCode={ groups[selectedGroupIndex].badgeCode } isGroup={ true } /> </CatalogProductPreviewView>
</div> } </NitroLayoutGridColumn>
<CatalogRoomPreviewerView roomPreviewer={ roomPreviewer } height={ 140 } /> </NitroLayoutGrid>
<div className="fs-6 text-black mt-1 overflow-hidden">{ GetOfferName(activeOffer) }</div>
{ groups.length === 0 && <div className="bg-muted text-center rounded p-1 text-black mt-auto">
{ LocalizeText('catalog.guild_selector.members_only') }
<button className="btn btn-sm btn-primary mt-1">{ LocalizeText('catalog.guild_selector.find_groups') }</button>
</div> }
{ groups.length > 0 && <>
<div className="d-flex mb-2">
<div className="rounded d-flex overflow-hidden me-1 border">
<div className="h-100" style={{ width: '20px', backgroundColor: '#' + groups[selectedGroupIndex].colorA }}></div>
<div className="h-100" style={{ width: '20px', backgroundColor: '#' + groups[selectedGroupIndex].colorB }}></div>
</div>
<select className="form-select form-select-sm" value={ selectedGroupIndex } onChange={ (e) => setSelectedGroupIndex(parseInt(e.target.value)) }>
{ groups.map((group, index) =>
{
return <option key={ index } value={ index }>{ group.groupName }</option>;
}) }
</select>
</div>
<CatalogPurchaseView offer={ activeOffer } pageId={ pageParser.pageId } extra={ groups[selectedGroupIndex] ? groups[selectedGroupIndex].groupId.toString() : '' } />
</> }
</div> }
</div>
); );
} }

View File

@ -1,12 +1,13 @@
import { CatalogGroupsComposer } from '@nitrots/nitro-renderer'; import { CatalogGroupsComposer } from '@nitrots/nitro-renderer';
import { FC, useEffect, useState } from 'react'; import { FC, useEffect, useState } from 'react';
import { LocalizeText } from '../../../../../../api';
import { SendMessageHook } from '../../../../../../hooks/messages'; import { SendMessageHook } from '../../../../../../hooks/messages';
import { BadgeImageView } from '../../../../../shared/badge-image/BadgeImageView'; import { NitroLayoutGrid, NitroLayoutGridColumn } from '../../../../../../layout';
import { NitroLayoutBase } from '../../../../../../layout/base';
import { GetCatalogPageText } from '../../../../common/CatalogUtilities'; import { GetCatalogPageText } from '../../../../common/CatalogUtilities';
import { useCatalogContext } from '../../../../context/CatalogContext'; import { useCatalogContext } from '../../../../context/CatalogContext';
import { CatalogActions } from '../../../../reducers/CatalogReducer'; import { CatalogActions } from '../../../../reducers/CatalogReducer';
import { CatalogPurchaseView } from '../../purchase/CatalogPurchaseView'; import { CatalogSelectGroupView } from '../../../select-group/CatalogSelectGroupView';
import { CatalogProductPreviewView } from '../../product-preview/CatalogProductPreviewView';
import { CatalogLayoutGuildForumViewProps } from './CatalogLayoutGuildForumView.types'; import { CatalogLayoutGuildForumViewProps } from './CatalogLayoutGuildForumView.types';
export const CatalogLayouGuildForumView: FC<CatalogLayoutGuildForumViewProps> = props => export const CatalogLayouGuildForumView: FC<CatalogLayoutGuildForumViewProps> = props =>
@ -36,35 +37,15 @@ export const CatalogLayouGuildForumView: FC<CatalogLayoutGuildForumViewProps> =
}, [ dispatchCatalogState, pageParser ]); }, [ dispatchCatalogState, pageParser ]);
return ( return (
<div className="row h-100 nitro-catalog-layout-guild-custom-furni"> <NitroLayoutGrid>
<div className="col-7 overflow-auto h-100 d-flex flex-column bg-muted rounded py-1 px-2 text-black"> <NitroLayoutGridColumn className="bg-muted rounded p-2 text-black overflow-hidden" size={ 7 }>
<div dangerouslySetInnerHTML={ { __html: GetCatalogPageText(pageParser, 1) } } /> <NitroLayoutBase className="overflow-auto" dangerouslySetInnerHTML={ { __html: GetCatalogPageText(pageParser, 1) } } />
</div> </NitroLayoutGridColumn>
{ product && <div className="col position-relative d-flex flex-column justify-content-center align-items-center"> <NitroLayoutGridColumn size={ 5 }>
{ groups.length === 0 && <div className="bg-muted text-center rounded p-1 text-black"> <CatalogProductPreviewView pageParser={ pageParser } activeOffer={ activeOffer } roomPreviewer={ null } extra={ groups[selectedGroupIndex] ? groups[selectedGroupIndex].groupId.toString() : '' } disabled={ !(!!groups[selectedGroupIndex]) }>
{ LocalizeText('catalog.guild_selector.members_only') } <CatalogSelectGroupView selectedGroupIndex={ selectedGroupIndex } setSelectedGroupIndex={ setSelectedGroupIndex } />
<button className="btn btn-sm btn-primary mt-1">{ LocalizeText('catalog.guild_selector.find_groups') }</button> </CatalogProductPreviewView>
</div> } </NitroLayoutGridColumn>
{ groups[selectedGroupIndex] && <div style={{ width: '50px', height: '50px', zIndex: 1 }}> </NitroLayoutGrid>
<BadgeImageView badgeCode={ groups[selectedGroupIndex].badgeCode } isGroup={ true } />
</div> }
{ groups.length > 0 && <>
<div className="d-flex mb-2 w-100">
<div className="rounded d-flex overflow-hidden me-1 border">
<div className="h-100" style={{ width: '20px', backgroundColor: '#' + groups[selectedGroupIndex].colorA }}></div>
<div className="h-100" style={{ width: '20px', backgroundColor: '#' + groups[selectedGroupIndex].colorB }}></div>
</div>
<select className="form-select form-select-sm" value={ selectedGroupIndex } onChange={ (e) => setSelectedGroupIndex(parseInt(e.target.value)) }>
{ groups.map((group, index) =>
{
return <option key={ index } value={ index }>{ group.groupName }</option>;
}) }
</select>
</div>
{ groups[selectedGroupIndex].hasForum && <div className="bg-primary p-1 text-center rounded">{ LocalizeText('catalog.alert.group_has_forum') }</div> }
<CatalogPurchaseView offer={ activeOffer } pageId={ pageParser.pageId } extra={ groups[selectedGroupIndex] ? groups[selectedGroupIndex].groupId.toString() : '' } />
</> }
</div> }
</div>
); );
} }

View File

@ -1,28 +1,29 @@
import { FC } from 'react'; import { FC } from 'react';
import { CreateLinkEvent, LocalizeText } from '../../../../../../api'; import { CreateLinkEvent, LocalizeText } from '../../../../../../api';
import { NitroLayoutGrid, NitroLayoutGridColumn } from '../../../../../../layout';
import { NitroLayoutBase } from '../../../../../../layout/base';
import { GetCatalogPageImage, GetCatalogPageText } from '../../../../common/CatalogUtilities'; import { GetCatalogPageImage, GetCatalogPageText } from '../../../../common/CatalogUtilities';
import { useCatalogContext } from '../../../../context/CatalogContext';
import { CatalogLayoutGuildFrontpageViewProps } from './CatalogLayoutGuildFrontpageView.types'; import { CatalogLayoutGuildFrontpageViewProps } from './CatalogLayoutGuildFrontpageView.types';
export const CatalogLayouGuildFrontpageView: FC<CatalogLayoutGuildFrontpageViewProps> = props => export const CatalogLayouGuildFrontpageView: FC<CatalogLayoutGuildFrontpageViewProps> = props =>
{ {
const { pageParser = null } = props; const { pageParser = null } = props;
const { catalogState = null, dispatchCatalogState = null } = useCatalogContext();
return ( return (
<div className="row h-100 nitro-catalog-layout-guild-custom-furni"> <NitroLayoutGrid>
<div className="col-7 overflow-auto h-100 d-flex flex-column bg-muted rounded py-1 px-2 text-black"> <NitroLayoutGridColumn className="bg-muted rounded p-2 text-black overflow-hidden" size={ 7 }>
<div dangerouslySetInnerHTML={ { __html: GetCatalogPageText(pageParser, 2) } } /> <NitroLayoutBase dangerouslySetInnerHTML={ { __html: GetCatalogPageText(pageParser, 2) } } />
<div dangerouslySetInnerHTML={ { __html: GetCatalogPageText(pageParser, 0) } } /> <NitroLayoutBase className="overflow-auto" dangerouslySetInnerHTML={ { __html: GetCatalogPageText(pageParser, 0) } } />
<div dangerouslySetInnerHTML={ { __html: GetCatalogPageText(pageParser, 1) } } /> <NitroLayoutBase dangerouslySetInnerHTML={ { __html: GetCatalogPageText(pageParser, 1) } } />
</NitroLayoutGridColumn>
<NitroLayoutGridColumn size={ 5 }>
<div className="d-block mb-2"> <div className="d-block mb-2">
<img alt="" src={ GetCatalogPageImage(pageParser, 1) } /> <img alt="" src={ GetCatalogPageImage(pageParser, 1) } />
</div> </div>
</div>
<div className="col position-relative d-flex flex-column justify-content-center" onClick={ () => CreateLinkEvent('groups/create') }> <div className="col position-relative d-flex flex-column justify-content-center" onClick={ () => CreateLinkEvent('groups/create') }>
<button className="btn btn-sm btn-primary mt-1">{ LocalizeText('catalog.start.guild.purchase.button') }</button> <button className="btn btn-sm btn-primary mt-1">{ LocalizeText('catalog.start.guild.purchase.button') }</button>
</div> </div>
</div> </NitroLayoutGridColumn>
</NitroLayoutGrid>
); );
} }

View File

@ -2,7 +2,8 @@ import { ColorConverter, GetSellablePetPalettesComposer, SellablePetPaletteData
import { FC, useEffect, useMemo, useState } from 'react'; import { FC, useEffect, useMemo, useState } from 'react';
import { GetProductDataForLocalization, LocalizeText } from '../../../../../../api'; import { GetProductDataForLocalization, LocalizeText } from '../../../../../../api';
import { SendMessageHook } from '../../../../../../hooks/messages/message-event'; import { SendMessageHook } from '../../../../../../hooks/messages/message-event';
import { NitroCardGridItemView, NitroCardGridView } from '../../../../../../layout'; import { NitroCardGridItemView, NitroCardGridView, NitroLayoutFlexColumn, NitroLayoutGrid, NitroLayoutGridColumn } from '../../../../../../layout';
import { NitroLayoutBase } from '../../../../../../layout/base';
import { PetImageView } from '../../../../../shared/pet-image/PetImageView'; import { PetImageView } from '../../../../../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';
@ -141,8 +142,8 @@ export const CatalogLayoutPetView: FC<CatalogLayoutPetViewProps> = props =>
if(!activeOffer) return null; if(!activeOffer) return null;
return ( return (
<div className="row h-100"> <NitroLayoutGrid>
<div className="d-flex flex-column col-7 h-100"> <NitroLayoutGridColumn size={ 7 }>
<NitroCardGridView> <NitroCardGridView>
{ !colorsShowing && (sellablePalettes.length > 0) && sellablePalettes.map((palette, index) => { !colorsShowing && (sellablePalettes.length > 0) && sellablePalettes.map((palette, index) =>
{ {
@ -159,22 +160,27 @@ export const CatalogLayoutPetView: FC<CatalogLayoutPetViewProps> = props =>
); );
})} })}
</NitroCardGridView> </NitroCardGridView>
</div> </NitroLayoutGridColumn>
<div className="position-relative d-flex flex-column col-5"> <NitroLayoutGridColumn size={ 5 }>
{ (petIndex === -1) && { (petIndex === -1) &&
<CatalogPageDetailsView pageParser={ pageParser } /> } <CatalogPageDetailsView pageParser={ pageParser } /> }
{ (petIndex >= 0) && { (petIndex >= 0) &&
<> <>
<CatalogRoomPreviewerView roomPreviewer={ roomPreviewer } height={ 140 }> <NitroLayoutFlexColumn overflow="hidden" position="relative">
{ roomPreviewer && <CatalogRoomPreviewerView roomPreviewer={ roomPreviewer } height={ 140 } /> }
{ (petIndex > -1 && petIndex <= 7) && { (petIndex > -1 && petIndex <= 7) &&
<NitroLayoutBase className="start-2 bottom-2" position="absolute">
<button type="button" className= { 'btn btn-primary btn-sm color-button ' + (colorsShowing ? 'active ' : '') } onClick={ event => setColorsShowing(!colorsShowing) }> <button type="button" className= { 'btn btn-primary btn-sm color-button ' + (colorsShowing ? 'active ' : '') } onClick={ event => setColorsShowing(!colorsShowing) }>
<i className="fas fa-fill-drip" /> <i className="fas fa-fill-drip" />
</button> } </button>
</CatalogRoomPreviewerView> </NitroLayoutBase> }
<div className="fs-6 text-black mt-1 overflow-hidden">{ petBreedName }</div> </NitroLayoutFlexColumn>
<NitroLayoutFlexColumn className="flex-grow-1" gap={ 2 }>
<NitroLayoutBase className="flex-grow-1 text-black text-truncate">{ petBreedName }</NitroLayoutBase>
<CatalogLayoutPetPurchaseView offer={ activeOffer } pageId={ pageParser.pageId } extra={ petPurchaseString } /> <CatalogLayoutPetPurchaseView offer={ activeOffer } pageId={ pageParser.pageId } extra={ petPurchaseString } />
</NitroLayoutFlexColumn>
</> } </> }
</div> </NitroLayoutGridColumn>
</div> </NitroLayoutGrid>
); );
} }

View File

@ -1,4 +1,6 @@
import { FC } from 'react'; import { FC } from 'react';
import { NitroLayoutFlex, NitroLayoutFlexColumn, NitroLayoutGrid, NitroLayoutGridColumn } from '../../../../../../layout';
import { NitroLayoutBase } from '../../../../../../layout/base';
import { GetCatalogPageImage, GetCatalogPageText } from '../../../../common/CatalogUtilities'; import { GetCatalogPageImage, GetCatalogPageText } from '../../../../common/CatalogUtilities';
import { CatalogLayoutPets3ViewProps } from './CatalogLayoutPets3View.types'; import { CatalogLayoutPets3ViewProps } from './CatalogLayoutPets3View.types';
@ -9,21 +11,19 @@ export const CatalogLayoutPets3View: FC<CatalogLayoutPets3ViewProps> = props =>
const imageUrl = GetCatalogPageImage(pageParser, 1); const imageUrl = GetCatalogPageImage(pageParser, 1);
return ( return (
<div className="row h-100"> <NitroLayoutGrid>
<div className="d-flex flex-column col-12 h-100"> <NitroLayoutGridColumn className="bg-muted rounded text-black p-2" overflow="hidden" size={ 12 }>
<div className="d-flex flex-column bg-muted rounded text-black gap-2 p-2 h-100"> <NitroLayoutFlex className="align-items-center" gap={ 2 }>
<div className="d-flex flex-row align-items-center gap-2">
{ imageUrl && <img alt="" src={ GetCatalogPageImage(pageParser, 1) } /> } { imageUrl && <img alt="" src={ GetCatalogPageImage(pageParser, 1) } /> }
<div className="fs-5" dangerouslySetInnerHTML={ { __html: GetCatalogPageText(pageParser, 1) } } /> <NitroLayoutBase className="fs-5" dangerouslySetInnerHTML={ { __html: GetCatalogPageText(pageParser, 1) } } />
</div> </NitroLayoutFlex>
<div className="d-flex flex-column align-items-center flex-grow-1 overflow-auto"> <NitroLayoutFlexColumn className="align-items-center flex-grow-1" overflow="auto">
<div dangerouslySetInnerHTML={ { __html: GetCatalogPageText(pageParser, 2) } } /> <NitroLayoutBase dangerouslySetInnerHTML={ { __html: GetCatalogPageText(pageParser, 2) } } />
</div> </NitroLayoutFlexColumn>
<div className="d-flex flex-row align-items-center"> <NitroLayoutFlex className="align-items-center">
<div className="fw-bold" dangerouslySetInnerHTML={ { __html: GetCatalogPageText(pageParser, 3) } } /> <NitroLayoutBase className="fw-bold" dangerouslySetInnerHTML={ { __html: GetCatalogPageText(pageParser, 3) } } />
</div> </NitroLayoutFlex>
</div> </NitroLayoutGridColumn>
</div> </NitroLayoutGrid>
</div>
); );
} }

View File

@ -1,5 +1,5 @@
import { FC } from 'react'; import { FC } from 'react';
import { NitroCardGridView } from '../../../../../../layout'; import { NitroCardGridView, NitroLayoutGrid, NitroLayoutGridColumn } from '../../../../../../layout';
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 { CatalogProductView } from '../../product/CatalogProductView';
@ -13,19 +13,19 @@ export const CatalogLayoutSingleBundleView: FC<CatalogLayoutSingleBundleViewProp
const { activeOffer = null } = catalogState; const { activeOffer = null } = catalogState;
return ( return (
<div className="row h-100"> <NitroLayoutGrid>
<div className="d-flex flex-column col-7 h-100"> <NitroLayoutGridColumn size={ 7 }>
<NitroCardGridView> <NitroCardGridView>
{ activeOffer && activeOffer.products && (activeOffer.products.length > 0) && activeOffer.products.map((product, index) => { activeOffer && activeOffer.products && (activeOffer.products.length > 0) && activeOffer.products.map((product, index) =>
{ {
return <CatalogProductView key={ index } isActive={ false } product={ product } /> return <CatalogProductView key={ index } isActive={ false } product={ product } />
}) } }) }
</NitroCardGridView> </NitroCardGridView>
</div> </NitroLayoutGridColumn>
<div className="position-relative d-flex flex-column col-5"> <NitroLayoutGridColumn size={ 5 }>
<CatalogPageDetailsView pageParser={ pageParser } /> <CatalogPageDetailsView pageParser={ pageParser } />
{ activeOffer && <CatalogPurchaseView offer={ activeOffer } pageId={ pageParser.pageId } /> } { activeOffer && <CatalogPurchaseView offer={ activeOffer } pageId={ pageParser.pageId } /> }
</div> </NitroLayoutGridColumn>
</div> </NitroLayoutGrid>
); );
} }

View File

@ -1,6 +1,7 @@
import { CatalogPageMessageOfferData, IFurnitureData } from '@nitrots/nitro-renderer'; 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 { GetSessionDataManager, LocalizeText } from '../../../../../../api';
import { NitroLayoutGrid, NitroLayoutGridColumn } from '../../../../../../layout';
import { ProductTypeEnum } from '../../../../common/ProductTypeEnum'; import { ProductTypeEnum } from '../../../../common/ProductTypeEnum';
import { useCatalogContext } from '../../../../context/CatalogContext'; import { useCatalogContext } from '../../../../context/CatalogContext';
import { CatalogPageOffersView } from '../../offers/CatalogPageOffersView'; import { CatalogPageOffersView } from '../../offers/CatalogPageOffersView';
@ -10,10 +11,10 @@ import { CatalogLayoutSpacesViewProps } from './CatalogLayoutSpacesView.types';
export const CatalogLayoutSpacesView: FC<CatalogLayoutSpacesViewProps> = props => export const CatalogLayoutSpacesView: FC<CatalogLayoutSpacesViewProps> = props =>
{ {
const { roomPreviewer = null, pageParser = null } = props; const { roomPreviewer = null, pageParser = null } = props;
const { catalogState } = useCatalogContext();
const { activeOffer = null } = catalogState;
const [ groups, setGroups ] = useState<CatalogPageMessageOfferData[][]>([]); const [ groups, setGroups ] = useState<CatalogPageMessageOfferData[][]>([]);
const [ activeGroupIndex, setActiveGroupIndex ] = useState(-1); const [ activeGroupIndex, setActiveGroupIndex ] = useState(-1);
const { catalogState } = useCatalogContext();
const { activeOffer = null } = catalogState;
const groupNames = [ 'floors', 'walls', 'views' ]; const groupNames = [ 'floors', 'walls', 'views' ];
@ -66,8 +67,8 @@ export const CatalogLayoutSpacesView: FC<CatalogLayoutSpacesViewProps> = props =
const product = ((activeOffer && activeOffer.products[0]) || null); const product = ((activeOffer && activeOffer.products[0]) || null);
return ( return (
<div className="row h-100"> <NitroLayoutGrid>
<div className="d-flex flex-column col-7 gap-2 h-100"> <NitroLayoutGridColumn size={ 7 }>
<div className="btn-group w-100"> <div className="btn-group w-100">
{ groupNames.map((name, index) => { groupNames.map((name, index) =>
{ {
@ -75,10 +76,10 @@ export const CatalogLayoutSpacesView: FC<CatalogLayoutSpacesViewProps> = props =
})} })}
</div> </div>
<CatalogPageOffersView offers={ groups[activeGroupIndex] } /> <CatalogPageOffersView offers={ groups[activeGroupIndex] } />
</div> </NitroLayoutGridColumn>
<div className="position-relative d-flex flex-column col-5"> <NitroLayoutGridColumn size={ 5 }>
<CatalogProductPreviewView pageParser={ pageParser } activeOffer={ activeOffer } roomPreviewer={ roomPreviewer } /> <CatalogProductPreviewView pageParser={ pageParser } activeOffer={ activeOffer } roomPreviewer={ roomPreviewer } />
</div> </NitroLayoutGridColumn>
</div> </NitroLayoutGrid>
); );
} }

View File

@ -1,4 +1,5 @@
import { FC, useState } from 'react'; import { FC, useState } from 'react';
import { NitroLayoutGrid, NitroLayoutGridColumn } from '../../../../../../layout';
import { useCatalogContext } from '../../../../context/CatalogContext'; import { useCatalogContext } from '../../../../context/CatalogContext';
import { CatalogPageOffersView } from '../../offers/CatalogPageOffersView'; import { CatalogPageOffersView } from '../../offers/CatalogPageOffersView';
import { CatalogProductPreviewView } from '../../product-preview/CatalogProductPreviewView'; import { CatalogProductPreviewView } from '../../product-preview/CatalogProductPreviewView';
@ -14,14 +15,14 @@ export const CatalogLayoutTrophiesView: FC<CatalogLayoutTrophiesViewProps> = pro
const product = ((activeOffer && activeOffer.products[0]) || null); const product = ((activeOffer && activeOffer.products[0]) || null);
return ( return (
<div className="row h-100"> <NitroLayoutGrid>
<div className="d-flex flex-column col-7 gap-2 h-100"> <NitroLayoutGridColumn size={ 7 }>
<CatalogPageOffersView offers={ pageParser.offers } /> <CatalogPageOffersView offers={ pageParser.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) } />
</div> </NitroLayoutGridColumn>
<div className="position-relative d-flex flex-column col-5"> <NitroLayoutGridColumn size={ 5 }>
<CatalogProductPreviewView pageParser={ pageParser } activeOffer={ activeOffer } roomPreviewer={ roomPreviewer } extra={ trophyText } /> <CatalogProductPreviewView pageParser={ pageParser } activeOffer={ activeOffer } roomPreviewer={ roomPreviewer } extra={ trophyText } />
</div> </NitroLayoutGridColumn>
</div> </NitroLayoutGrid>
); );
} }

View File

@ -4,6 +4,8 @@ import { LocalizeText } from '../../../../../../api';
import { CatalogEvent } from '../../../../../../events/catalog/CatalogEvent'; import { CatalogEvent } from '../../../../../../events/catalog/CatalogEvent';
import { useUiEvent } from '../../../../../../hooks'; import { useUiEvent } from '../../../../../../hooks';
import { SendMessageHook } from '../../../../../../hooks/messages/message-event'; import { SendMessageHook } from '../../../../../../hooks/messages/message-event';
import { NitroLayoutFlexColumn, NitroLayoutGrid, NitroLayoutGridColumn } from '../../../../../../layout';
import { NitroLayoutBase } from '../../../../../../layout/base';
import { NitroCardGridItemView } from '../../../../../../layout/card/grid/item/NitroCardGridItemView'; import { NitroCardGridItemView } from '../../../../../../layout/card/grid/item/NitroCardGridItemView';
import { NitroCardGridView } from '../../../../../../layout/card/grid/NitroCardGridView'; import { NitroCardGridView } from '../../../../../../layout/card/grid/NitroCardGridView';
import { LoadingSpinnerView } from '../../../../../../layout/loading-spinner/LoadingSpinnerView'; import { LoadingSpinnerView } from '../../../../../../layout/loading-spinner/LoadingSpinnerView';
@ -142,15 +144,14 @@ export const CatalogLayoutVipBuyView: FC<CatalogLayoutVipBuyViewProps> = props =
}, [ pendingOffer, purchaseState, purchaseSubscription ]); }, [ pendingOffer, purchaseState, purchaseSubscription ]);
return ( return (
<> <NitroLayoutGrid>
<div className="row h-100 nitro-catalog-layout-vip-buy"> <NitroLayoutGridColumn size={ 7 }>
<div className="col-6 h-100">
<NitroCardGridView columns={ 1 } className="vip-buy-grid"> <NitroCardGridView columns={ 1 } className="vip-buy-grid">
{ clubOffers && (clubOffers.length > 0) && clubOffers.map((offer, index) => { clubOffers && (clubOffers.length > 0) && clubOffers.map((offer, index) =>
{ {
return ( return (
<NitroCardGridItemView key={ index } className="justify-content-between py-1 px-2 text-black" itemActive={ pendingOffer === offer } onClick={ () => setOffer(offer) }> <NitroCardGridItemView key={ index } className="justify-content-between py-1 px-2 text-black" itemActive={ pendingOffer === offer } onClick={ () => setOffer(offer) }>
<div className="hc-banner"></div> <i className="icon icon-hc-banner" />
<div className="fw-bold"> <div className="fw-bold">
<div className="text-end">{ getOfferText(offer) }</div> <div className="text-end">{ getOfferText(offer) }</div>
<div className="d-flex gap-2 justify-content-end"> <div className="d-flex gap-2 justify-content-end">
@ -170,12 +171,12 @@ export const CatalogLayoutVipBuyView: FC<CatalogLayoutVipBuyViewProps> = props =
); );
}) } }) }
</NitroCardGridView> </NitroCardGridView>
</div> </NitroLayoutGridColumn>
<div className="position-relative d-flex flex-column col-6 justify-content-center align-items-center"> <NitroLayoutGridColumn size={ 5 }>
<div className="d-block mb-2"> <NitroLayoutFlexColumn className="justify-content-center align-items-center h-100" overflow="hidden" gap={ 2 }>
<img alt="" src={ GetCatalogPageImage(pageParser, 1) } /> { GetCatalogPageImage(pageParser, 1) && <img className="" alt="" src={ GetCatalogPageImage(pageParser, 1) } /> }
</div> <NitroLayoutBase className="text-center text-black" overflow="auto" dangerouslySetInnerHTML={ { __html: getSubscriptionDetails } } />
<div className="text-center text-black small bg-muted rounded p-1" dangerouslySetInnerHTML={ { __html: getSubscriptionDetails } }></div> </NitroLayoutFlexColumn>
{ pendingOffer && <div className="mt-auto w-100 text-black"> { pendingOffer && <div className="mt-auto w-100 text-black">
<div className="d-flex gap-2 mb-2 align-items-center"> <div className="d-flex gap-2 mb-2 align-items-center">
<div className="w-100"> <div className="w-100">
@ -196,9 +197,8 @@ export const CatalogLayoutVipBuyView: FC<CatalogLayoutVipBuyViewProps> = props =
</div> </div>
</div> </div>
{ getPurchaseButton() } { getPurchaseButton() }
</div>} </div> }
</div> </NitroLayoutGridColumn>
</div> </NitroLayoutGrid>
</>
); );
} }

View File

@ -1,4 +1,7 @@
import { FC } from 'react'; import { FC } from 'react';
import { NitroLayoutFlexColumn } from '../../../../../layout';
import { NitroLayoutBase } from '../../../../../layout/base';
import { BadgeImageView } from '../../../../shared/badge-image/BadgeImageView';
import { LimitedEditionCompletePlateView } from '../../../../shared/limited-edition/complete-plate/LimitedEditionCompletePlateView'; import { LimitedEditionCompletePlateView } from '../../../../shared/limited-edition/complete-plate/LimitedEditionCompletePlateView';
import { GetOfferName } from '../../../common/CatalogUtilities'; import { GetOfferName } from '../../../common/CatalogUtilities';
import { CatalogRoomPreviewerView } from '../../catalog-room-previewer/CatalogRoomPreviewerView'; import { CatalogRoomPreviewerView } from '../../catalog-room-previewer/CatalogRoomPreviewerView';
@ -8,7 +11,7 @@ import { CatalogProductPreviewViewProps } from './CatalogProductPreviewView.type
export const CatalogProductPreviewView: FC<CatalogProductPreviewViewProps> = props => export const CatalogProductPreviewView: FC<CatalogProductPreviewViewProps> = props =>
{ {
const { pageParser = null, activeOffer = null, roomPreviewer = null, extra = '', disabled = false, children = null } = props; const { pageParser = null, activeOffer = null, roomPreviewer = null, badgeCode = null, extra = '', disabled = false, children = null } = props;
const product = ((activeOffer && activeOffer.products[0]) || null); const product = ((activeOffer && activeOffer.products[0]) || null);
@ -16,16 +19,22 @@ export const CatalogProductPreviewView: FC<CatalogProductPreviewViewProps> = pro
return ( return (
<> <>
<div className="position-relative d-flex flex-column overflow-auto h-100"> <NitroLayoutFlexColumn overflow="hidden" position="relative">
<CatalogRoomPreviewerView roomPreviewer={ roomPreviewer } height={ 140 } /> { roomPreviewer && <CatalogRoomPreviewerView roomPreviewer={ roomPreviewer } height={ 140 } /> }
{ product.uniqueLimitedItem && { product.uniqueLimitedItem &&
<LimitedEditionCompletePlateView uniqueLimitedItemsLeft={ product.uniqueLimitedItemsLeft } uniqueLimitedSeriesSize={ product.uniqueLimitedSeriesSize } /> } <NitroLayoutBase className="top-2 end-2" position="absolute">
</div> <LimitedEditionCompletePlateView uniqueLimitedItemsLeft={ product.uniqueLimitedItemsLeft } uniqueLimitedSeriesSize={ product.uniqueLimitedSeriesSize } />
<div className="d-flex flex-column gap-2"> </NitroLayoutBase> }
<div className="flex-grow-1 text-black text-truncate">{ GetOfferName(activeOffer) }</div> { badgeCode && badgeCode.length &&
<NitroLayoutBase className="top-2 end-2" position="absolute">
<BadgeImageView badgeCode={ badgeCode } isGroup={ true } />
</NitroLayoutBase> }
</NitroLayoutFlexColumn>
<NitroLayoutFlexColumn className="flex-grow-1" gap={ 2 }>
<NitroLayoutBase className="flex-grow-1 text-black text-truncate">{ GetOfferName(activeOffer) }</NitroLayoutBase>
{ children } { children }
<CatalogPurchaseView offer={ activeOffer } pageId={ pageParser.pageId } extra={ extra } disabled={ disabled } /> <CatalogPurchaseView offer={ activeOffer } pageId={ pageParser.pageId } extra={ extra } disabled={ disabled } />
</div> </NitroLayoutFlexColumn>
</> </>
); );
} }

View File

@ -5,6 +5,8 @@ export interface CatalogProductPreviewViewProps
pageParser: CatalogPageMessageParser; pageParser: CatalogPageMessageParser;
activeOffer: CatalogPageMessageOfferData; activeOffer: CatalogPageMessageOfferData;
roomPreviewer: RoomPreviewer; roomPreviewer: RoomPreviewer;
badgeCode?: string;
extra?: string; extra?: string;
disabled?: boolean; disabled?: boolean;
} }

View File

@ -39,7 +39,7 @@ export const CatalogRedeemVoucherView: FC<CatalogRedeemVoucherViewProps> = props
CreateMessageHook(VoucherRedeemErrorMessageEvent, onVoucherRedeemErrorMessageEvent); CreateMessageHook(VoucherRedeemErrorMessageEvent, onVoucherRedeemErrorMessageEvent);
return ( return (
<div className="d-flex mt-1"> <div className="d-flex">
<div className="d-flex flex-grow-1 me-1"> <div className="d-flex flex-grow-1 me-1">
<input type="text" className="form-control form-control-sm" placeholder={ text } value={ voucher } onChange={ event => setVoucher(event.target.value) } /> <input type="text" className="form-control form-control-sm" placeholder={ text } value={ voucher } onChange={ event => setVoucher(event.target.value) } />
</div> </div>

View File

@ -0,0 +1,40 @@
import { FC } from 'react';
import { LocalizeText } from '../../../../api';
import { NitroLayoutButton, NitroLayoutFlex } from '../../../../layout';
import { NitroLayoutBase } from '../../../../layout/base';
import { useCatalogContext } from '../../context/CatalogContext';
import { CatalogSelectGroupViewProps } from './CatalogSelectGroupView.types';
export const CatalogSelectGroupView: FC<CatalogSelectGroupViewProps> = props =>
{
const { selectedGroupIndex = -1, setSelectedGroupIndex = null } = props;
const { catalogState = null } = useCatalogContext();
const { groups = null } = catalogState;
if(!groups || !groups.length)
{
return (
<NitroLayoutBase className="flex-grow-1 bg-muted rounded text-black text-center p-1">
{ LocalizeText('catalog.guild_selector.members_only') }
<NitroLayoutButton className="mt-1" variant="primary" size="sm">
{ LocalizeText('catalog.guild_selector.find_groups') }
</NitroLayoutButton>
</NitroLayoutBase>
);
}
return (
<NitroLayoutFlex>
<NitroLayoutFlex className="rounded border me-1" overflow="hidden">
<NitroLayoutBase className="h-100" style={ { width: '20px', backgroundColor: '#' + groups[selectedGroupIndex].colorA } } />
<NitroLayoutBase className="h-100" style={ { width: '20px', backgroundColor: '#' + groups[selectedGroupIndex].colorB } } />
</NitroLayoutFlex>
<select className="form-select form-select-sm" value={ selectedGroupIndex } onChange={ event => setSelectedGroupIndex(parseInt(event.target.value)) }>
{ groups.map((group, index) =>
{
return <option key={ index } value={ index }>{ group.groupName }</option>;
}) }
</select>
</NitroLayoutFlex>
);
}

View File

@ -0,0 +1,7 @@
import { Dispatch, SetStateAction } from 'react';
export interface CatalogSelectGroupViewProps
{
selectedGroupIndex: number;
setSelectedGroupIndex: Dispatch<SetStateAction<number>>;
}