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

View File

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

View File

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

View File

@ -1,4 +1,5 @@
import { FC } from 'react';
import { NitroLayoutFlexColumn } from '../../../../layout';
import { GetCatalogPageImage, GetCatalogPageText } from '../../common/CatalogUtilities';
import { CatalogPageDetailsViewProps } from './CatalogPageDetailsView.types';
@ -11,9 +12,9 @@ export const CatalogPageDetailsView: FC<CatalogPageDetailsViewProps> = props =>
const imageUrl = GetCatalogPageImage(pageParser, 1);
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 } /> }
<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 { InventoryBadgesRequestEvent } from '../../../../../../events/inventory/InventoryBadgesRequestEvent';
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 { NitroCardGridView } from '../../../../../../layout/card/grid/NitroCardGridView';
import { BadgeImageView } from '../../../../../shared/badge-image/BadgeImageView';
@ -53,11 +55,11 @@ export const CatalogLayoutBadgeDisplayView: FC<CatalogLayoutBadgeDisplayViewProp
}, [ currentBadge, activeOffer, roomPreviewer ]);
return (
<div className="row h-100">
<div className="d-flex flex-column col-7 gap-2 h-100">
<NitroLayoutGrid>
<NitroLayoutGridColumn size={ 7 }>
<CatalogPageOffersView className="flex-shrink-0" offers={ pageParser.offers } />
<div className="d-flex flex-column overflow-hidden">
<div className="text-black fw-bold">{ LocalizeText('catalog_selectbadge') }</div>
<NitroLayoutFlexColumn gap={ 1 } overflow="hidden">
<NitroLayoutBase className="flex-shrink-0 fw-bold text-black text-truncate">{ LocalizeText('catalog_selectbadge') }</NitroLayoutBase>
<NitroCardGridView>
{ badges && (badges.length > 0) && badges.map(code =>
{
@ -68,11 +70,11 @@ export const CatalogLayoutBadgeDisplayView: FC<CatalogLayoutBadgeDisplayViewProp
);
}) }
</NitroCardGridView>
</div>
</div>
<div className="position-relative d-flex flex-column col-5">
</NitroLayoutFlexColumn>
</NitroLayoutGridColumn>
<NitroLayoutGridColumn size={ 5 }>
<CatalogProductPreviewView pageParser={ pageParser } activeOffer={ activeOffer } roomPreviewer={ roomPreviewer } extra={ currentBadge } disabled={ !currentBadge } />
</div>
</div>
</NitroLayoutGridColumn>
</NitroLayoutGrid>
);
}

View File

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

View File

