Start catalog

This commit is contained in:
Bill 2021-05-05 03:14:54 -04:00
parent 0218743efa
commit 1cf02c53d7
31 changed files with 450 additions and 27 deletions

View File

@ -0,0 +1,6 @@
import { CatalogPageComposer } from 'nitro-renderer';
export function GetCatalogPageComposer(...args: ConstructorParameters<typeof CatalogPageComposer>): CatalogPageComposer
{
return new CatalogPageComposer(...args);
}

View File

@ -1,6 +1,7 @@
@import './avatar-image/AvatarImage';
@import './badge-image/BadgeImage';
@import './catalog/CatalogView';
@import './catalog-icon/CatalogIconView';
@import './hotel-view/HotelView';
@import './inventory/InventoryView';
@import './friend-list/FriendListView';

View File

@ -0,0 +1,8 @@
.catalog-icon-image {
width: 20px;
height: 20px;
min-width: 20px;
min-height: 20px;
background-position: center;
background-repeat: no-repeat;
}

View File

@ -0,0 +1,17 @@
import { FC } from 'react';
import { GetConfiguration } from '../../utils/GetConfiguration';
import { CatalogIconViewProps } from './CatalogIconView.types';
export const CatalogIconView: FC<CatalogIconViewProps> = props =>
{
const { icon = 0 } = props;
function getIconUrl(): string
{
return ((GetConfiguration<string>('catalog.asset.icon.url')).replace('%name%', icon.toString()));
}
const url = `url('${ getIconUrl() }')`;
return <div className="catalog-icon-image" style={ (url && url.length) ? { backgroundImage: url } : {} }></div>;
}

View File

@ -0,0 +1,4 @@
export interface CatalogIconViewProps
{
icon: number;
}

View File

@ -1,10 +1,40 @@
import { FC } from 'react';
import { CatalogPageEvent, CatalogPagesEvent } from 'nitro-renderer';
import { FC, useCallback } from 'react';
import { CreateMessageHook } from '../../hooks/messages/message-event';
import { CatalogMessageHandlerProps } from './CatalogMessageHandler.types';
import { useCatalogContext } from './context/CatalogContext';
import { CatalogActions } from './reducers/CatalogReducer';
export const CatalogMessageHandler: FC<CatalogMessageHandlerProps> = props =>
{
return (
<>
</>
);
const { dispatchCatalogState = null } = useCatalogContext();
const onCatalogPagesEvent = useCallback((event: CatalogPagesEvent) =>
{
const parser = event.getParser();
dispatchCatalogState({
type: CatalogActions.SET_CATALOG_ROOT,
payload: {
root: parser.root
}
});
}, [ dispatchCatalogState ]);
const onCatalogPageEvent = useCallback((event: CatalogPageEvent) =>
{
const parser = event.getParser();
dispatchCatalogState({
type: CatalogActions.SET_CATALOG_PAGE_PARSER,
payload: {
pageParser: parser
}
});
}, [ dispatchCatalogState ]);
CreateMessageHook(CatalogPagesEvent, onCatalogPagesEvent);
CreateMessageHook(CatalogPageEvent, onCatalogPageEvent);
return null;
}

View File

@ -1,3 +1,5 @@
.nitro-catalog {
width: 450px;
width: 600px;
}
@import './views/CatalogViews';

View File

