mirror of
https://github.com/billsonnn/nitro-react.git
synced 2024-11-27 08:00:51 +01:00
commit
a64c01b2db
@ -53,7 +53,7 @@
|
||||
"avatareditor.show.clubitems.first": true,
|
||||
"chat.history.max.items": 100,
|
||||
"animation.fps": 24,
|
||||
"limits.fps": true,
|
||||
"limits.fps": false,
|
||||
"system.dispatcher.log": false,
|
||||
"system.currency.types": [
|
||||
-1,
|
||||
|
@ -4,11 +4,14 @@ import { GetRoomEngine } from './GetRoomEngine';
|
||||
let didMouseMove = false;
|
||||
let lastClick = 0;
|
||||
let clickCount = 0;
|
||||
let touchTimer: ReturnType<typeof setTimeout> = null;
|
||||
|
||||
export function DispatchTouchEvent(roomId: number, canvasId: number, event: TouchEvent)
|
||||
export function DispatchTouchEvent(roomId: number, canvasId: number, event: TouchEvent, longTouch: boolean = false, altKey: boolean = false, ctrlKey: boolean = false, shiftKey: boolean = false)
|
||||
{
|
||||
let eventType = event.type;
|
||||
|
||||
if(longTouch) eventType = TouchEventType.TOUCH_LONG;
|
||||
|
||||
if(eventType === TouchEventType.TOUCH_END && !didMouseMove)
|
||||
{
|
||||
eventType = MouseEventType.MOUSE_CLICK;
|
||||
@ -17,7 +20,7 @@ export function DispatchTouchEvent(roomId: number, canvasId: number, event: Touc
|
||||
{
|
||||
clickCount = 1;
|
||||
|
||||
if(lastClick >= Date.now() - 300) clickCount++;
|
||||
if(lastClick >= (Date.now() - 300)) clickCount++;
|
||||
}
|
||||
|
||||
lastClick = Date.now();
|
||||
@ -31,24 +34,7 @@ export function DispatchTouchEvent(roomId: number, canvasId: number, event: Touc
|
||||
}
|
||||
}
|
||||
|
||||
switch(eventType)
|
||||
{
|
||||
case MouseEventType.MOUSE_CLICK:
|
||||
break;
|
||||
case MouseEventType.DOUBLE_CLICK:
|
||||
break;
|
||||
case TouchEventType.TOUCH_START:
|
||||
eventType = MouseEventType.MOUSE_DOWN;
|
||||
|
||||
didMouseMove = false;
|
||||
break;
|
||||
case TouchEventType.TOUCH_MOVE:
|
||||
eventType = MouseEventType.MOUSE_MOVE;
|
||||
|
||||
didMouseMove = true;
|
||||
break;
|
||||
default: return;
|
||||
}
|
||||
if(touchTimer) clearTimeout(touchTimer);
|
||||
|
||||
let x = 0;
|
||||
let y = 0;
|
||||
@ -66,5 +52,38 @@ export function DispatchTouchEvent(roomId: number, canvasId: number, event: Touc
|
||||
}
|
||||
|
||||
GetRoomEngine().setActiveRoomId(roomId);
|
||||
GetRoomEngine().dispatchMouseEvent(canvasId, x, y, eventType, event.altKey, (event.ctrlKey || event.metaKey), event.shiftKey, false);
|
||||
|
||||
switch(eventType)
|
||||
{
|
||||
case MouseEventType.MOUSE_CLICK:
|
||||
break;
|
||||
case MouseEventType.DOUBLE_CLICK:
|
||||
break;
|
||||
case TouchEventType.TOUCH_START:
|
||||
touchTimer = setTimeout(() =>
|
||||
{
|
||||
if(didMouseMove) return;
|
||||
|
||||
DispatchTouchEvent(roomId, canvasId, event, true);
|
||||
}, 300);
|
||||
|
||||
eventType = MouseEventType.MOUSE_DOWN;
|
||||
|
||||
didMouseMove = false;
|
||||
break;
|
||||
case TouchEventType.TOUCH_MOVE:
|
||||
eventType = MouseEventType.MOUSE_MOVE;
|
||||
|
||||
didMouseMove = true;
|
||||
break;
|
||||
case TouchEventType.TOUCH_END:
|
||||
eventType = MouseEventType.MOUSE_UP;
|
||||
break;
|
||||
case TouchEventType.TOUCH_LONG:
|
||||
eventType = MouseEventType.MOUSE_DOWN_LONG;
|
||||
break;
|
||||
default: return;
|
||||
}
|
||||
|
||||
GetRoomEngine().dispatchMouseEvent(canvasId, x, y, eventType, altKey, ctrlKey, shiftKey, false);
|
||||
}
|
||||
|
@ -32,10 +32,7 @@ ul {
|
||||
}
|
||||
|
||||
.cursor-pointer {
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.pointer-events-none {
|
||||
|
@ -10,4 +10,5 @@ export class CatalogEvent extends NitroEvent
|
||||
public static SOLD_OUT: string = 'CE_SOLD_OUT';
|
||||
public static APPROVE_NAME_RESULT: string = 'CE_APPROVE_NAME_RESULT';
|
||||
public static PURCHASE_APPROVED: string = 'CE_PURCHASE_APPROVED';
|
||||
public static CATALOG_RESET: string = 'CE_RESET';
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
.draggable-window {
|
||||
visibility: hidden;
|
||||
|
||||
.drag-handler {
|
||||
cursor: move;
|
||||
|
@ -62,6 +62,8 @@ export const DraggableWindow: FC<DraggableWindowProps> = props =>
|
||||
element.style.top = `${ top }px`;
|
||||
}
|
||||
|
||||
element.style.visibility = 'visible';
|
||||
|
||||
return () =>
|
||||
{
|
||||
const index = currentWindows.indexOf(element);
|
||||
|
@ -1,24 +1,17 @@
|
||||
import { IEventDispatcher, NitroEvent } from 'nitro-renderer';
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
export function CreateEventDispatcherHook(type: string, eventDispatcher: IEventDispatcher, handler: (event: NitroEvent) => void): void
|
||||
{
|
||||
const handlerRef = useRef<(event: NitroEvent) => void>();
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
handlerRef.current = handler;
|
||||
}, [ handler ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
eventDispatcher.addEventListener(type, handlerRef.current);
|
||||
eventDispatcher.addEventListener(type, handler);
|
||||
|
||||
return () =>
|
||||
{
|
||||
eventDispatcher.removeEventListener(type, handlerRef.current);
|
||||
eventDispatcher.removeEventListener(type, handler);
|
||||
}
|
||||
}, [ type, eventDispatcher ]);
|
||||
}, [ type, eventDispatcher, handler ]);
|
||||
}
|
||||
|
||||
export function DispatchEventHook(eventDispatcher: IEventDispatcher, event: NitroEvent): void
|
||||
|
@ -19,7 +19,7 @@ $nitro-card-top-height: $nitro-card-header-height + $nitro-card-tabs-height;
|
||||
@import './tabs/NitroCardTabsView';
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(md) {
|
||||
@include media-breakpoint-down(lg) {
|
||||
|
||||
.draggable-window {
|
||||
top: 0 !important;
|
||||
@ -31,6 +31,7 @@ $nitro-card-top-height: $nitro-card-header-height + $nitro-card-tabs-height;
|
||||
|
||||
.nitro-card {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
&.rounded {
|
||||
border-radius: 0 !important;
|
||||
|
@ -3,7 +3,7 @@
|
||||
padding-bottom: $container-padding-x;
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(md) {
|
||||
@include media-breakpoint-down(lg) {
|
||||
|
||||
.content-area {
|
||||
height: 100% !important;
|
||||
|
@ -4,11 +4,11 @@ import { NitroCardTabsItemViewProps } from './NitroCardTabsItemView.types';
|
||||
|
||||
export const NitroCardTabsItemView: FC<NitroCardTabsItemViewProps> = props =>
|
||||
{
|
||||
const { tabText = '', isActive = false, onClick = null } = props;
|
||||
const { children = null, isActive = false, onClick = null } = props;
|
||||
|
||||
return (
|
||||
<li className="nav-item me-1 cursor-pointer" onClick={ onClick }>
|
||||
<span className={ 'nav-link ' + classNames({ 'active': isActive }) }>{ tabText }</span>
|
||||
<span className={ 'nav-link ' + classNames({ 'active': isActive }) }>{ children }</span>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ import { MouseEventHandler } from 'react';
|
||||
|
||||
export interface NitroCardTabsItemViewProps
|
||||
{
|
||||
tabText?: string;
|
||||
isActive?: boolean;
|
||||
onClick?: MouseEventHandler<HTMLLIElement>;
|
||||
}
|
||||
|
32
src/layout/scrollable-area/ScrollableAreaView.tsx
Normal file
32
src/layout/scrollable-area/ScrollableAreaView.tsx
Normal file
@ -0,0 +1,32 @@
|
||||
import { FC, useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { ScrollableAreaViewProps } from './ScrollableAreaView.types';
|
||||
|
||||
export const ScrollableAreaView: FC<ScrollableAreaViewProps> = props =>
|
||||
{
|
||||
const { className = null, children = null } = props;
|
||||
const [ height, setHeight ] = useState(0);
|
||||
const elementRef = useRef<HTMLDivElement>();
|
||||
|
||||
const resize = useCallback(() =>
|
||||
{
|
||||
setHeight(elementRef.current.parentElement.clientHeight);
|
||||
}, [ elementRef ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
resize();
|
||||
|
||||
window.addEventListener('resize', resize);
|
||||
|
||||
return () =>
|
||||
{
|
||||
window.removeEventListener('resize', resize);
|
||||
}
|
||||
}, [ resize ]);
|
||||
|
||||
return (
|
||||
<div ref={ elementRef } className={ className } style={ { 'overflowY': 'auto', height } }>
|
||||
{ children }
|
||||
</div>
|
||||
);
|
||||
}
|
4
src/layout/scrollable-area/ScrollableAreaView.types.ts
Normal file
4
src/layout/scrollable-area/ScrollableAreaView.types.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export interface ScrollableAreaViewProps
|
||||
{
|
||||
className?: string;
|
||||
}
|
@ -1 +0,0 @@
|
||||
@import './currency-icon/CurrencyIcon.scss';
|
@ -3,6 +3,7 @@
|
||||
@import './badge-image/BadgeImage';
|
||||
@import './catalog/CatalogView';
|
||||
@import './catalog-icon/CatalogIconView';
|
||||
@import './currency-icon/CurrencyIcon';
|
||||
@import './friend-list/FriendListView';
|
||||
@import './furni-image/FurniImageView';
|
||||
@import './hotel-view/HotelView';
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { CatalogApproveNameResultEvent, CatalogClubEvent, CatalogPageEvent, CatalogPagesEvent, CatalogPurchaseEvent, CatalogPurchaseFailedEvent, CatalogPurchaseUnavailableEvent, CatalogSearchEvent, CatalogSoldOutEvent, SellablePetPalettesEvent } from 'nitro-renderer';
|
||||
import { CatalogApproveNameResultEvent, CatalogClubEvent, CatalogPageEvent, CatalogPagesEvent, CatalogPurchaseEvent, CatalogPurchaseFailedEvent, CatalogPurchaseUnavailableEvent, CatalogSearchEvent, CatalogSoldOutEvent, CatalogUpdatedEvent, SellablePetPalettesEvent, UserSubscriptionEvent } from 'nitro-renderer';
|
||||
import { FC, useCallback } from 'react';
|
||||
import { CatalogNameResultEvent, CatalogPurchaseFailureEvent } from '../../events';
|
||||
import { CatalogPurchasedEvent } from '../../events/catalog/CatalogPurchasedEvent';
|
||||
@ -9,6 +9,7 @@ import { CatalogMessageHandlerProps } from './CatalogMessageHandler.types';
|
||||
import { useCatalogContext } from './context/CatalogContext';
|
||||
import { CatalogActions } from './reducers/CatalogReducer';
|
||||
import { CatalogPetPalette } from './utils/CatalogPetPalette';
|
||||
import { SubscriptionInfo } from './utils/SubscriptionInfo';
|
||||
|
||||
export const CatalogMessageHandler: FC<CatalogMessageHandlerProps> = props =>
|
||||
{
|
||||
@ -106,6 +107,32 @@ export const CatalogMessageHandler: FC<CatalogMessageHandlerProps> = props =>
|
||||
});
|
||||
}, [ dispatchCatalogState ]);
|
||||
|
||||
const onUserSubscriptionEvent = useCallback((event: UserSubscriptionEvent) =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
|
||||
dispatchCatalogState({
|
||||
type: CatalogActions.SET_SUBSCRIPTION_INFO,
|
||||
payload: {
|
||||
subscriptionInfo: new SubscriptionInfo(
|
||||
Math.max(0, parser.days),
|
||||
Math.max(0, parser.months),
|
||||
parser.isVip,
|
||||
parser.pastClubDays,
|
||||
parser.pastVIPDays
|
||||
)
|
||||
}
|
||||
});
|
||||
}, [ dispatchCatalogState ]);
|
||||
|
||||
const onCatalogUpdatedEvent = useCallback((event: CatalogUpdatedEvent) =>
|
||||
{
|
||||
dispatchCatalogState({
|
||||
type: CatalogActions.RESET_STATE,
|
||||
payload: {}
|
||||
});
|
||||
}, [ dispatchCatalogState ]);
|
||||
|
||||
CreateMessageHook(CatalogPagesEvent, onCatalogPagesEvent);
|
||||
CreateMessageHook(CatalogPageEvent, onCatalogPageEvent);
|
||||
CreateMessageHook(CatalogPurchaseEvent, onCatalogPurchaseEvent);
|
||||
@ -116,6 +143,8 @@ export const CatalogMessageHandler: FC<CatalogMessageHandlerProps> = props =>
|
||||
CreateMessageHook(SellablePetPalettesEvent, onSellablePetPalettesEvent);
|
||||
CreateMessageHook(CatalogApproveNameResultEvent, onCatalogApproveNameResultEvent);
|
||||
CreateMessageHook(CatalogClubEvent, onCatalogClubEvent);
|
||||
CreateMessageHook(UserSubscriptionEvent, onUserSubscriptionEvent);
|
||||
CreateMessageHook(CatalogUpdatedEvent, onCatalogUpdatedEvent);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { CatalogModeComposer, ICatalogPageData, RoomPreviewer } from 'nitro-renderer';
|
||||
import { FC, useCallback, useEffect, useReducer, useState } from 'react';
|
||||
import { GetRoomEngine } from '../../api';
|
||||
import { GetCatalogPageComposer } from '../../api/catalog/GetCatalogPageComposer';
|
||||
import { CatalogEvent } from '../../events';
|
||||
import { useUiEvent } from '../../hooks/events/ui/ui-event';
|
||||
import { SendMessageHook } from '../../hooks/messages/message-event';
|
||||
@ -12,14 +13,13 @@ import { CatalogContextProvider } from './context/CatalogContext';
|
||||
import { CatalogActions, CatalogReducer, initialCatalog } from './reducers/CatalogReducer';
|
||||
import { CatalogNavigationView } from './views/navigation/CatalogNavigationView';
|
||||
import { CatalogPageView } from './views/page/CatalogPageView';
|
||||
import { CatalogSearchView } from './views/search/CatalogSearchView';
|
||||
|
||||
export const CatalogView: FC<CatalogViewProps> = props =>
|
||||
{
|
||||
const [ isVisible, setIsVisible ] = useState(false);
|
||||
const [ roomPreviewer, setRoomPreviewer ] = useState<RoomPreviewer>(null);
|
||||
const [ catalogState, dispatchCatalogState ] = useReducer(CatalogReducer, initialCatalog);
|
||||
const { root = null, currentTab = null, activeOffer = null, searchResult = null } = catalogState;
|
||||
const { root = null, currentTab = null, pageParser = null, activeOffer = null, searchResult = null } = catalogState;
|
||||
|
||||
const onCatalogEvent = useCallback((event: CatalogEvent) =>
|
||||
{
|
||||
@ -40,6 +40,7 @@ export const CatalogView: FC<CatalogViewProps> = props =>
|
||||
useUiEvent(CatalogEvent.SHOW_CATALOG, onCatalogEvent);
|
||||
useUiEvent(CatalogEvent.HIDE_CATALOG, onCatalogEvent);
|
||||
useUiEvent(CatalogEvent.TOGGLE_CATALOG, onCatalogEvent);
|
||||
useUiEvent(CatalogEvent.CATALOG_RESET, onCatalogEvent);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
@ -51,6 +52,13 @@ export const CatalogView: FC<CatalogViewProps> = props =>
|
||||
}
|
||||
}, [ isVisible, catalogState.root ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if(!currentTab) return;
|
||||
|
||||
SendMessageHook(GetCatalogPageComposer(currentTab.pageId, -1, CatalogMode.MODE_NORMAL));
|
||||
}, [ currentTab ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
setRoomPreviewer(new RoomPreviewer(GetRoomEngine(), ++RoomPreviewer.PREVIEW_COUNTER));
|
||||
@ -66,7 +74,7 @@ export const CatalogView: FC<CatalogViewProps> = props =>
|
||||
}
|
||||
}, []);
|
||||
|
||||
function setCurrentTab(page: ICatalogPageData): void
|
||||
const setCurrentTab = useCallback((page: ICatalogPageData) =>
|
||||
{
|
||||
dispatchCatalogState({
|
||||
type: CatalogActions.SET_CATALOG_CURRENT_TAB,
|
||||
@ -74,7 +82,7 @@ export const CatalogView: FC<CatalogViewProps> = props =>
|
||||
currentTab: page
|
||||
}
|
||||
});
|
||||
}
|
||||
}, [ dispatchCatalogState ]);
|
||||
|
||||
const currentNavigationPage = ((searchResult && searchResult.page) || currentTab);
|
||||
|
||||
@ -87,15 +95,19 @@ export const CatalogView: FC<CatalogViewProps> = props =>
|
||||
<NitroCardTabsView>
|
||||
{ root && root.children.length && root.children.map((page, index) =>
|
||||
{
|
||||
return <NitroCardTabsItemView key={ index } tabText={ page.localization } isActive={ (currentTab === page) } onClick={ event => setCurrentTab(page) } />
|
||||
return (
|
||||
<NitroCardTabsItemView key={ index } isActive={ (currentTab === page) } onClick={ event => setCurrentTab(page) }>
|
||||
{ page.localization }
|
||||
</NitroCardTabsItemView>
|
||||
);
|
||||
}) }
|
||||
</NitroCardTabsView>
|
||||
<NitroCardContentView>
|
||||
<div className="row h-100">
|
||||
{ pageParser && !pageParser.frontPageItems.length &&
|
||||
<div className="col-3">
|
||||
<CatalogSearchView />
|
||||
<CatalogNavigationView page={ currentNavigationPage } />
|
||||
</div>
|
||||
</div> }
|
||||
<div className="col">
|
||||
<CatalogPageView roomPreviewer={ roomPreviewer } />
|
||||
</div>
|
||||
|
@ -2,17 +2,20 @@ import { CatalogClubOfferData, CatalogPageOfferData, ICatalogPageData, ICatalogP
|
||||
import { Reducer } from 'react';
|
||||
import { CatalogPetPalette } from '../utils/CatalogPetPalette';
|
||||
import { ICatalogOffers, ICatalogSearchResult, SetOffersToNodes } from '../utils/CatalogUtilities';
|
||||
import { SubscriptionInfo } from '../utils/SubscriptionInfo';
|
||||
|
||||
export interface ICatalogState
|
||||
{
|
||||
root: ICatalogPageData;
|
||||
offerRoot: ICatalogOffers;
|
||||
currentTab: ICatalogPageData;
|
||||
currentPage: ICatalogPageData;
|
||||
pageParser: ICatalogPageParser;
|
||||
activeOffer: CatalogPageOfferData;
|
||||
searchResult: ICatalogSearchResult;
|
||||
petPalettes: CatalogPetPalette[];
|
||||
clubOffers: CatalogClubOfferData[];
|
||||
subscriptionInfo: SubscriptionInfo;
|
||||
}
|
||||
|
||||
export interface ICatalogAction
|
||||
@ -22,11 +25,13 @@ export interface ICatalogAction
|
||||
root?: ICatalogPageData;
|
||||
offerRoot?: ICatalogOffers;
|
||||
currentTab?: ICatalogPageData;
|
||||
currentPage?: ICatalogPageData;
|
||||
pageParser?: ICatalogPageParser;
|
||||
activeOffer?: CatalogPageOfferData;
|
||||
searchResult?: ICatalogSearchResult;
|
||||
petPalette?: CatalogPetPalette;
|
||||
clubOffers?: CatalogClubOfferData[];
|
||||
subscriptionInfo?: SubscriptionInfo;
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,22 +39,27 @@ export class CatalogActions
|
||||
{
|
||||
public static SET_CATALOG_ROOT: string = 'CA_SET_CATALOG_ROOT';
|
||||
public static SET_CATALOG_CURRENT_TAB: string = 'CA_SET_CATALOG_CURRENT_TAB';
|
||||
public static SET_CATALOG_CURRENT_PAGE: string = 'CA_SET_CATALOG_CURRENT_PAGE';
|
||||
public static SET_CATALOG_PAGE_PARSER: string = 'CA_SET_CATALOG_PAGE';
|
||||
public static SET_CATALOG_ACTIVE_OFFER: string = 'CA_SET_ACTIVE_OFFER';
|
||||
public static SET_SEARCH_RESULT: string = 'CA_SET_SEARCH_RESULT';
|
||||
public static SET_PET_PALETTE: string = 'CA_SET_PET_PALETTE';
|
||||
public static SET_CLUB_OFFERS: string = 'CA_SET_CLUB_OFFERS';
|
||||
public static SET_SUBSCRIPTION_INFO: string = 'CA_SET_SUBSCRIPTION_INFO';
|
||||
public static RESET_STATE = 'CA_RESET_STATE';
|
||||
}
|
||||
|
||||
export const initialCatalog: ICatalogState = {
|
||||
root: null,
|
||||
offerRoot: null,
|
||||
currentTab: null,
|
||||
currentPage: null,
|
||||
pageParser: null,
|
||||
activeOffer: null,
|
||||
searchResult: null,
|
||||
petPalettes: [],
|
||||
clubOffers: null
|
||||
clubOffers: null,
|
||||
subscriptionInfo: new SubscriptionInfo()
|
||||
}
|
||||
|
||||
export const CatalogReducer: Reducer<ICatalogState, ICatalogAction> = (state, action) =>
|
||||
@ -72,8 +82,13 @@ export const CatalogReducer: Reducer<ICatalogState, ICatalogAction> = (state, ac
|
||||
|
||||
return { ...state, currentTab, searchResult };
|
||||
}
|
||||
case CatalogActions.SET_CATALOG_CURRENT_PAGE: {
|
||||
const currentPage = (action.payload.currentPage || state.currentPage || null);
|
||||
|
||||
return { ...state, currentPage };
|
||||
}
|
||||
case CatalogActions.SET_CATALOG_PAGE_PARSER: {
|
||||
let pageParser = Object.create(action.payload.pageParser);
|
||||
let pageParser = (Object.create(action.payload.pageParser) as ICatalogPageParser);
|
||||
let activeOffer = null;
|
||||
|
||||
if(pageParser.layoutCode === 'single_bundle')
|
||||
@ -126,6 +141,14 @@ export const CatalogReducer: Reducer<ICatalogState, ICatalogAction> = (state, ac
|
||||
|
||||
return { ...state, clubOffers };
|
||||
}
|
||||
case CatalogActions.SET_SUBSCRIPTION_INFO: {
|
||||
const subscriptionInfo = (action.payload.subscriptionInfo || null);
|
||||
|
||||
return { ...state, subscriptionInfo };
|
||||
}
|
||||
case CatalogActions.RESET_STATE: {
|
||||
return { ...initialCatalog };
|
||||
}
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
14
src/views/catalog/utils/IPurse.ts
Normal file
14
src/views/catalog/utils/IPurse.ts
Normal file
@ -0,0 +1,14 @@
|
||||
export interface IPurse
|
||||
{
|
||||
_Str_14389: boolean;
|
||||
_Str_4458: number;
|
||||
credits: number;
|
||||
clubDays: number;
|
||||
clubPeriods: number;
|
||||
_Str_13571: boolean;
|
||||
_Str_3738: boolean;
|
||||
_Str_6288: number;
|
||||
_Str_4605: number;
|
||||
_Str_6312: number;
|
||||
_Str_5590(_arg_1: number): number;
|
||||
}
|
144
src/views/catalog/utils/Purse.ts
Normal file
144
src/views/catalog/utils/Purse.ts
Normal file
@ -0,0 +1,144 @@
|
||||
import { Nitro } from 'nitro-renderer';
|
||||
import { IPurse } from './IPurse';
|
||||
|
||||
export class Purse implements IPurse
|
||||
{
|
||||
private _credits: number = 0;
|
||||
private _activityPoints: Map<number, number>;
|
||||
private _clubDays: number = 0;
|
||||
private _clubPeriods: number = 0;
|
||||
private _isVIP: boolean = false;
|
||||
private _pastClubDays: number = 0;
|
||||
private _pastVipDays: number = 0;
|
||||
private _isExpiring: boolean = false;
|
||||
private _minutesUntilExpiration: number = 0;
|
||||
private _minutesSinceLastModified: number;
|
||||
private _lastUpdated: number;
|
||||
|
||||
public get credits(): number
|
||||
{
|
||||
return this._credits;
|
||||
}
|
||||
|
||||
public set credits(k: number)
|
||||
{
|
||||
this._lastUpdated = Nitro.instance.time;
|
||||
this._credits = k;
|
||||
}
|
||||
|
||||
public get clubDays(): number
|
||||
{
|
||||
return this._clubDays;
|
||||
}
|
||||
|
||||
public set clubDays(k: number)
|
||||
{
|
||||
this._lastUpdated = Nitro.instance.time;
|
||||
this._clubDays = k;
|
||||
}
|
||||
|
||||
public get clubPeriods(): number
|
||||
{
|
||||
return this._clubPeriods;
|
||||
}
|
||||
|
||||
public set clubPeriods(k: number)
|
||||
{
|
||||
this._lastUpdated = Nitro.instance.time;
|
||||
this._clubPeriods = k;
|
||||
}
|
||||
|
||||
public get _Str_13571(): boolean
|
||||
{
|
||||
return (this._clubDays > 0) || (this._clubPeriods > 0);
|
||||
}
|
||||
|
||||
public get _Str_3738(): boolean
|
||||
{
|
||||
return this._isVIP;
|
||||
}
|
||||
|
||||
public get _Str_14389(): boolean
|
||||
{
|
||||
return this._isExpiring;
|
||||
}
|
||||
|
||||
public set _Str_14389(k: boolean)
|
||||
{
|
||||
this._isExpiring = k;
|
||||
}
|
||||
|
||||
public set _Str_3738(k: boolean)
|
||||
{
|
||||
this._isVIP = k;
|
||||
}
|
||||
|
||||
public get _Str_6288(): number
|
||||
{
|
||||
return this._pastClubDays;
|
||||
}
|
||||
|
||||
public set _Str_6288(k: number)
|
||||
{
|
||||
this._lastUpdated = Nitro.instance.time;
|
||||
this._pastClubDays = k;
|
||||
}
|
||||
|
||||
public get _Str_4605(): number
|
||||
{
|
||||
return this._pastVipDays;
|
||||
}
|
||||
|
||||
public set _Str_4605(k: number)
|
||||
{
|
||||
this._lastUpdated = Nitro.instance.time;
|
||||
this._pastVipDays = k;
|
||||
}
|
||||
|
||||
public get _Str_18527(): Map<number, number>
|
||||
{
|
||||
return this._activityPoints;
|
||||
}
|
||||
|
||||
public set _Str_18527(k: Map<number, number>)
|
||||
{
|
||||
this._lastUpdated = Nitro.instance.time;
|
||||
this._activityPoints = k;
|
||||
}
|
||||
|
||||
public _Str_5590(k: number): number
|
||||
{
|
||||
return this._activityPoints[k];
|
||||
}
|
||||
|
||||
public set _Str_4458(k: number)
|
||||
{
|
||||
this._lastUpdated = Nitro.instance.time;
|
||||
|
||||
this._minutesUntilExpiration = k;
|
||||
}
|
||||
|
||||
public get _Str_4458(): number
|
||||
{
|
||||
const k = ((Nitro.instance.time - this._lastUpdated) / (1000 * 60));
|
||||
const _local_2 = (this._minutesUntilExpiration - k);
|
||||
|
||||
return (_local_2 > 0) ? _local_2 : 0;
|
||||
}
|
||||
|
||||
public set _Str_6312(k: number)
|
||||
{
|
||||
this._lastUpdated = Nitro.instance.time;
|
||||
this._minutesSinceLastModified = k;
|
||||
}
|
||||
|
||||
public get _Str_6312(): number
|
||||
{
|
||||
return this._minutesSinceLastModified;
|
||||
}
|
||||
|
||||
public get _Str_26225(): number
|
||||
{
|
||||
return this._lastUpdated;
|
||||
}
|
||||
}
|
17
src/views/catalog/utils/SubscriptionInfo.ts
Normal file
17
src/views/catalog/utils/SubscriptionInfo.ts
Normal file
@ -0,0 +1,17 @@
|
||||
|
||||
export class SubscriptionInfo
|
||||
{
|
||||
private _lastUpdated: number;
|
||||
|
||||
constructor(
|
||||
public clubDays: number = 0,
|
||||
public clubPeriods: number = 0,
|
||||
public isVip: boolean = false,
|
||||
public pastDays: number = 0,
|
||||
public pastVipDays: number = 0) {}
|
||||
|
||||
public get lastUpdated(): number
|
||||
{
|
||||
return this._lastUpdated;
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
import { ICatalogPageData } from 'nitro-renderer';
|
||||
import { FC, useEffect } from 'react';
|
||||
import { CatalogSearchView } from '../search/CatalogSearchView';
|
||||
import { CatalogNavigationViewProps } from './CatalogNavigationView.types';
|
||||
import { CatalogNavigationSetView } from './set/CatalogNavigationSetView';
|
||||
|
||||
@ -17,10 +18,13 @@ export const CatalogNavigationView: FC<CatalogNavigationViewProps> = props =>
|
||||
}, [ page ]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<CatalogSearchView />
|
||||
<div className="border border-2 rounded overflow-hidden nitro-catalog-navigation">
|
||||
<div className="navigation-container m-1">
|
||||
<CatalogNavigationSetView page={ page } isFirstSet={ true } />
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -13,7 +13,12 @@ export const CatalogNavigationSetView: FC<CatalogNavigationSetViewProps> = props
|
||||
{
|
||||
if(!isFirstSet || !page || (page.pageId === -1)) return;
|
||||
|
||||
if(page && page.children.length) setActiveChild(page.children[0]);
|
||||
if(page && page.children.length)
|
||||
{
|
||||
const child = page.children[0];
|
||||
|
||||
setActiveChild(child);
|
||||
}
|
||||
}, [ page, isFirstSet ]);
|
||||
|
||||
useEffect(() =>
|
||||
|
@ -1,3 +1,4 @@
|
||||
@import './header/CatalogPageHeaderView';
|
||||
@import './layout/CatalogLayout';
|
||||
@import './offer/CatalogPageOfferView';
|
||||
@import './offers/CatalogPageOffersView';
|
||||
|
@ -0,0 +1,3 @@
|
||||
.nitro-catalog-page-header {
|
||||
padding-top: $container-padding-x;
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
import { FC } from 'react';
|
||||
import { CatalogIconView } from '../../../../catalog-icon/CatalogIconView';
|
||||
import { useCatalogContext } from '../../../context/CatalogContext';
|
||||
import { CatalogPageHeaderViewProps } from './CatalogPageHeaderView.types';
|
||||
|
||||
export const CatalogPageHeaderView: FC<CatalogPageHeaderViewProps> = props =>
|
||||
{
|
||||
const { catalogState = null } = useCatalogContext();
|
||||
const { currentPage = null, pageParser = null } = catalogState;
|
||||
|
||||
return (
|
||||
<div className="container-fluid nitro-catalog-page-header bg-light">
|
||||
<div className="row h-100">
|
||||
<div className="col-2">
|
||||
<CatalogIconView icon={ currentPage.icon } />
|
||||
</div>
|
||||
<div className="d-flex col-10 flex-column">
|
||||
<div className="d-block">
|
||||
{ currentPage.localization }
|
||||
</div>
|
||||
{ pageParser && <div className="d-block">
|
||||
{ pageParser.localization.texts[0] }
|
||||
</div> }
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
import { ICatalogPageParser } from 'nitro-renderer';
|
||||
|
||||
export interface CatalogPageHeaderViewProps
|
||||
{
|
||||
pageParser: ICatalogPageParser;
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
@import './default/CatalogLayoutDefaultView';
|
||||
@import './frontpage4/CatalogLayoutFrontpage4View';
|
||||
@import './pets/CatalogLayoutPetView';
|
||||
@import './pets3/CatalogLayoutPets3View';
|
||||
@import './single-bundle/CatalogLayoutSingleBundleView';
|
||||
@import './spaces-new/CatalogLayoutSpacesView';
|
||||
@import './trophies/CatalogLayoutTrophiesView';
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { ICatalogPageParser, RoomPreviewer } from 'nitro-renderer';
|
||||
import { CatalogLayoutDefaultView } from './default/CatalogLayoutDefaultView';
|
||||
import { CatalogLayoutFrontpage4View } from './frontpage4/CatalogLayoutFrontpage4View';
|
||||
import { CatalogLayoutPetView } from './pets/CatalogLayoutPetView';
|
||||
import { CatalogLayoutPets3View } from './pets3/CatalogLayoutPets3View';
|
||||
import { CatalogLayoutSingleBundleView } from './single-bundle/CatalogLayoutSingleBundleView';
|
||||
import { CatalogLayoutSpacesView } from './spaces-new/CatalogLayoutSpacesView';
|
||||
import { CatalogLayoutTrophiesView } from './trophies/CatalogLayoutTrophiesView';
|
||||
@ -13,13 +15,13 @@ export function GetCatalogLayout(pageParser: ICatalogPageParser, roomPreviewer:
|
||||
case 'frontpage_featured':
|
||||
return null;
|
||||
case 'frontpage4':
|
||||
return null;
|
||||
return <CatalogLayoutFrontpage4View roomPreviewer={ roomPreviewer } pageParser={ pageParser } />;
|
||||
case 'pets':
|
||||
return <CatalogLayoutPetView roomPreviewer={ roomPreviewer } pageParser={ pageParser } />;
|
||||
case 'pets2':
|
||||
return null;
|
||||
case 'pets3':
|
||||
return null;
|
||||
return <CatalogLayoutPets3View roomPreviewer={ roomPreviewer } pageParser={ pageParser } />;
|
||||
case 'vip_buy':
|
||||
return <CatalogLayoutVipBuyView roomPreviewer={ roomPreviewer } pageParser={ pageParser } />;
|
||||
case 'guild_frontpage':
|
||||
|
@ -0,0 +1,22 @@
|
||||
.nitro-catalog-layout-frontpage4 {
|
||||
|
||||
.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);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
import { FC, useCallback, useMemo } from 'react';
|
||||
import { GetConfiguration } from '../../../../../../utils/GetConfiguration';
|
||||
import { CatalogLayoutFrontpage4ViewProps } from './CatalogLayoutFrontpage4View.types';
|
||||
|
||||
export const CatalogLayoutFrontpage4View: FC<CatalogLayoutFrontpage4ViewProps> = props =>
|
||||
{
|
||||
const { pageParser = null } = props;
|
||||
|
||||
const getFrontPageItem = useCallback((position: number) =>
|
||||
{
|
||||
for(const item of pageParser.frontPageItems)
|
||||
{
|
||||
if(item.position !== position) continue;
|
||||
|
||||
return item;
|
||||
}
|
||||
}, [ pageParser ]);
|
||||
|
||||
const getFrontPageItemImage = useCallback((position: number) =>
|
||||
{
|
||||
const item = getFrontPageItem(position);
|
||||
|
||||
if(!item) return null;
|
||||
|
||||
return item.itemPromoImage;
|
||||
}, [ getFrontPageItem ]);
|
||||
|
||||
const imageLibraryUrl = useMemo(() =>
|
||||
{
|
||||
return GetConfiguration<string>('image.library.url');
|
||||
}, []);
|
||||
|
||||
if(!pageParser) return null;
|
||||
|
||||
return (
|
||||
<div className="row h-100 nitro-catalog-layout-frontpage4">
|
||||
<div className="col-4">
|
||||
{ pageParser.frontPageItems[0] &&
|
||||
<div className="front-page-item h-100" style={ { backgroundImage: `url('${ imageLibraryUrl }${ pageParser.frontPageItems[0].itemPromoImage }')`}}>
|
||||
<div className="front-page-item-caption">{ pageParser.frontPageItems[0].itemName }</div>
|
||||
</div> }
|
||||
</div>
|
||||
<div className="d-flex col-8 flex-column">
|
||||
{ pageParser.frontPageItems[1] &&
|
||||
<div className="front-page-item h-100 mb-2" style={ { backgroundImage: `url('${ imageLibraryUrl }${ pageParser.frontPageItems[1].itemPromoImage }')`}}>
|
||||
<div className="front-page-item-caption">{ pageParser.frontPageItems[1].itemName }</div>
|
||||
</div> }
|
||||
{ pageParser.frontPageItems[2] &&
|
||||
<div className="front-page-item h-100 mb-2" style={ { backgroundImage: `url('${ imageLibraryUrl }${ pageParser.frontPageItems[2].itemPromoImage }')`}}>
|
||||
<div className="front-page-item-caption">{ pageParser.frontPageItems[2].itemName }</div>
|
||||
</div> }
|
||||
{ pageParser.frontPageItems[3] &&
|
||||
<div className="front-page-item h-100" style={ { backgroundImage: `url('${ imageLibraryUrl }${ pageParser.frontPageItems[3].itemPromoImage }')`}}>
|
||||
<div className="front-page-item-caption">{ pageParser.frontPageItems[3].itemName }</div>
|
||||
</div> }
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
import { CatalogLayoutProps } from '../CatalogLayout.types';
|
||||
|
||||
export interface CatalogLayoutFrontpage4ViewProps extends CatalogLayoutProps
|
||||
{
|
||||
|
||||
}
|
@ -7,7 +7,7 @@ import { PetImageView } from '../../../../../pet-image/PetImageView';
|
||||
import { RoomPreviewerView } from '../../../../../room-previewer/RoomPreviewerView';
|
||||
import { useCatalogContext } from '../../../../context/CatalogContext';
|
||||
import { CatalogActions } from '../../../../reducers/CatalogReducer';
|
||||
import { GetPetAvailableColors, GetPetIndexFromLocalization } from '../../../../utils/CatalogUtilities';
|
||||
import { GetCatalogPageImage, GetCatalogPageText, GetPetAvailableColors, GetPetIndexFromLocalization } from '../../../../utils/CatalogUtilities';
|
||||
import { CatalogLayoutPetViewProps } from './CatalogLayoutPetView.types';
|
||||
import { CatalogLayoutPetPurchaseView } from './purchase/CatalogLayoutPetPurchaseView';
|
||||
|
||||
@ -160,6 +160,14 @@ export const CatalogLayoutPetView: FC<CatalogLayoutPetViewProps> = props =>
|
||||
}) }
|
||||
</div>
|
||||
</div>
|
||||
{ (petIndex === -1) &&
|
||||
<div className="position-relative d-flex flex-column col-5 justify-content-center align-items-center">
|
||||
<div className="d-block mb-2">
|
||||
<img alt="" src={ GetCatalogPageImage(pageParser, 1) } />
|
||||
</div>
|
||||
<div className="fs-6 text-center text-black lh-sm overflow-hidden">{ GetCatalogPageText(pageParser, 0) }</div>
|
||||
</div> }
|
||||
{ (petIndex >= 0) &&
|
||||
<div className="position-relative d-flex flex-column col-5">
|
||||
<RoomPreviewerView roomPreviewer={ roomPreviewer } height={ 140 }>
|
||||
{ (petIndex > -1 && petIndex <= 7) &&
|
||||
@ -169,7 +177,7 @@ export const CatalogLayoutPetView: FC<CatalogLayoutPetViewProps> = props =>
|
||||
</RoomPreviewerView>
|
||||
<div className="fs-6 text-black mt-1 overflow-hidden">{ petBreedName }</div>
|
||||
<CatalogLayoutPetPurchaseView offer={ activeOffer } pageId={ pageParser.pageId } extra={ petPurchaseString } />
|
||||
</div>
|
||||
</div> }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -3,8 +3,8 @@ import { FC, useCallback, useState } from 'react';
|
||||
import { CatalogEvent } from '../../../../../../../events';
|
||||
import { useUiEvent } from '../../../../../../../hooks/events/ui/ui-event';
|
||||
import { SendMessageHook } from '../../../../../../../hooks/messages/message-event';
|
||||
import { CurrencyIcon } from '../../../../../../../utils/currency-icon/CurrencyIcon';
|
||||
import { LocalizeText } from '../../../../../../../utils/LocalizeText';
|
||||
import { CurrencyIcon } from '../../../../../../currency-icon/CurrencyIcon';
|
||||
import { CatalogPurchaseButtonView } from '../../../purchase/purchase-button/CatalogPurchaseButtonView';
|
||||
import { CatalogPetNameApprovalView } from '../name-approval/CatalogPetNameApprovalView';
|
||||
import { CatalogLayoutPetPurchaseViewProps } from './CatalogLayoutPetPurchaseView.types';
|
||||
|
@ -0,0 +1,2 @@
|
||||
.nitro-catalog-layout-pets3 {
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
import { FC } from 'react';
|
||||
import { GetCatalogPageImage, GetCatalogPageText } from '../../../../utils/CatalogUtilities';
|
||||
import { CatalogLayoutPets3ViewProps } from './CatalogLayoutPets3View.types';
|
||||
|
||||
export const CatalogLayoutPets3View: FC<CatalogLayoutPets3ViewProps> = props =>
|
||||
{
|
||||
const { pageParser = null } = props;
|
||||
|
||||
return (
|
||||
<div className="row h-100 nitro-catalog-layout-pets3">
|
||||
<div className="col-7">
|
||||
<div className="" dangerouslySetInnerHTML={ {__html: GetCatalogPageText(pageParser, 1) } } />
|
||||
<div className="" dangerouslySetInnerHTML={ {__html: GetCatalogPageText(pageParser, 2) } } />
|
||||
<div className="" dangerouslySetInnerHTML={ {__html: GetCatalogPageText(pageParser, 3) } } />
|
||||
</div>
|
||||
<div className="position-relative d-flex flex-column col-5 justify-content-center align-items-center">
|
||||
<div className="d-block mb-2">
|
||||
<img alt="" src={ GetCatalogPageImage(pageParser, 1) } />
|
||||
</div>
|
||||
<div className="fs-6 text-center text-black lh-sm overflow-hidden">{ GetCatalogPageText(pageParser, 0) }</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
import { CatalogLayoutProps } from '../CatalogLayout.types';
|
||||
|
||||
export interface CatalogLayoutPets3ViewProps extends CatalogLayoutProps
|
||||
{
|
||||
|
||||
}
|
@ -5,7 +5,7 @@ import { LocalizeText } from '../../../../../../utils/LocalizeText';
|
||||
import { RoomPreviewerView } from '../../../../../room-previewer/RoomPreviewerView';
|
||||
import { useCatalogContext } from '../../../../context/CatalogContext';
|
||||
import { ProductTypeEnum } from '../../../../enums/ProductTypeEnum';
|
||||
import { GetOfferName } from '../../../../utils/CatalogUtilities';
|
||||
import { GetCatalogPageImage, GetCatalogPageText, GetOfferName } from '../../../../utils/CatalogUtilities';
|
||||
import { CatalogPageOffersView } from '../../offers/CatalogPageOffersView';
|
||||
import { CatalogPurchaseView } from '../../purchase/CatalogPurchaseView';
|
||||
import { CatalogLayoutSpacesViewProps } from './CatalogLayoutSpacesView.types';
|
||||
@ -81,6 +81,13 @@ export const CatalogLayoutSpacesView: FC<CatalogLayoutSpacesViewProps> = props =
|
||||
</div>
|
||||
<CatalogPageOffersView offers={ groups[activeGroupIndex] } />
|
||||
</div>
|
||||
{ !product &&
|
||||
<div className="position-relative d-flex flex-column col-5 justify-content-center align-items-center">
|
||||
<div className="d-block mb-2">
|
||||
<img alt="" src={ GetCatalogPageImage(pageParser, 1) } />
|
||||
</div>
|
||||
<div className="fs-6 text-center text-black lh-sm overflow-hidden">{ GetCatalogPageText(pageParser, 0) }</div>
|
||||
</div> }
|
||||
{ product &&
|
||||
<div className="position-relative d-flex flex-column col">
|
||||
<RoomPreviewerView roomPreviewer={ roomPreviewer } height={ 140 } />
|
||||
|
@ -1,16 +1,16 @@
|
||||
import { CatalogClubOfferData, CatalogRequestVipOffersComposer } from 'nitro-renderer';
|
||||
import { FC, useCallback, useEffect } from 'react';
|
||||
import { FC, useCallback, useEffect, useMemo } from 'react';
|
||||
import { SendMessageHook } from '../../../../../../hooks/messages/message-event';
|
||||
import { CurrencyIcon } from '../../../../../../utils/currency-icon/CurrencyIcon';
|
||||
import { LocalizeText } from '../../../../../../utils/LocalizeText';
|
||||
import { CurrencyIcon } from '../../../../../currency-icon/CurrencyIcon';
|
||||
import { useCatalogContext } from '../../../../context/CatalogContext';
|
||||
import { GetCatalogPageImage, GetCatalogPageText } from '../../../../utils/CatalogUtilities';
|
||||
import { GetCatalogPageImage } from '../../../../utils/CatalogUtilities';
|
||||
import { CatalogLayoutVipBuyViewProps } from './CatalogLayoutVipBuyView.types';
|
||||
|
||||
export const CatalogLayoutVipBuyView: FC<CatalogLayoutVipBuyViewProps> = props =>
|
||||
{
|
||||
const { catalogState = null } = useCatalogContext();
|
||||
const { pageParser = null, clubOffers = null } = catalogState;
|
||||
const { pageParser = null, clubOffers = null, subscriptionInfo = null } = catalogState;
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
@ -41,6 +41,17 @@ export const CatalogLayoutVipBuyView: FC<CatalogLayoutVipBuyViewProps> = props =
|
||||
return offerText;
|
||||
}, []);
|
||||
|
||||
const getSubscriptionDetails = useMemo(() =>
|
||||
{
|
||||
if(!subscriptionInfo) return '';
|
||||
|
||||
const clubDays = subscriptionInfo.clubDays;
|
||||
const clubPeriods = subscriptionInfo.clubPeriods;
|
||||
const totalDays = (clubPeriods * 31) + clubDays;
|
||||
|
||||
return LocalizeText('catalog.vip.extend.info', [ 'days' ], [ totalDays.toString() ]);
|
||||
}, [ subscriptionInfo ]);
|
||||
|
||||
return (
|
||||
<div className="row h-100 nitro-catalog-layout-vip-buy">
|
||||
<div className="col-7">
|
||||
@ -74,7 +85,7 @@ export const CatalogLayoutVipBuyView: FC<CatalogLayoutVipBuyViewProps> = props =
|
||||
<div className="d-block mb-2">
|
||||
<img alt="" src={ GetCatalogPageImage(pageParser, 1) } />
|
||||
</div>
|
||||
<div className="fs-6 text-center text-black lh-sm overflow-hidden">{ GetCatalogPageText(pageParser, 0) }</div>
|
||||
<div className="fs-6 text-center text-black lh-sm overflow-hidden" dangerouslySetInnerHTML={ {__html: getSubscriptionDetails } }></div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { FC, useEffect, useState } from 'react';
|
||||
import { CurrencyIcon } from '../../../../../utils/currency-icon/CurrencyIcon';
|
||||
import { LocalizeText } from '../../../../../utils/LocalizeText';
|
||||
import { CurrencyIcon } from '../../../../currency-icon/CurrencyIcon';
|
||||
import { CatalogPurchaseViewProps } from './CatalogPurchaseView.types';
|
||||
import { CatalogPurchaseButtonView } from './purchase-button/CatalogPurchaseButtonView';
|
||||
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { GetConfiguration } from '../GetConfiguration';
|
||||
import { FC } from 'react';
|
||||
import { GetConfiguration } from '../../utils/GetConfiguration';
|
||||
import { CurrencyIconProps } from './CurrencyIcon.types';
|
||||
|
||||
export function CurrencyIcon(props: CurrencyIconProps): JSX.Element
|
||||
export const CurrencyIcon: FC<CurrencyIconProps> = props =>
|
||||
{
|
||||
let url = GetConfiguration<string>('currency.asset.icon.url', '');
|
||||
|
@ -42,8 +42,8 @@
|
||||
}
|
||||
|
||||
.left {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
width: 1200px;
|
||||
height: 800px;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
animation-iteration-count: 1;
|
||||
|
@ -105,7 +105,11 @@ export const InventoryView: FC<InventoryViewProps> = props =>
|
||||
<NitroCardTabsView>
|
||||
{ tabs.map((name, index) =>
|
||||
{
|
||||
return <NitroCardTabsItemView key={ index } tabText={ LocalizeText(name) } isActive={ (currentTab === name) } onClick={ event => setCurrentTab(name) } />
|
||||
return (
|
||||
<NitroCardTabsItemView key={ index } isActive={ (currentTab === name) } onClick={ event => setCurrentTab(name) }>
|
||||
{ LocalizeText(name) }
|
||||
</NitroCardTabsItemView>
|
||||
);
|
||||
}) }
|
||||
</NitroCardTabsView>
|
||||
<NitroCardContentView>
|
||||
|
@ -76,8 +76,8 @@ export const InventoryBadgeView: FC<InventoryBadgeViewProps> = props =>
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="row">
|
||||
<div className="col-7">
|
||||
<div className="row h-100">
|
||||
<div className="d-flex flex-column col-7">
|
||||
<InventoryBadgeResultsView badges={ badges } activeBadges={ activeBadges } />
|
||||
</div>
|
||||
<div className="col">
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { FC } from 'react';
|
||||
import { ScrollableAreaView } from '../../../../../layout/scrollable-area/ScrollableAreaView';
|
||||
import { InventoryBadgeItemView } from '../item/InventoryBadgeItemView';
|
||||
import { InventoryBadgeResultsViewProps } from './InventoryBadgeResultsView.types';
|
||||
|
||||
@ -7,13 +8,15 @@ export const InventoryBadgeResultsView: FC<InventoryBadgeResultsViewProps> = pro
|
||||
const { badges = [], activeBadges = [] } = props;
|
||||
|
||||
return (
|
||||
<div className="row row-cols-5 align-content-start g-0 badge-item-container">
|
||||
<div className="d-flex flex-grow-1">
|
||||
<ScrollableAreaView className="row row-cols-5 align-content-start g-0 w-100">
|
||||
{ badges && (badges.length > 0) && badges.map((code, index) =>
|
||||
{
|
||||
if(activeBadges.indexOf(code) >= 0) return null;
|
||||
|
||||
return <InventoryBadgeItemView key={ index } badge={ code } />
|
||||
}) }
|
||||
</ScrollableAreaView>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -81,8 +81,8 @@ export const InventoryBotView: FC<InventoryBotViewProps> = props =>
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="row">
|
||||
<div className="col-7">
|
||||
<div className="row h-100">
|
||||
<div className="d-flex flex-column col-7">
|
||||
<InventoryBotResultsView botItems={ botItems } />
|
||||
</div>
|
||||
<div className="d-flex flex-column col-5 justify-space-between">
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { FC } from 'react';
|
||||
import { ScrollableAreaView } from '../../../../../layout/scrollable-area/ScrollableAreaView';
|
||||
import { InventoryBotItemView } from '../item/InventoryBotItemView';
|
||||
import { InventoryBotResultsViewProps } from './InventoryBotResultsView.types';
|
||||
|
||||
@ -7,11 +8,13 @@ export const InventoryBotResultsView: FC<InventoryBotResultsViewProps> = props =
|
||||
const { botItems = [] } = props;
|
||||
|
||||
return (
|
||||
<div className="row row-cols-5 align-content-start g-0 bot-item-container">
|
||||
<div className="d-flex flex-grow-1">
|
||||
<ScrollableAreaView className="row row-cols-5 align-content-start g-0 w-100">
|
||||
{ botItems && (botItems.length > 0) && botItems.map((item, index) =>
|
||||
{
|
||||
return <InventoryBotItemView key={ index } botItem={ item } />
|
||||
}) }
|
||||
</ScrollableAreaView>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -116,8 +116,8 @@ export const InventoryFurnitureView: FC<InventoryFurnitureViewProps> = props =>
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="row">
|
||||
<div className="col-7">
|
||||
<div className="row h-100">
|
||||
<div className="d-flex flex-column col-7">
|
||||
<InventoryFurnitureSearchView groupItems={ groupItems } setGroupItems={ setFilteredGroupItems } />
|
||||
<InventoryFurnitureResultsView groupItems={ filteredGroupItems } />
|
||||
</div>
|
||||
|
@ -1,5 +1,2 @@
|
||||
.furni-item-container {
|
||||
height: 188px;
|
||||
max-height: 188px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { FC } from 'react';
|
||||
import { ScrollableAreaView } from '../../../../../layout/scrollable-area/ScrollableAreaView';
|
||||
import { InventoryFurnitureItemView } from '../item/InventoryFurnitureItemView';
|
||||
import { InventoryFurnitureResultsViewProps } from './InventoryFurnitureResultsView.types';
|
||||
|
||||
@ -7,11 +8,13 @@ export const InventoryFurnitureResultsView: FC<InventoryFurnitureResultsViewProp
|
||||
const { groupItems = [] } = props;
|
||||
|
||||
return (
|
||||
<div className="row row-cols-5 align-content-start g-0 furni-item-container">
|
||||
<div className="d-flex flex-grow-1">
|
||||
<ScrollableAreaView className="row row-cols-5 align-content-start g-0 w-100">
|
||||
{ groupItems && (groupItems.length > 0) && groupItems.map((item, index) =>
|
||||
{
|
||||
return <InventoryFurnitureItemView key={ index } groupItem={ item } />
|
||||
}) }
|
||||
</ScrollableAreaView>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { FC, useEffect, useState } from 'react';
|
||||
import { LocalizeText } from '../../../../../utils/LocalizeText';
|
||||
import { InventoryFurnitureSearchViewProps } from './InventoryFurnitureSearchView.types';
|
||||
|
||||
export const InventoryFurnitureSearchView: FC<InventoryFurnitureSearchViewProps> = props =>
|
||||
@ -31,7 +32,7 @@ export const InventoryFurnitureSearchView: FC<InventoryFurnitureSearchViewProps>
|
||||
return (
|
||||
<div className="d-flex mb-1">
|
||||
<div className="d-flex flex-grow-1 me-1">
|
||||
<input type="text" className="form-control form-control-sm" placeholder="search" value={ searchValue } onChange={ event => setSearchValue(event.target.value) } />
|
||||
<input type="text" className="form-control form-control-sm" placeholder={ LocalizeText('generic.search') } value={ searchValue } onChange={ event => setSearchValue(event.target.value) } />
|
||||
</div>
|
||||
<div className="d-flex">
|
||||
<button type="button" className="btn btn-primary btn-sm">
|
||||
|
@ -82,7 +82,7 @@ export const InventoryPetView: FC<InventoryPetViewProps> = props =>
|
||||
|
||||
return (
|
||||
<div className="row h-100">
|
||||
<div className="col-7">
|
||||
<div className="d-flex flex-column col-7">
|
||||
<InventoryPetResultsView petItems={ petItems } />
|
||||
</div>
|
||||
<div className="d-flex flex-column col-5 justify-space-between">
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { FC } from 'react';
|
||||
import { ScrollableAreaView } from '../../../../../layout/scrollable-area/ScrollableAreaView';
|
||||
import { InventoryPetItemView } from '../item/InventoryPetItemView';
|
||||
import { InventoryPetResultsViewProps } from './InventoryPetResultsView.types';
|
||||
|
||||
@ -7,11 +8,13 @@ export const InventoryPetResultsView: FC<InventoryPetResultsViewProps> = props =
|
||||
const { petItems = [] } = props;
|
||||
|
||||
return (
|
||||
<div className="row row-cols-5 align-content-start g-0 pet-item-container">
|
||||
<div className="d-flex flex-grow-1">
|
||||
<ScrollableAreaView className="row row-cols-5 align-content-start g-0 w-100">
|
||||
{ petItems && (petItems.length > 0) && petItems.map((item, index) =>
|
||||
{
|
||||
return <InventoryPetItemView key={ index } petItem={ item } />
|
||||
}) }
|
||||
</ScrollableAreaView>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ import { NavigatorSearchView } from './views/search/NavigatorSearchView';
|
||||
export const NavigatorView: FC<NavigatorViewProps> = props =>
|
||||
{
|
||||
const [ isVisible, setIsVisible ] = useState(false);
|
||||
const [ isCreatorOpen, setCreatorOpen ] = useState(false);
|
||||
const [ navigatorState, dispatchNavigatorState ] = useReducer(NavigatorReducer, initialNavigator);
|
||||
const { needsNavigatorUpdate = false, topLevelContext = null, topLevelContexts = null } = navigatorState;
|
||||
|
||||
@ -86,8 +87,15 @@ export const NavigatorView: FC<NavigatorViewProps> = props =>
|
||||
<NitroCardTabsView>
|
||||
{ topLevelContexts.map((context, index) =>
|
||||
{
|
||||
return <NitroCardTabsItemView key={ index } tabText={ LocalizeText(('navigator.toplevelview.' + context.code)) } isActive={ (topLevelContext === context) } onClick={ event => sendSearch('', context.code) } />
|
||||
return (
|
||||
<NitroCardTabsItemView key={ index } isActive={ ((topLevelContext === context) && !isCreatorOpen) } onClick={ event => sendSearch('', context.code) }>
|
||||
{ LocalizeText(('navigator.toplevelview.' + context.code)) }
|
||||
</NitroCardTabsItemView>
|
||||
);
|
||||
}) }
|
||||
<NitroCardTabsItemView>
|
||||
|
||||
</NitroCardTabsItemView>
|
||||
</NitroCardTabsView>
|
||||
<NitroCardContentView>
|
||||
<NavigatorSearchView sendSearch={ sendSearch } />
|
||||
|
@ -1,3 +1,4 @@
|
||||
@import './creator/NavigatorRoomCreatorView';
|
||||
@import './search/NavigatorSearchView';
|
||||
@import './search-result/NavigatorSearchResultView';
|
||||
@import './search-result-item/NavigatorSearchResultItemView';
|
||||
|
@ -0,0 +1,7 @@
|
||||
import { FC } from 'react';
|
||||
import { NavigatorRoomCreatorViewProps } from './NavigatorRoomCreatorView.types';
|
||||
|
||||
export const NavigatorRoomCreatorView: FC<NavigatorRoomCreatorViewProps> = props =>
|
||||
{
|
||||
return null;
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
export interface NavigatorRoomCreatorViewProps
|
||||
{
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
import { CurrencyIcon } from '../../../utils/currency-icon/CurrencyIcon';
|
||||
import { CurrencyIcon } from '../../currency-icon/CurrencyIcon';
|
||||
import { CurrencyViewProps } from './CurrencyView.types';
|
||||
|
||||
export function CurrencyView(props: CurrencyViewProps): JSX.Element
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { EventDispatcher, IEventDispatcher, IRoomSession, RoomBackgroundColorEvent, RoomEngineDimmerStateEvent, RoomEngineEvent, RoomEngineObjectEvent, RoomId, RoomObjectCategory, RoomObjectHSLColorEnabledEvent, RoomObjectOperationType, RoomSessionEvent, RoomZoomEvent } from 'nitro-renderer';
|
||||
import { useCallback, useState } from 'react';
|
||||
import { FC, useCallback, useState } from 'react';
|
||||
import { ProcessRoomObjectOperation } from '../../api/nitro/room/ProcessRoomObjectOperation';
|
||||
import { SetActiveRoomId } from '../../api/nitro/room/SetActiveRoomId';
|
||||
import { GetRoomSession } from '../../api/nitro/session/GetRoomSession';
|
||||
@ -13,7 +13,7 @@ import { RoomHostViewProps } from './RoomHostView.types';
|
||||
import { CanManipulateFurniture } from './utils/CanManipulateFurniture';
|
||||
import { IsFurnitureSelectionDisabled } from './utils/IsFurnitureSelectionDisabled';
|
||||
|
||||
export function RoomHostView(props: RoomHostViewProps): JSX.Element
|
||||
export const RoomHostView: FC<RoomHostViewProps> = props =>
|
||||
{
|
||||
const [ roomSession, setRoomSession ] = useState<IRoomSession>(null);
|
||||
const [ eventDispatcher, setEventDispatcher ] = useState<IEventDispatcher>(null);
|
||||
@ -40,7 +40,7 @@ export function RoomHostView(props: RoomHostViewProps): JSX.Element
|
||||
|
||||
const onRoomEngineObjectEvent = useCallback((event: RoomEngineObjectEvent) =>
|
||||
{
|
||||
if(!eventDispatcher) return;
|
||||
if(!roomSession || !eventDispatcher) return;
|
||||
|
||||
const objectId = event.objectId;
|
||||
const category = event.category;
|
||||
@ -101,6 +101,10 @@ export function RoomHostView(props: RoomHostViewProps): JSX.Element
|
||||
case RoomEngineObjectEvent.REQUEST_ROTATE:
|
||||
if(CanManipulateFurniture(roomSession, objectId, category)) ProcessRoomObjectOperation(objectId, category, RoomObjectOperationType.OBJECT_ROTATE_POSITIVE);
|
||||
break;
|
||||
case RoomEngineObjectEvent.REQUEST_MANIPULATION:
|
||||
console.log('yaaa')
|
||||
if(CanManipulateFurniture(roomSession, objectId, category)) updateEvent = new RoomWidgetRoomObjectUpdateEvent(RoomWidgetRoomObjectUpdateEvent.OBJECT_REQUEST_MANIPULATION, objectId, category, event.roomId);
|
||||
break;
|
||||
}
|
||||
|
||||
if(updateEvent)
|
||||
@ -152,6 +156,7 @@ export function RoomHostView(props: RoomHostViewProps): JSX.Element
|
||||
useRoomEngineEvent(RoomEngineObjectEvent.PLACED, onRoomEngineObjectEvent);
|
||||
useRoomEngineEvent(RoomEngineObjectEvent.REQUEST_MOVE, onRoomEngineObjectEvent);
|
||||
useRoomEngineEvent(RoomEngineObjectEvent.REQUEST_ROTATE, onRoomEngineObjectEvent);
|
||||
useRoomEngineEvent(RoomEngineObjectEvent.REQUEST_MANIPULATION, onRoomEngineObjectEvent);
|
||||
useRoomEngineEvent(RoomEngineObjectEvent.MOUSE_ENTER, onRoomEngineObjectEvent);
|
||||
useRoomEngineEvent(RoomEngineObjectEvent.MOUSE_LEAVE, onRoomEngineObjectEvent);
|
||||
|
||||
|
@ -1 +1 @@
|
||||
@import './widgets/Widgets';
|
||||
@import './widgets/RoomWidgets';
|
||||
|
@ -6,6 +6,7 @@ import { WindowResizeEvent } from '../../api/nitro/room/DispatchResizeEvent';
|
||||
import { DispatchTouchEvent } from '../../api/nitro/room/DispatchTouchEvent';
|
||||
import { GetRoomEngine } from '../../api/nitro/room/GetRoomEngine';
|
||||
import { RoomViewProps } from './RoomView.types';
|
||||
import { AvatarInfoWidgetView } from './widgets/avatar-info/AvatarInfoWidgetView';
|
||||
import { ChatInputView } from './widgets/chat-input/ChatInputView';
|
||||
import { ChatWidgetView } from './widgets/chat/ChatWidgetView';
|
||||
import { FurnitureWidgetsView } from './widgets/furniture/FurnitureWidgetsView';
|
||||
@ -90,9 +91,10 @@ export function RoomView(props: RoomViewProps): JSX.Element
|
||||
{ roomSession && events && roomCanvas &&
|
||||
createPortal(props.children, document.getElementById('room-view').appendChild(roomCanvas)) &&
|
||||
<>
|
||||
<AvatarInfoWidgetView events={ events } />
|
||||
<ChatWidgetView />
|
||||
<ChatInputView />
|
||||
<FurnitureWidgetsView events={ events } />
|
||||
<ChatWidgetView />
|
||||
</> }
|
||||
</div>
|
||||
);
|
||||
|
6
src/views/room/widgets/RoomWidgets.types.ts
Normal file
6
src/views/room/widgets/RoomWidgets.types.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import { IEventDispatcher } from 'nitro-renderer';
|
||||
|
||||
export interface RoomWidgetProps
|
||||
{
|
||||
events: IEventDispatcher;
|
||||
}
|
91
src/views/room/widgets/avatar-info/AvatarInfoWidgetView.tsx
Normal file
91
src/views/room/widgets/avatar-info/AvatarInfoWidgetView.tsx
Normal file
@ -0,0 +1,91 @@
|
||||
import { IFurnitureData, RoomObjectCategory, RoomObjectVariable } from 'nitro-renderer';
|
||||
import { FC, useCallback } from 'react';
|
||||
import { GetRoomEngine, GetRoomSession, GetSessionDataManager } from '../../../../api';
|
||||
import { CreateEventDispatcherHook } from '../../../../hooks/events/event-dispatcher.base';
|
||||
import { RoomObjectNameEvent, RoomWidgetRoomObjectUpdateEvent } from '../events';
|
||||
import { AvatarInfoWidgetViewProps } from './AvatarInfoWidgetView.types';
|
||||
|
||||
export const AvatarInfoWidgetView: FC<AvatarInfoWidgetViewProps> = props =>
|
||||
{
|
||||
const { events = null } = props;
|
||||
|
||||
const processObjectName = useCallback((roomId: number, objectId: number, category: number) =>
|
||||
{
|
||||
let id = -1;
|
||||
let name: string = null;
|
||||
let type = 0;
|
||||
let roomIndex = 0;
|
||||
|
||||
switch(category)
|
||||
{
|
||||
case RoomObjectCategory.FLOOR:
|
||||
case RoomObjectCategory.WALL:
|
||||
const roomObject = GetRoomEngine().getRoomObject(roomId, id, category);
|
||||
|
||||
if(!roomObject) return;
|
||||
|
||||
if(roomObject.type.indexOf('poster') === 0)
|
||||
{
|
||||
name = ('${poster_' + parseInt(roomObject.type.replace('poster', '')) + '_name}');
|
||||
roomIndex = roomObject.id;
|
||||
}
|
||||
else
|
||||
{
|
||||
let furniData: IFurnitureData = null;
|
||||
|
||||
const typeId = roomObject.model.getValue<number>(RoomObjectVariable.FURNITURE_TYPE_ID);
|
||||
|
||||
if(category === RoomObjectCategory.FLOOR)
|
||||
{
|
||||
furniData = GetSessionDataManager().getFloorItemData(typeId);
|
||||
}
|
||||
|
||||
else if(category === RoomObjectCategory.WALL)
|
||||
{
|
||||
furniData = GetSessionDataManager().getWallItemData(typeId);
|
||||
}
|
||||
|
||||
if(!furniData) return;
|
||||
|
||||
id = furniData.id;
|
||||
name = furniData.name;
|
||||
roomIndex = roomObject.id;
|
||||
}
|
||||
break;
|
||||
case RoomObjectCategory.UNIT:
|
||||
const userData = GetRoomSession().userDataManager.getUserDataByIndex(id);
|
||||
|
||||
if(!userData) return;
|
||||
|
||||
id = userData.webID;
|
||||
name = userData.name;
|
||||
type = userData.type;
|
||||
roomIndex = userData.roomIndex;
|
||||
break;
|
||||
}
|
||||
|
||||
if(!name) return;
|
||||
|
||||
events.dispatchEvent(new RoomObjectNameEvent(id, category, name, type, roomIndex));
|
||||
}, [ events ]);
|
||||
|
||||
const onRoomWidgetRoomObjectUpdateEvent = useCallback((event: RoomWidgetRoomObjectUpdateEvent) =>
|
||||
{
|
||||
switch(event.type)
|
||||
{
|
||||
case RoomWidgetRoomObjectUpdateEvent.OBJECT_ROLL_OVER: {
|
||||
processObjectName(event.roomId, event.id, event.category);
|
||||
return;
|
||||
}
|
||||
case RoomWidgetRoomObjectUpdateEvent.OBJECT_ROLL_OUT: {
|
||||
console.log('out');
|
||||
return;
|
||||
}
|
||||
}
|
||||
}, []);
|
||||
|
||||
CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.OBJECT_ROLL_OVER, events, onRoomWidgetRoomObjectUpdateEvent);
|
||||
CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.OBJECT_ROLL_OUT, events, onRoomWidgetRoomObjectUpdateEvent);
|
||||
|
||||
return null;
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
import { RoomWidgetProps } from '../RoomWidgets.types';
|
||||
|
||||
export interface AvatarInfoWidgetViewProps extends RoomWidgetProps
|
||||
{}
|
@ -13,19 +13,19 @@ export function ChatWidgetView(props: ChatWidgetViewProps): JSX.Element
|
||||
const [ chatMessages, setChatMessages ] = useState<ChatBubbleMessage[]>([]);
|
||||
const elementRef = useRef<HTMLDivElement>();
|
||||
|
||||
const removeLastHiddenChat = useCallback(() =>
|
||||
const removeFirstHiddenChat = useCallback(() =>
|
||||
{
|
||||
if(!chatMessages.length) return;
|
||||
|
||||
const lastChat = chatMessages[chatMessages.length - 1];
|
||||
const lastChat = chatMessages[0];
|
||||
|
||||
if((lastChat.lastTop > -(lastChat.height))) return;
|
||||
if((lastChat.lastTop > (-(lastChat.height) * 2))) return;
|
||||
|
||||
setChatMessages(prevValue =>
|
||||
{
|
||||
const newMessages = [ ...prevValue ];
|
||||
|
||||
newMessages.splice((newMessages.length - 1), 1);
|
||||
newMessages.shift();
|
||||
|
||||
return newMessages;
|
||||
});
|
||||
@ -33,42 +33,33 @@ export function ChatWidgetView(props: ChatWidgetViewProps): JSX.Element
|
||||
|
||||
const moveChatUp = useCallback((chat: ChatBubbleMessage, amount: number) =>
|
||||
{
|
||||
if(!chat.elementRef) return;
|
||||
chat.lastTop -= amount;
|
||||
|
||||
let y = chat.elementRef.offsetHeight;
|
||||
|
||||
if(amount > 0) y = amount;
|
||||
|
||||
let top = (chat.elementRef.offsetTop - y);
|
||||
|
||||
chat.lastTop = top;
|
||||
chat.elementRef.style.top = (top + 'px');
|
||||
if(chat.elementRef) chat.elementRef.style.top = (chat.lastTop + 'px');
|
||||
}, []);
|
||||
|
||||
const moveAllChatsUp = useCallback((amount: number) =>
|
||||
{
|
||||
chatMessages.forEach(chat => moveChatUp(chat, amount));
|
||||
}, [ chatMessages, moveChatUp ]);
|
||||
|
||||
const makeRoom = useCallback((amount: number = 0, skipLast: boolean = false) =>
|
||||
removeFirstHiddenChat();
|
||||
}, [ chatMessages, moveChatUp, removeFirstHiddenChat ]);
|
||||
|
||||
const makeRoom = useCallback((chat: ChatBubbleMessage) =>
|
||||
{
|
||||
const lastChat = chatMessages[chatMessages.length - 1];
|
||||
|
||||
if(!lastChat) return;
|
||||
|
||||
const lowestPoint = ((lastChat.lastTop + lastChat.height) - 1);
|
||||
const requiredSpace = ((amount || lastChat.height) + 1);
|
||||
const lowestPoint = ((chat.lastTop + chat.height) - 1);
|
||||
const requiredSpace = (chat.height + 1);
|
||||
const spaceAvailable = (elementRef.current.offsetHeight - lowestPoint);
|
||||
|
||||
if(spaceAvailable < requiredSpace)
|
||||
{
|
||||
amount = (requiredSpace - spaceAvailable);
|
||||
const amount = (requiredSpace - spaceAvailable);
|
||||
|
||||
chatMessages.forEach((chat, index) =>
|
||||
chatMessages.forEach((existingChat, index) =>
|
||||
{
|
||||
if(skipLast && (index === (chatMessages.length - 1))) return;
|
||||
if(existingChat === chat) return;
|
||||
|
||||
moveChatUp(chat, amount)
|
||||
moveChatUp(existingChat, amount)
|
||||
});
|
||||
}
|
||||
}, [ chatMessages, moveChatUp ]);
|
||||
@ -146,25 +137,25 @@ export function ChatWidgetView(props: ChatWidgetViewProps): JSX.Element
|
||||
|
||||
useRoomSessionManagerEvent(RoomSessionChatEvent.CHAT_EVENT, onRoomSessionChatEvent);
|
||||
|
||||
// useEffect(() =>
|
||||
// {
|
||||
// const interval = setInterval(() => moveAllChatsUp(15), 500);
|
||||
|
||||
// return () =>
|
||||
// {
|
||||
// if(interval) clearInterval(interval);
|
||||
// }
|
||||
// }, [ chatMessages, moveAllChatsUp ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
const interval = setInterval(() => moveAllChatsUp(15), 500);
|
||||
const interval = setInterval(() => removeFirstHiddenChat(), 1000);
|
||||
|
||||
return () =>
|
||||
{
|
||||
if(interval) clearInterval(interval);
|
||||
}
|
||||
}, [ chatMessages, moveAllChatsUp ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
const interval = setInterval(() => removeLastHiddenChat(), 500);
|
||||
|
||||
return () =>
|
||||
{
|
||||
if(interval) clearInterval(interval);
|
||||
}
|
||||
}, [ removeLastHiddenChat ]);
|
||||
}, [ removeFirstHiddenChat ]);
|
||||
|
||||
return (
|
||||
<div ref={ elementRef } className="nitro-chat-widget">
|
||||
|
@ -25,8 +25,6 @@ export const ChatWidgetMessageView: FC<ChatWidgetMessageViewProps> = props =>
|
||||
chat.height = height;
|
||||
chat.elementRef = element;
|
||||
|
||||
if(isVisible || !chat) return;
|
||||
|
||||
let left = chat.lastLeft;
|
||||
let top = chat.lastTop;
|
||||
|
||||
@ -34,22 +32,27 @@ export const ChatWidgetMessageView: FC<ChatWidgetMessageViewProps> = props =>
|
||||
{
|
||||
left = (chat.location.x - (width / 2));
|
||||
top = (element.parentElement.offsetHeight - height);
|
||||
}
|
||||
|
||||
chat.lastLeft = left;
|
||||
chat.lastTop = top;
|
||||
}
|
||||
|
||||
element.style.left = (left + 'px');
|
||||
element.style.top = (top + 'px');
|
||||
|
||||
makeRoom(0, true);
|
||||
setIsVisible(true);
|
||||
if(!chat.visible)
|
||||
{
|
||||
makeRoom(chat);
|
||||
}
|
||||
|
||||
chat.visible = true;
|
||||
//setIsVisible(true);
|
||||
|
||||
return () =>
|
||||
{
|
||||
chat.elementRef = null;
|
||||
}
|
||||
}, [ isVisible, elementRef, chat, makeRoom ]);
|
||||
}, [ elementRef, isVisible, chat, makeRoom ]);
|
||||
|
||||
return (
|
||||
<div ref={ elementRef } className="bubble-container" style={ { visibility: (isVisible ? 'visible' : 'hidden') } }>
|
||||
|
@ -3,5 +3,5 @@ import { ChatBubbleMessage } from '../utils/ChatBubbleMessage';
|
||||
export interface ChatWidgetMessageViewProps
|
||||
{
|
||||
chat: ChatBubbleMessage;
|
||||
makeRoom: (amount?: number, skipLast?: boolean) => void;
|
||||
makeRoom: (chat: ChatBubbleMessage) => void;
|
||||
}
|
||||
|
@ -1,10 +0,0 @@
|
||||
import { ChatMessagesWidgetViewProps } from './ChatMessagesWidgetView.types';
|
||||
|
||||
export function ChatMessagesWidgetView(props: ChatMessagesWidgetViewProps): JSX.Element
|
||||
{
|
||||
const {} = props;
|
||||
|
||||
return (
|
||||
<></>
|
||||
);
|
||||
}
|
@ -1,2 +0,0 @@
|
||||
export interface ChatMessagesWidgetViewProps
|
||||
{}
|
@ -1,10 +0,0 @@
|
||||
import { ChatMessageWidgetViewProps } from './ChatMessageWidgetView.types';
|
||||
|
||||
export function ChatMessageWidgetView(props: ChatMessageWidgetViewProps): JSX.Element
|
||||
{
|
||||
const {} = props;
|
||||
|
||||
return (
|
||||
<></>
|
||||
);
|
||||
}
|
@ -1,2 +0,0 @@
|
||||
export interface ChatMessageWidgetViewProps
|
||||
{}
|
@ -10,6 +10,7 @@ export class ChatBubbleMessage
|
||||
public lastTop: number = 0;
|
||||
public lastLeft: number = 0;
|
||||
public elementRef: HTMLDivElement = null;
|
||||
public visible: boolean = false;
|
||||
|
||||
constructor(
|
||||
public text: string = '',
|
||||
|
@ -10,6 +10,7 @@ export class RoomWidgetRoomObjectUpdateEvent extends RoomWidgetUpdateEvent
|
||||
public static USER_ADDED: string = 'RWROUE_USER_ADDED';
|
||||
public static OBJECT_ROLL_OVER: string = 'RWROUE_OBJECT_ROLL_OVER';
|
||||
public static OBJECT_ROLL_OUT: string = 'RWROUE_OBJECT_ROLL_OUT';
|
||||
public static OBJECT_REQUEST_MANIPULATION: string = 'RWROUE_OBJECT_REQUEST_MANIPULATION';
|
||||
|
||||
private _id: number;
|
||||
private _category: number;
|
||||
|
@ -1,6 +1,4 @@
|
||||
import { IEventDispatcher } from 'nitro-renderer';
|
||||
import { RoomWidgetProps } from '../RoomWidgets.types';
|
||||
|
||||
export interface FurnitureWidgetProps
|
||||
{
|
||||
events: IEventDispatcher;
|
||||
}
|
||||
export interface FurnitureWidgetProps extends RoomWidgetProps
|
||||
{}
|
||||
|
@ -1 +1,2 @@
|
||||
@import './manipulation-menu/FurnitureManipulationMenuView';
|
||||
@import './stickie/FurnitureStickieView';
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { FurnitureWidgetsViewProps } from './FurnitureWidgetsView.types';
|
||||
import { FurnitureHighScoreView } from './high-score/FurnitureHighScoreView';
|
||||
import { FurnitureManipulationMenuView } from './manipulation-menu/FurnitureManipulationMenuView';
|
||||
import { FurnitureMannequinView } from './mannequin/FurnitureMannequinView';
|
||||
import { FurniturePresentView } from './present/FurniturePresentView';
|
||||
import { FurnitureStickieView } from './stickie/FurnitureStickieView';
|
||||
@ -11,6 +12,7 @@ export function FurnitureWidgetsView(props: FurnitureWidgetsViewProps): JSX.Elem
|
||||
return (
|
||||
<div className="position-absolute nitro-room-widgets t-0 l-0">
|
||||
<FurnitureHighScoreView events={ events } />
|
||||
<FurnitureManipulationMenuView events={ events } />
|
||||
<FurnitureMannequinView events={ events } />
|
||||
<FurniturePresentView events={ events } />
|
||||
<FurnitureStickieView events={ events } />
|
||||
|
@ -0,0 +1,71 @@
|
||||
import { RoomObjectOperationType } from 'nitro-renderer';
|
||||
import { FC, useCallback, useEffect, useState } from 'react';
|
||||
import { ProcessRoomObjectOperation } from '../../../../../api';
|
||||
import { CreateEventDispatcherHook } from '../../../../../hooks/events/event-dispatcher.base';
|
||||
import { RoomWidgetRoomObjectUpdateEvent } from '../../events';
|
||||
import { ObjectLocationView } from '../../object-location/ObjectLocationView';
|
||||
import { FurnitureManipulationMenuViewProps } from './FurnitureManipulationMenuView.types';
|
||||
|
||||
export const FurnitureManipulationMenuView: FC<FurnitureManipulationMenuViewProps> = props =>
|
||||
{
|
||||
const { events = null } = props;
|
||||
const [ isVisible, setIsVisible ] = useState(false);
|
||||
const [ objectId, setObjectId ] = useState(-1);
|
||||
const [ objectType, setObjectType ] = useState(-1);
|
||||
|
||||
const onRoomWidgetRoomObjectUpdateEvent = useCallback((event: RoomWidgetRoomObjectUpdateEvent) =>
|
||||
{
|
||||
switch(event.type)
|
||||
{
|
||||
case RoomWidgetRoomObjectUpdateEvent.OBJECT_REQUEST_MANIPULATION: {
|
||||
setIsVisible(true);
|
||||
setObjectId(event.id);
|
||||
setObjectType(event.category);
|
||||
return;
|
||||
}
|
||||
case RoomWidgetRoomObjectUpdateEvent.FURNI_REMOVED: {
|
||||
return;
|
||||
}
|
||||
case RoomWidgetRoomObjectUpdateEvent.OBJECT_DESELECTED: {
|
||||
console.log('tru')
|
||||
setIsVisible(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}, []);
|
||||
|
||||
const rotateFurniture = useCallback(() =>
|
||||
{
|
||||
ProcessRoomObjectOperation(objectId, objectType, RoomObjectOperationType.OBJECT_ROTATE_POSITIVE);
|
||||
}, [ objectId, objectType ]);
|
||||
|
||||
const moveFurniture = useCallback(() =>
|
||||
{
|
||||
ProcessRoomObjectOperation(objectId, objectType, RoomObjectOperationType.OBJECT_MOVE);
|
||||
}, [ objectId, objectType ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if(!isVisible) return;
|
||||
|
||||
moveFurniture();
|
||||
}, [ isVisible, moveFurniture ]);
|
||||
|
||||
CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.OBJECT_REQUEST_MANIPULATION, events, onRoomWidgetRoomObjectUpdateEvent);
|
||||
CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.OBJECT_DESELECTED, events, onRoomWidgetRoomObjectUpdateEvent);
|
||||
|
||||
if(!isVisible) return null;
|
||||
|
||||
return (
|
||||
<ObjectLocationView objectId={ objectId } objectType={ objectType }>
|
||||
<div className="btn-group">
|
||||
<button type="button" className="btn btn-primary btn-sm">
|
||||
<i className="fas fa-times" />
|
||||
</button>
|
||||
<button type="button" className="btn btn-primary btn-sm" onClick={ rotateFurniture }>
|
||||
<i className="fas fa-undo" />
|
||||
</button>
|
||||
</div>
|
||||
</ObjectLocationView>
|
||||
);
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
import { FurnitureWidgetProps } from '../FurnitureWidget.types';
|
||||
|
||||
export interface FurnitureManipulationMenuViewProps extends FurnitureWidgetProps
|
||||
{
|
||||
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
import { Nitro } from 'nitro-renderer';
|
||||
import { FC, useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { GetRoomEngine, GetRoomSession } from '../../../../api';
|
||||
import { ObjectLocationViewProps } from './ObjectLocationView.types';
|
||||
|
||||
export const ObjectLocationView: FC<ObjectLocationViewProps> = props =>
|
||||
{
|
||||
const { objectId = -1, objectType = -1, children = null } = props;
|
||||
const [ posX, setPosX ] = useState(0);
|
||||
const [ posY, setPosY ] = useState(0);
|
||||
const elementRef = useRef<HTMLDivElement>();
|
||||
|
||||
const updatePosition = useCallback(() =>
|
||||
{
|
||||
const roomSession = GetRoomSession();
|
||||
const objectBounds = GetRoomEngine().getRoomObjectBoundingRectangle(roomSession.roomId, objectId, objectType, 1);
|
||||
|
||||
if(!objectBounds) return;
|
||||
|
||||
setPosX(Math.round(((objectBounds.left + (objectBounds.width / 2)) - (elementRef.current.offsetWidth / 2))));
|
||||
setPosY(Math.round((objectBounds.top - elementRef.current.offsetHeight) + 10));
|
||||
}, [ objectId, objectType ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
Nitro.instance.ticker.add(updatePosition);
|
||||
|
||||
return () =>
|
||||
{
|
||||
Nitro.instance.ticker.remove(updatePosition);
|
||||
}
|
||||
}, [ updatePosition ]);
|
||||
|
||||
return (
|
||||
<div ref={ elementRef } className="position-absolute w-100" style={ { left: posX, top: posY } }>
|
||||
{ children }
|
||||
</div>
|
||||
);
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
export interface ObjectLocationViewProps
|
||||
{
|
||||
objectId: number;
|
||||
objectType: number;
|
||||
}
|
Loading…
Reference in New Issue
Block a user