@ -1,23 +1,17 @@
.nitro-catalog-layout-frontpage4 {
max-height:600px;
.nitro-front-page-item {
background-position: center;
background-repeat: no-repeat;
cursor: pointer;
.front-page-item {
position: relative;
border-radius: $border-radius;
background-position: center;
background-repeat: no-repeat;
cursor: pointer;
.front-page-item-caption {
position: absolute;
background: rgba(0, 0, 0, .5);
color: #fff;
font-size: 16px;
border-radius: 5px;
margin: 10px;
padding: 5px 15px;
bottom: 0;
text-shadow: 2px 2px rgba(0, 0, 0, .2);
}
.front-page-item-caption {
position: absolute;
background: rgba(0, 0, 0, .5);
color: #fff;
font-size: 16px;
border-radius: 5px;
margin: 10px;
padding: 5px 15px;
bottom: 0;
text-shadow: 2px 2px rgba(0, 0, 0, .2);
}
}

View File

@ -1,9 +1,11 @@
import { FrontPageItem } from '@nitrots/nitro-renderer';
import { FC, useCallback, useMemo } from 'react';
import { CreateLinkEvent, GetConfiguration } from '../../../../../../api';
import { NitroLayoutGrid, NitroLayoutGridColumn } from '../../../../../../layout';
import { GetCatalogPageText } from '../../../../common/CatalogUtilities';
import { CatalogRedeemVoucherView } from '../../redeem-voucher/CatalogRedeemVoucherView';
import { CatalogLayoutFrontpage4ViewProps } from './CatalogLayoutFrontpage4View.types';
import { CatalogLayoutFrontPageItemView } from './item/CatalogLayoutFrontPageItemView';
export const CatalogLayoutFrontpage4View: FC<CatalogLayoutFrontpage4ViewProps> = props =>
{
@ -31,28 +33,20 @@ export const CatalogLayoutFrontpage4View: FC<CatalogLayoutFrontpage4ViewProps> =
if(!pageParser) return null;
return (
<div className="row h-100 nitro-catalog-layout-frontpage4">
<div className="col-4">
<NitroLayoutGrid>
<NitroLayoutGridColumn size={ 4 }>
{ pageParser.frontPageItems[0] &&
<div className="front-page-item h-100" style={ { backgroundImage: `url('${ imageLibraryUrl }${ pageParser.frontPageItems[0].itemPromoImage }')` }} onClick={ event => selectItem(pageParser.frontPageItems[0]) }>
<div className="front-page-item-caption">{ pageParser.frontPageItems[0].itemName }</div>
</div> }
</div>
<div className="d-flex col-8 flex-column">
<CatalogLayoutFrontPageItemView item={ pageParser.frontPageItems[0] } onClick={ event => selectItem(pageParser.frontPageItems[0]) } /> }
</NitroLayoutGridColumn>
<NitroLayoutGridColumn size={ 8 }>
{ 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]) }>
<div className="front-page-item-caption">{ pageParser.frontPageItems[1].itemName }</div>
</div> }
<CatalogLayoutFrontPageItemView item={ pageParser.frontPageItems[1] } onClick={ event => selectItem(pageParser.frontPageItems[1]) } /> }
{ 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]) }>
<div className="front-page-item-caption">{ pageParser.frontPageItems[2].itemName }</div>
</div> }
<CatalogLayoutFrontPageItemView item={ pageParser.frontPageItems[2] } onClick={ event => selectItem(pageParser.frontPageItems[2]) } /> }
{ pageParser.frontPageItems[3] &&
<div className="front-page-item h-100" style={ { backgroundImage: `url('${ imageLibraryUrl }${ pageParser.frontPageItems[3].itemPromoImage }')` }} onClick={ event => selectItem(pageParser.frontPageItems[3]) }>
<div className="front-page-item-caption">{ pageParser.frontPageItems[3].itemName }</div>
</div> }
<CatalogLayoutFrontPageItemView item={ pageParser.frontPageItems[3] } onClick={ event => selectItem(pageParser.frontPageItems[3]) } /> }
<CatalogRedeemVoucherView text={ GetCatalogPageText(pageParser, 1) } />
</div>
</div>
</NitroLayoutGridColumn>
</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 { FC, useEffect, useState } from 'react';
import { LocalizeText } from '../../../../../../api';
import { FC, useEffect, useMemo, useState } from 'react';
import { SetRoomPreviewerStuffDataEvent } from '../../../../../../events';
import { dispatchUiEvent } from '../../../../../../hooks';
import { SendMessageHook } from '../../../../../../hooks/messages';
import { BadgeImageView } from '../../../../../shared/badge-image/BadgeImageView';
import { GetOfferName } from '../../../../common/CatalogUtilities';
import { NitroLayoutGrid, NitroLayoutGridColumn } from '../../../../../../layout';
import { useCatalogContext } from '../../../../context/CatalogContext';
import { CatalogRoomPreviewerView } from '../../../catalog-room-previewer/CatalogRoomPreviewerView';
import { CatalogSelectGroupView } from '../../../select-group/CatalogSelectGroupView';
import { CatalogPageOffersView } from '../../offers/CatalogPageOffersView';
import { CatalogPurchaseView } from '../../purchase/CatalogPurchaseView';
import { CatalogProductPreviewView } from '../../product-preview/CatalogProductPreviewView';
import { CatalogLayoutGuildCustomFurniViewProps } from './CatalogLayoutGuildCustomFurniView.types';
export const CatalogLayouGuildCustomFurniView: FC<CatalogLayoutGuildCustomFurniViewProps> = props =>
{
const { roomPreviewer = null, pageParser = null } = props;
const [ selectedGroupIndex, setSelectedGroupIndex ] = useState<number>(0);
const { catalogState = null } = useCatalogContext();
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(() =>
{
@ -44,41 +47,17 @@ export const CatalogLayouGuildCustomFurniView: FC<CatalogLayoutGuildCustomFurniV
}, [ groups, selectedGroupIndex, activeOffer ]);
if(!groups) return null;
const product = ((activeOffer && activeOffer.products[0]) || null);
return (
<div className="row h-100 nitro-catalog-layout-guild-custom-furni">
<div className="d-flex flex-column col-7 h-100">
<NitroLayoutGrid>
<NitroLayoutGridColumn size={ 7 }>
<CatalogPageOffersView offers={ pageParser.offers } />
</div>
{ product &&
<div className="col position-relative d-flex flex-column">
{ groups[selectedGroupIndex] && <div className="position-absolute" style={{ width: '50px', height: '50px', zIndex: 1 }}>
<BadgeImageView badgeCode={ groups[selectedGroupIndex].badgeCode } isGroup={ true } />
</div> }
<CatalogRoomPreviewerView roomPreviewer={ roomPreviewer } height={ 140 } />
<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>
);
</NitroLayoutGridColumn>
<NitroLayoutGridColumn size={ 5 }>
<CatalogProductPreviewView pageParser={ pageParser } activeOffer={ activeOffer } roomPreviewer={ roomPreviewer } badgeCode={ ((selectedGroup && selectedGroup.badgeCode) || null) } extra={ groups[selectedGroupIndex] ? groups[selectedGroupIndex].groupId.toString() : '' } disabled={ !(!!groups[selectedGroupIndex]) }>
<CatalogSelectGroupView selectedGroupIndex={ selectedGroupIndex } setSelectedGroupIndex={ setSelectedGroupIndex } />
</CatalogProductPreviewView>
</NitroLayoutGridColumn>
</NitroLayoutGrid>
);
}