@ -1,14 +1,23 @@
import { FC, useCallback, useState } from 'react';
import { CatalogModeComposer, ICatalogPageData } from 'nitro-renderer';
import { FC, useCallback, useEffect, useReducer, useState } from 'react';
import { CatalogEvent } from '../../events';
import { DraggableWindow } from '../../hooks/draggable-window/DraggableWindow';
import { useUiEvent } from '../../hooks/events/ui/ui-event';
import { SendMessageHook } from '../../hooks/messages/message-event';
import { NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../layout';
import { LocalizeText } from '../../utils/LocalizeText';
import { CatalogMessageHandler } from './CatalogMessageHandler';
import { CatalogViewProps } from './CatalogView.types';
import { CatalogMode, CatalogViewProps } from './CatalogView.types';
import { CatalogContextProvider } from './context/CatalogContext';
import { CatalogReducer, initialCatalog } from './reducers/CatalogReducer';
import { CatalogNavigationView } from './views/navigation/CatalogNavigationView';
import { CatalogPageView } from './views/page/CatalogPageView';
export const CatalogView: FC<CatalogViewProps> = props =>
{
const [ isVisible, setIsVisible ] = useState(false);
const [ currentTab, setCurrentTab ] = useState<ICatalogPageData>(null);
const [ catalogState, dispatchCatalogState ] = useReducer(CatalogReducer, initialCatalog);
const { root = null } = catalogState;
const onCatalogEvent = useCallback((event: CatalogEvent) =>
{
@ -26,27 +35,43 @@ export const CatalogView: FC<CatalogViewProps> = props =>
useUiEvent(CatalogEvent.SHOW_CATALOG, onCatalogEvent);
useUiEvent(CatalogEvent.TOGGLE_CATALOG, onCatalogEvent);
function hideCatalog(): void
useEffect(() =>
{
setIsVisible(false);
}
if(!isVisible) return;
if(!catalogState.root)
{
SendMessageHook(new CatalogModeComposer(CatalogMode.MODE_NORMAL));
}
else
{
setCurrentTab(catalogState.root.children[0]);
}
}, [ isVisible, catalogState.root ]);
return (
<>
<CatalogContextProvider value={ { catalogState, dispatchCatalogState } }>
<CatalogMessageHandler />
{ isVisible && <DraggableWindow handle=".drag-handler">
<div className="nitro-catalog d-flex flex-column bg-primary border border-black shadow rounded">
<div className="drag-handler d-flex justify-content-between align-items-center px-3 pt-3">
<div className="h6 m-0">{ LocalizeText('catalog.title') }</div>
<button type="button" className="close" onClick={ hideCatalog }>
<i className="fas fa-times"></i>
</button>
</div>
<div className="d-flex p-3">
content
</div>
</div>
</DraggableWindow> }
</>
{ isVisible &&
<NitroCardView className="nitro-catalog">
<NitroCardHeaderView headerText={ LocalizeText('catalog.title') } onCloseClick={ event => setIsVisible(false) } />
<NitroCardTabsView>
{ root && root.children.length && root.children.map((page, index) =>
{
return <NitroCardTabsItemView key={ index } tabText={ page.localization } isActive={ (currentTab === page) } onClick={ event => setCurrentTab(page) } />
}) }
</NitroCardTabsView>
<NitroCardContentView>
<div className="row">
<div className="col-3">
<CatalogNavigationView page={ currentTab } />
</div>
<div className="col">
<CatalogPageView />
</div>
</div>
</NitroCardContentView>
</NitroCardView> }
</CatalogContextProvider>
);
}

View File

@ -2,3 +2,8 @@ export interface CatalogViewProps
{
}
export class CatalogMode
{
public static MODE_NORMAL: string = 'NORMAL';
}

View File

@ -0,0 +1,14 @@
import { createContext, FC, useContext } from 'react';
import { CatalogContextProps, ICatalogContext } from './CatalogContext.types';
const CatalogContext = createContext<ICatalogContext>({
catalogState: null,
dispatchCatalogState: null
});
export const CatalogContextProvider: FC<CatalogContextProps> = props =>
{
return <CatalogContext.Provider value={ props.value }>{ props.children }</CatalogContext.Provider>
}
export const useCatalogContext = () => useContext(CatalogContext);

View File

@ -0,0 +1,13 @@
import { Dispatch, ProviderProps } from 'react';
import { ICatalogAction, ICatalogState } from '../reducers/CatalogReducer';
export interface ICatalogContext
{
catalogState: ICatalogState;
dispatchCatalogState: Dispatch<ICatalogAction>;
}
export interface CatalogContextProps extends ProviderProps<ICatalogContext>
{
}

View File

@ -0,0 +1,51 @@
import { ICatalogPageData, ICatalogPageParser } from 'nitro-renderer';
import { Reducer } from 'react';
export interface ICatalogState
{
needsCatalogUpdate: boolean;
root: ICatalogPageData;
pageParser: ICatalogPageParser;
}
export interface ICatalogAction
{
type: string;
payload: {
flag?: boolean;
root?: ICatalogPageData;
pageParser?: ICatalogPageParser;
}
}
export class CatalogActions
{
public static SET_NEEDS_UPDATE: string = 'CA_SET_NEEDS_UPDATE';
public static SET_CATALOG_ROOT: string = 'CA_SET_CATALOG_ROOT';
public static SET_CATALOG_PAGE_PARSER: string = 'CA_SET_CATALOG_PAGE';
}
export const initialCatalog: ICatalogState = {
needsCatalogUpdate: true,
root: null,
pageParser: null
}
export const CatalogReducer: Reducer<ICatalogState, ICatalogAction> = (state, action) =>
{
switch(action.type)
{
case CatalogActions.SET_CATALOG_ROOT: {
const root = (action.payload.root || state.root || null);
return { ...state, root };
}
case CatalogActions.SET_CATALOG_PAGE_PARSER: {
const pageParser = (action.payload.pageParser || state.pageParser || null);
return { ...state, pageParser };
}
default:
return state;
}
}

View File

@ -0,0 +1,6 @@
.nitro-catalog {
}
@import './navigation/CatalogNavigationView';
@import './page/CatalogPageView';

View File

@ -0,0 +1,13 @@
.nitro-catalog-navigation {
border-color: $grid-border-color !important;
background-color: $grid-bg-color !important;
.navigation-container {
height: 275px;
max-height: 275px;
overflow-y: auto;
}
}
@import './item/CatalogNavigationItemView';
@import './set/CatalogNavigationSetView';

View File

@ -0,0 +1,16 @@
import { FC } from 'react';
import { CatalogNavigationViewProps } from './CatalogNavigationView.types';
import { CatalogNavigationSetView } from './set/CatalogNavigationSetView';
export const CatalogNavigationView: FC<CatalogNavigationViewProps> = props =>
{
const { page = null } = props;
return (
<div className="nitro-catalog-navigation border border-2 rounded overflow-hidden">
<div className="navigation-container m-1">
<CatalogNavigationSetView page={ page } isFirstSet={ true } />
</div>
</div>
);
}

View File

@ -0,0 +1,6 @@
import { ICatalogPageData } from 'nitro-renderer';
export interface CatalogNavigationViewProps
{
page: ICatalogPageData;
}

View File

@ -0,0 +1,11 @@
.catalog-navigation-item-container {
.catalog-navigation-item {
font-size: $font-size-sm;
i.fas {
color: $black;
font-size: 10px;
}
}
}

View File

@ -0,0 +1,43 @@
import { FC, useEffect } from 'react';
import { GetCatalogPageComposer } from '../../../../../api/catalog/GetCatalogPageComposer';
import { SendMessageHook } from '../../../../../hooks/messages/message-event';
import { CatalogIconView } from '../../../../catalog-icon/CatalogIconView';
import { CatalogMode } from '../../../CatalogView.types';
import { CatalogNavigationSetView } from '../set/CatalogNavigationSetView';
import { CatalogNavigationItemViewProps } from './CatalogNavigationItemView.types';
export const CatalogNavigationItemView: FC<CatalogNavigationItemViewProps> = props =>
{
const { page = null, isActive = false, setActiveChild = null } = props;
useEffect(() =>
{
if(!isActive) return;
SendMessageHook(GetCatalogPageComposer(page.pageId, -1, CatalogMode.MODE_NORMAL));
}, [ isActive, page ]);
function select(): void
{
setActiveChild(prevValue =>
{
if(prevValue === page) return null;
return page;
});
}
return (
<div className="col pe-1 pb-1 catalog-navigation-item-container">
<div className="d-flex align-items-center cursor-pointer catalog-navigation-item" onClick={ select }>
<CatalogIconView icon={ page.icon } />
<div className="flex-grow-1 text-black text-nowrap text-truncate overflow-hidden px-1">{ page.localization }</div>
{ (page.children.length > 0) && <i className={ 'fas fa-caret-' + (isActive ? 'up' : 'down') } /> }
</div>
{ isActive && page.children && (page.children.length > 0) &&
<div className="d-flex flex-column mt-1">
<CatalogNavigationSetView page={ page } />
</div> }
</div>
);
}

View File

@ -0,0 +1,9 @@
import { ICatalogPageData } from 'nitro-renderer';
import { Dispatch, SetStateAction } from 'react';
export interface CatalogNavigationItemViewProps
{
page: ICatalogPageData;
isActive: boolean;
setActiveChild: Dispatch<SetStateAction<ICatalogPageData>>;
}

View File

@ -0,0 +1,14 @@
.catalog-navigation-set-container {
.catalog-navigation-set-container {
padding-left: 5px;
.catalog-navigation-item-container {
padding-right: 0px !important;
}
}
> :last-child {
padding-bottom: 0px !important;
}
}

View File

@ -0,0 +1,28 @@
import { ICatalogPageData } from 'nitro-renderer';
import { FC, useEffect, useState } from 'react';
import { CatalogNavigationItemView } from '../item/CatalogNavigationItemView';
import { CatalogNavigationSetViewProps } from './CatalogNavigationSetView.types';
export const CatalogNavigationSetView: FC<CatalogNavigationSetViewProps> = props =>
{
const { page = null, isFirstSet = false } = props;
const [ activeChild, setActiveChild ] = useState<ICatalogPageData>(null);
useEffect(() =>
{
if(!isFirstSet) return;
if(page && page.children.length) setActiveChild(page.children[0]);
}, [ page, isFirstSet ]);
return (
<div className="row row-cols-1 g-0 catalog-navigation-set-container w-100">
{ page && (page.children.length > 0) && page.children.map((page, index) =>
{
if(!page.visible) return null;
return <CatalogNavigationItemView key={ index } page={ page } isActive={ (activeChild === page) } setActiveChild={ setActiveChild } />
}) }
</div>
);
}

View File

@ -0,0 +1,7 @@
import { ICatalogPageData } from 'nitro-renderer';
export interface CatalogNavigationSetViewProps
{
page: ICatalogPageData;
isFirstSet?: boolean;
}

View File

@ -0,0 +1 @@
@import './layout/CatalogLayout';

View File

@ -0,0 +1,21 @@
import { FC } from 'react';
import { useCatalogContext } from '../../context/CatalogContext';
import { CatalogPageViewProps } from './CatalogPageView.types';
import { GetCatalogLayout } from './layout/GetCatalogLayout';
export const CatalogPageView: FC<CatalogPageViewProps> = props =>
{
const { catalogState = null } = useCatalogContext();
const { pageParser = null } = catalogState;
return (
<div className="row h-100">
<div className="col-7">
{ pageParser && GetCatalogLayout(pageParser) }
</div>
<div className="col">
preview area
</div>
</div>
);
}

View File

@ -0,0 +1,4 @@
export interface CatalogPageViewProps
{
}

View File

@ -0,0 +1 @@
@import './default/CatalogLayoutDefaultView';

View File

@ -0,0 +1,6 @@
import { ICatalogPageParser } from 'nitro-renderer';
export interface CatalogLayoutProps
{
pageParser: ICatalogPageParser;
}

View File

@ -0,0 +1,42 @@
import { ICatalogPageParser } from 'nitro-renderer';
import { CatalogLayoutDefaultView } from './default/CatalogLayoutDefaultView';
export function GetCatalogLayout(pageParser: ICatalogPageParser): JSX.Element
{
switch(pageParser.catalogType)
{
case 'frontpage_featured':
return null;
case 'frontpage4':
return null;
case 'bots':
return null;
case 'pets':
return null;
case 'pets2':
return null;
case 'pets3':
return null;
case 'spaces_new':
return null;
case 'vip_buy':
return null;
case 'guild_frontpage':
return null;
case 'guild_custom_furni':
return null;
case 'trophies':
return null;
case 'search_results':
return null;
case 'club_gifts':
return null;
case 'marketplace_own_items':
return null;
case 'marketplace':
return null;
case 'default_3x3':
default:
return <CatalogLayoutDefaultView pageParser={ pageParser } />
}
}

View File

@ -0,0 +1,13 @@
import { FC } from 'react';
import { CatalogLayoutDefaultViewProps } from './CatalogLayoutDefaultView.types';
export const CatalogLayoutDefaultView: FC<CatalogLayoutDefaultViewProps> = props =>
{
const { pageParser = null } = props;
return (
<div className="d-flex">
{ pageParser && pageParser.localization.texts[0] }
</div>
);
}

View File

@ -0,0 +1,6 @@
import { CatalogLayoutProps } from '../CatalogLayout.types';
export interface CatalogLayoutDefaultViewProps extends CatalogLayoutProps
{
}