View File

@ -1,12 +1,13 @@
import { CatalogGroupsComposer } from '@nitrots/nitro-renderer';
import { FC, useEffect, useState } from 'react';
import { LocalizeText } from '../../../../../../api';
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 { useCatalogContext } from '../../../../context/CatalogContext';
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';
export const CatalogLayouGuildForumView: FC<CatalogLayoutGuildForumViewProps> = props =>
@ -36,35 +37,15 @@ export const CatalogLayouGuildForumView: FC<CatalogLayoutGuildForumViewProps> =
}, [ dispatchCatalogState, pageParser ]);
return (
<div className="row h-100 nitro-catalog-layout-guild-custom-furni">
<div className="col-7 overflow-auto h-100 d-flex flex-column bg-muted rounded py-1 px-2 text-black">
<div dangerouslySetInnerHTML={ { __html: GetCatalogPageText(pageParser, 1) } } />
</div>
{ product && <div className="col position-relative d-flex flex-column justify-content-center align-items-center">
{ groups.length === 0 && <div className="bg-muted text-center rounded p-1 text-black">
{ LocalizeText('catalog.guild_selector.members_only') }
<button className="btn btn-sm btn-primary mt-1">{ LocalizeText('catalog.guild_selector.find_groups') }</button>
</div> }
{ groups[selectedGroupIndex] && <div style={{ width: '50px', height: '50px', zIndex: 1 }}>
<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>
);
<NitroLayoutGrid>
<NitroLayoutGridColumn className="bg-muted rounded p-2 text-black overflow-hidden" size={ 7 }>
<NitroLayoutBase className="overflow-auto" dangerouslySetInnerHTML={ { __html: GetCatalogPageText(pageParser, 1) } } />
</NitroLayoutGridColumn>
<NitroLayoutGridColumn size={ 5 }>
<CatalogProductPreviewView pageParser={ pageParser } activeOffer={ activeOffer } roomPreviewer={ null } extra={ groups[selectedGroupIndex] ? groups[selectedGroupIndex].groupId.toString() : '' } disabled={ !(!!groups[selectedGroupIndex]) }>
<CatalogSelectGroupView selectedGroupIndex={ selectedGroupIndex } setSelectedGroupIndex={ setSelectedGroupIndex } />
</CatalogProductPreviewView>
</NitroLayoutGridColumn>
</NitroLayoutGrid>
);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,7 @@
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 { GetOfferName } from '../../../common/CatalogUtilities';
import { CatalogRoomPreviewerView } from '../../catalog-room-previewer/CatalogRoomPreviewerView';
@ -8,7 +11,7 @@ import { CatalogProductPreviewViewProps } from './CatalogProductPreviewView.type
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);
@ -16,16 +19,22 @@ export const CatalogProductPreviewView: FC<CatalogProductPreviewViewProps> = pro
return (
<>
<div className="position-relative d-flex flex-column overflow-auto h-100">
<CatalogRoomPreviewerView roomPreviewer={ roomPreviewer } height={ 140 } />
<NitroLayoutFlexColumn overflow="hidden" position="relative">
{ roomPreviewer && <CatalogRoomPreviewerView roomPreviewer={ roomPreviewer } height={ 140 } /> }
{ product.uniqueLimitedItem &&
<LimitedEditionCompletePlateView uniqueLimitedItemsLeft={ product.uniqueLimitedItemsLeft } uniqueLimitedSeriesSize={ product.uniqueLimitedSeriesSize } /> }
</div>
<div className="d-flex flex-column gap-2">
<div className="flex-grow-1 text-black text-truncate">{ GetOfferName(activeOffer) }</div>
<NitroLayoutBase className="top-2 end-2" position="absolute">
<LimitedEditionCompletePlateView uniqueLimitedItemsLeft={ product.uniqueLimitedItemsLeft } uniqueLimitedSeriesSize={ product.uniqueLimitedSeriesSize } />
</NitroLayoutBase> }
{ 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 }
<CatalogPurchaseView offer={ activeOffer } pageId={ pageParser.pageId } extra={ extra } disabled={ disabled } />
</div>
</NitroLayoutFlexColumn>
</>
);
}

View File

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

View File

@ -39,7 +39,7 @@ export const CatalogRedeemVoucherView: FC<CatalogRedeemVoucherViewProps> = props
CreateMessageHook(VoucherRedeemErrorMessageEvent, onVoucherRedeemErrorMessageEvent);
return (
<div className="d-flex mt-1">
<div className="d-flex">
<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) } />
</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>>;
}