diff --git a/src/App.tsx b/src/App.tsx index eb7bb5df..9a1421c7 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,6 +1,6 @@ import { ConfigurationEvent, LegacyExternalInterface, Nitro, NitroCommunicationDemoEvent, NitroEvent, NitroLocalizationEvent, RoomEngineEvent, WebGL } from 'nitro-renderer'; import { FC, useCallback, useState } from 'react'; -import { GetConfiguration } from './api'; +import { GetCommunication, GetConfiguration, GetNitroInstance } from './api'; import { useConfigurationEvent } from './hooks/events/core/configuration/configuration-event'; import { useLocalizationEvent } from './hooks/events/nitro/localization/localization-event'; import { dispatchMainEvent, useMainEvent } from './hooks/events/nitro/main-event'; @@ -19,7 +19,7 @@ export const App: FC<{}> = props => //@ts-ignore if(!NitroConfig) throw new Error('NitroConfig is not defined!'); - if(!Nitro.instance) Nitro.bootstrap(); + if(!GetNitroInstance()) Nitro.bootstrap(); const getPreloadAssetUrls = useCallback(() => { @@ -28,7 +28,7 @@ export const App: FC<{}> = props => if(assetUrls && assetUrls.length) { - for(const url of assetUrls) urls.push(Nitro.instance.core.configuration.interpolate(url)); + for(const url of assetUrls) urls.push(GetNitroInstance().core.configuration.interpolate(url)); } return urls; @@ -39,7 +39,7 @@ export const App: FC<{}> = props => switch(event.type) { case ConfigurationEvent.LOADED: - Nitro.instance.localization.init(); + GetNitroInstance().localization.init(); return; case ConfigurationEvent.FAILED: setIsError(true); @@ -73,14 +73,14 @@ export const App: FC<{}> = props => case NitroCommunicationDemoEvent.CONNECTION_AUTHENTICATED: setMessage('Finishing Up'); - Nitro.instance.init(); + GetNitroInstance().init(); return; case NitroCommunicationDemoEvent.CONNECTION_ERROR: setIsError(true); setMessage('Connection Error'); return; case NitroCommunicationDemoEvent.CONNECTION_CLOSED: - if(Nitro.instance.roomEngine) Nitro.instance.roomEngine.dispose(); + if(GetNitroInstance().roomEngine) GetNitroInstance().roomEngine.dispose(); setIsError(true); setMessage('Connection Error'); @@ -91,13 +91,13 @@ export const App: FC<{}> = props => setIsReady(true); return; case NitroLocalizationEvent.LOADED: - Nitro.instance.core.asset.downloadAssets(getPreloadAssetUrls(), (status: boolean) => + GetNitroInstance().core.asset.downloadAssets(getPreloadAssetUrls(), (status: boolean) => { if(status) { setMessage('Connecting'); - Nitro.instance.communication.init(); + GetCommunication().init(); } else { @@ -127,7 +127,7 @@ export const App: FC<{}> = props => } else { - Nitro.instance.core.configuration.init(); + GetNitroInstance().core.configuration.init(); } return ( diff --git a/src/api/catalog/GetCatalogPageComposer.ts b/src/api/catalog/GetCatalogPageComposer.ts deleted file mode 100644 index 685112a8..00000000 --- a/src/api/catalog/GetCatalogPageComposer.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { CatalogPageComposer } from 'nitro-renderer'; - -export function GetCatalogPageComposer(...args: ConstructorParameters): CatalogPageComposer -{ - return new CatalogPageComposer(...args); -} diff --git a/src/api/core/GetConfigurationManager.ts b/src/api/core/GetConfigurationManager.ts new file mode 100644 index 00000000..f974b328 --- /dev/null +++ b/src/api/core/GetConfigurationManager.ts @@ -0,0 +1,7 @@ +import { IConfigurationManager } from 'nitro-renderer'; +import { GetNitroCore } from './GetNitroCore'; + +export function GetConfigurationManager(): IConfigurationManager +{ + return GetNitroCore().configuration; +} diff --git a/src/api/core/GetNitroCore.ts b/src/api/core/GetNitroCore.ts new file mode 100644 index 00000000..4972ef2d --- /dev/null +++ b/src/api/core/GetNitroCore.ts @@ -0,0 +1,7 @@ +import { INitroCore } from 'nitro-renderer'; +import { GetNitroInstance } from '../nitro'; + +export function GetNitroCore(): INitroCore +{ + return GetNitroInstance().core; +} diff --git a/src/api/core/index.ts b/src/api/core/index.ts new file mode 100644 index 00000000..3322c9cb --- /dev/null +++ b/src/api/core/index.ts @@ -0,0 +1,2 @@ +export * from './GetConfigurationManager'; +export * from './GetNitroCore'; diff --git a/src/api/index.ts b/src/api/index.ts index 85f5a489..e935bf12 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -1 +1,2 @@ +export * from './core'; export * from './nitro'; diff --git a/src/api/nitro/AddLinkEventTracker.ts b/src/api/nitro/AddLinkEventTracker.ts new file mode 100644 index 00000000..df1667de --- /dev/null +++ b/src/api/nitro/AddLinkEventTracker.ts @@ -0,0 +1,7 @@ +import { ILinkEventTracker } from 'nitro-renderer'; +import { GetNitroInstance } from './GetNitroInstance'; + +export function AddEventLinkTracker(tracker: ILinkEventTracker): void +{ + GetNitroInstance().addLinkEventTracker(tracker); +} diff --git a/src/api/nitro/GetCommunication.ts b/src/api/nitro/GetCommunication.ts new file mode 100644 index 00000000..696104fa --- /dev/null +++ b/src/api/nitro/GetCommunication.ts @@ -0,0 +1,7 @@ +import { INitroCommunicationManager } from 'nitro-renderer'; +import { GetNitroInstance } from './GetNitroInstance'; + +export function GetCommunication(): INitroCommunicationManager +{ + return GetNitroInstance().communication; +} diff --git a/src/api/nitro/GetConfiguration.ts b/src/api/nitro/GetConfiguration.ts index a70a82f2..2676d53f 100644 --- a/src/api/nitro/GetConfiguration.ts +++ b/src/api/nitro/GetConfiguration.ts @@ -1,6 +1,6 @@ -import { Nitro } from 'nitro-renderer'; +import { GetNitroInstance } from './GetNitroInstance'; export function GetConfiguration(key: string, value: T = null): T { - return Nitro.instance.getConfiguration(key, value); + return GetNitroInstance().getConfiguration(key, value); } diff --git a/src/api/nitro/GetConnection.ts b/src/api/nitro/GetConnection.ts index 03c13354..bf924a26 100644 --- a/src/api/nitro/GetConnection.ts +++ b/src/api/nitro/GetConnection.ts @@ -1,6 +1,7 @@ -import { IConnection, Nitro } from 'nitro-renderer'; +import { IConnection } from 'nitro-renderer'; +import { GetCommunication } from './GetCommunication'; export function GetConnection(): IConnection { - return Nitro.instance.communication.connection; + return GetCommunication().connection; } diff --git a/src/api/nitro/GetNitroInstance.ts b/src/api/nitro/GetNitroInstance.ts new file mode 100644 index 00000000..17735012 --- /dev/null +++ b/src/api/nitro/GetNitroInstance.ts @@ -0,0 +1,6 @@ +import { INitro, Nitro } from 'nitro-renderer'; + +export function GetNitroInstance(): INitro +{ + return Nitro.instance; +} diff --git a/src/api/nitro/GetTicker.ts b/src/api/nitro/GetTicker.ts index eaab9664..9d02551f 100644 --- a/src/api/nitro/GetTicker.ts +++ b/src/api/nitro/GetTicker.ts @@ -1,6 +1,6 @@ -import { Nitro } from 'nitro-renderer'; +import { GetNitroInstance } from './GetNitroInstance'; export function GetTicker() { - return Nitro.instance.ticker; + return GetNitroInstance().ticker; } diff --git a/src/api/nitro/RemoveLinkEventTracker.ts b/src/api/nitro/RemoveLinkEventTracker.ts new file mode 100644 index 00000000..8963dedc --- /dev/null +++ b/src/api/nitro/RemoveLinkEventTracker.ts @@ -0,0 +1,7 @@ +import { ILinkEventTracker } from 'nitro-renderer'; +import { GetNitroInstance } from './GetNitroInstance'; + +export function RemoveLinkEventTracker(tracker: ILinkEventTracker): void +{ + GetNitroInstance().removeLinkEventTracker(tracker); +} diff --git a/src/api/nitro/avatar/GetAvatarRenderManager.ts b/src/api/nitro/avatar/GetAvatarRenderManager.ts index c616c1a3..9f7547ab 100644 --- a/src/api/nitro/avatar/GetAvatarRenderManager.ts +++ b/src/api/nitro/avatar/GetAvatarRenderManager.ts @@ -1,6 +1,7 @@ -import { IAvatarRenderManager, Nitro } from 'nitro-renderer'; +import { IAvatarRenderManager } from 'nitro-renderer'; +import { GetNitroInstance } from '../GetNitroInstance'; export function GetAvatarRenderManager(): IAvatarRenderManager { - return Nitro.instance.avatar; + return GetNitroInstance().avatar; } diff --git a/src/api/nitro/camera/GetRoomCameraWidgetManager.ts b/src/api/nitro/camera/GetRoomCameraWidgetManager.ts index ca3e498f..90bfc45c 100644 --- a/src/api/nitro/camera/GetRoomCameraWidgetManager.ts +++ b/src/api/nitro/camera/GetRoomCameraWidgetManager.ts @@ -1,7 +1,7 @@ -import { Nitro } from 'nitro-renderer'; import { IRoomCameraWidgetManager } from 'nitro-renderer/src/nitro/camera/IRoomCameraWidgetManager'; +import { GetNitroInstance } from '../GetNitroInstance'; export function GetRoomCameraWidgetManager(): IRoomCameraWidgetManager { - return Nitro.instance.cameraManager; + return GetNitroInstance().cameraManager; } diff --git a/src/api/nitro/index.ts b/src/api/nitro/index.ts index 4c46e69f..3cc66155 100644 --- a/src/api/nitro/index.ts +++ b/src/api/nitro/index.ts @@ -1,7 +1,11 @@ +export * from './AddLinkEventTracker'; export * from './avatar'; export * from './camera'; +export * from './GetCommunication'; export * from './GetConfiguration'; export * from './GetConnection'; +export * from './GetNitroInstance'; export * from './GetTicker'; +export * from './RemoveLinkEventTracker'; export * from './room'; export * from './session'; diff --git a/src/api/nitro/room/GetRoomEngine.ts b/src/api/nitro/room/GetRoomEngine.ts index 153ab4a1..58ae4421 100644 --- a/src/api/nitro/room/GetRoomEngine.ts +++ b/src/api/nitro/room/GetRoomEngine.ts @@ -1,6 +1,7 @@ -import { IRoomEngine, Nitro } from 'nitro-renderer'; +import { IRoomEngine } from 'nitro-renderer'; +import { GetNitroInstance } from '../GetNitroInstance'; export function GetRoomEngine(): IRoomEngine { - return Nitro.instance.roomEngine; + return GetNitroInstance().roomEngine; } diff --git a/src/api/nitro/session/GetRoomSessionManager.ts b/src/api/nitro/session/GetRoomSessionManager.ts index cdba1b0e..830ba177 100644 --- a/src/api/nitro/session/GetRoomSessionManager.ts +++ b/src/api/nitro/session/GetRoomSessionManager.ts @@ -1,6 +1,7 @@ -import { IRoomSessionManager, Nitro } from 'nitro-renderer'; +import { IRoomSessionManager } from 'nitro-renderer'; +import { GetNitroInstance } from '../GetNitroInstance'; export function GetRoomSessionManager(): IRoomSessionManager { - return Nitro.instance.roomSessionManager; + return GetNitroInstance().roomSessionManager; } diff --git a/src/api/nitro/session/GetSessionDataManager.ts b/src/api/nitro/session/GetSessionDataManager.ts index d31e1a0c..6af8c5c7 100644 --- a/src/api/nitro/session/GetSessionDataManager.ts +++ b/src/api/nitro/session/GetSessionDataManager.ts @@ -1,6 +1,7 @@ -import { ISessionDataManager, Nitro } from 'nitro-renderer'; +import { ISessionDataManager } from 'nitro-renderer'; +import { GetNitroInstance } from '../GetNitroInstance'; export function GetSessionDataManager(): ISessionDataManager { - return Nitro.instance.sessionDataManager; + return GetNitroInstance().sessionDataManager; } diff --git a/src/assets/styles/bootstrap/_variables.scss b/src/assets/styles/bootstrap/_variables.scss index 0fd0eeb4..48937b78 100644 --- a/src/assets/styles/bootstrap/_variables.scss +++ b/src/assets/styles/bootstrap/_variables.scss @@ -81,7 +81,8 @@ $cello-dark: #1e465e !default; $pale-sky: #677181 !default; $oslo-gray: #8F9297 !default; $gainsboro: #d9d9d9 !default; - +$ghost: #c8cad0 !default; +$gray-chateau: #a3a7b1 !default; $success: $green !default; $info: $cyan !default; $warning: $yellow !default; diff --git a/src/events/inventory/InventoryBadgesRequestEvent.ts b/src/events/inventory/InventoryBadgesRequestEvent.ts new file mode 100644 index 00000000..18683834 --- /dev/null +++ b/src/events/inventory/InventoryBadgesRequestEvent.ts @@ -0,0 +1,6 @@ +import { NitroEvent } from 'nitro-renderer'; + +export class InventoryBadgesRequestEvent extends NitroEvent +{ + public static REQUEST_BADGES: string = 'IBRE_REQUEST_BADGES'; +} diff --git a/src/events/inventory/InventoryBadgesUpdatedEvent.ts b/src/events/inventory/InventoryBadgesUpdatedEvent.ts new file mode 100644 index 00000000..0b5d2220 --- /dev/null +++ b/src/events/inventory/InventoryBadgesUpdatedEvent.ts @@ -0,0 +1,20 @@ +import { NitroEvent } from 'nitro-renderer'; + +export class InventoryBadgesUpdatedEvent extends NitroEvent +{ + public static BADGES_UPDATED: string = 'IBUE_BADGES_UPDATED'; + + private _badges: string[] = []; + + constructor(type: string, badges: string[] = []) + { + super(type); + + this._badges = badges; + } + + public get badges(): string[] + { + return this._badges; + } +} diff --git a/src/events/inventory/index.ts b/src/events/inventory/index.ts index 2b21bce9..90a8cd46 100644 --- a/src/events/inventory/index.ts +++ b/src/events/inventory/index.ts @@ -1,3 +1,4 @@ +export * from './InventoryBadgesUpdatedEvent'; export * from './InventoryEvent'; export * from './InventoryTradeRequestEvent'; export * from './InventoryTradeStartEvent'; diff --git a/src/hooks/events/nitro/communication/communication-event.tsx b/src/hooks/events/core/communication/communication-event.tsx similarity index 61% rename from src/hooks/events/nitro/communication/communication-event.tsx rename to src/hooks/events/core/communication/communication-event.tsx index 9049dcea..c9bcdd65 100644 --- a/src/hooks/events/nitro/communication/communication-event.tsx +++ b/src/hooks/events/core/communication/communication-event.tsx @@ -1,8 +1,8 @@ import { NitroEvent } from 'nitro-renderer'; -import { Nitro } from 'nitro-renderer/src/nitro/Nitro'; +import { GetCommunication } from '../../../../api'; import { CreateEventDispatcherHook } from '../../event-dispatcher.base'; export function useCommunicationEvent(type: string, handler: (event: NitroEvent) => void): void { - CreateEventDispatcherHook(type, Nitro.instance.communication.events, handler); + CreateEventDispatcherHook(type, GetCommunication().events, handler); } diff --git a/src/hooks/events/nitro/communication/index.ts b/src/hooks/events/core/communication/index.ts similarity index 100% rename from src/hooks/events/nitro/communication/index.ts rename to src/hooks/events/core/communication/index.ts diff --git a/src/hooks/events/core/configuration/configuration-event.tsx b/src/hooks/events/core/configuration/configuration-event.tsx index 3e117dc7..6654fa23 100644 --- a/src/hooks/events/core/configuration/configuration-event.tsx +++ b/src/hooks/events/core/configuration/configuration-event.tsx @@ -1,8 +1,8 @@ import { NitroEvent } from 'nitro-renderer'; -import { Nitro } from 'nitro-renderer/src/nitro/Nitro'; +import { GetConfigurationManager } from '../../../../api'; import { CreateEventDispatcherHook } from '../../event-dispatcher.base'; export function useConfigurationEvent(type: string, handler: (event: NitroEvent) => void): void { - CreateEventDispatcherHook(type, Nitro.instance.core.configuration.events, handler); + CreateEventDispatcherHook(type, GetConfigurationManager().events, handler); } diff --git a/src/hooks/events/core/index.ts b/src/hooks/events/core/index.ts index 75a11149..d344bc2c 100644 --- a/src/hooks/events/core/index.ts +++ b/src/hooks/events/core/index.ts @@ -1 +1,2 @@ +export * from './communication'; export * from './configuration'; diff --git a/src/hooks/events/nitro/avatar/avatar-event.tsx b/src/hooks/events/nitro/avatar/avatar-event.tsx index 2d9b065f..c41f721b 100644 --- a/src/hooks/events/nitro/avatar/avatar-event.tsx +++ b/src/hooks/events/nitro/avatar/avatar-event.tsx @@ -1,8 +1,8 @@ import { NitroEvent } from 'nitro-renderer'; -import { Nitro } from 'nitro-renderer/src/nitro/Nitro'; +import { GetAvatarRenderManager } from '../../../../api'; import { CreateEventDispatcherHook } from '../../event-dispatcher.base'; export function useAvatarEvent(type: string, handler: (event: NitroEvent) => void): void { - CreateEventDispatcherHook(type, Nitro.instance.avatar.events, handler); + CreateEventDispatcherHook(type, GetAvatarRenderManager().events, handler); } diff --git a/src/hooks/events/nitro/camera/camera-event.tsx b/src/hooks/events/nitro/camera/camera-event.tsx index 499b162f..3a8e311f 100644 --- a/src/hooks/events/nitro/camera/camera-event.tsx +++ b/src/hooks/events/nitro/camera/camera-event.tsx @@ -1,8 +1,8 @@ import { NitroEvent } from 'nitro-renderer'; -import { Nitro } from 'nitro-renderer/src/nitro/Nitro'; +import { GetNitroInstance } from '../../../../api'; import { CreateEventDispatcherHook } from '../../event-dispatcher.base'; export function useCameraEvent(type: string, handler: (event: NitroEvent) => void): void { - CreateEventDispatcherHook(type, Nitro.instance.cameraManager.events, handler); + CreateEventDispatcherHook(type, GetNitroInstance().cameraManager.events, handler); } diff --git a/src/hooks/events/nitro/index.ts b/src/hooks/events/nitro/index.ts index 8bf15d27..262c00cd 100644 --- a/src/hooks/events/nitro/index.ts +++ b/src/hooks/events/nitro/index.ts @@ -1,6 +1,5 @@ export * from './avatar'; export * from './camera'; -export * from './communication'; export * from './localization'; export * from './main-event'; export * from './room'; diff --git a/src/hooks/events/nitro/localization/localization-event.tsx b/src/hooks/events/nitro/localization/localization-event.tsx index 38d835ac..8fd273d8 100644 --- a/src/hooks/events/nitro/localization/localization-event.tsx +++ b/src/hooks/events/nitro/localization/localization-event.tsx @@ -1,8 +1,8 @@ import { NitroEvent } from 'nitro-renderer'; -import { Nitro } from 'nitro-renderer/src/nitro/Nitro'; +import { GetNitroInstance } from '../../../../api'; import { CreateEventDispatcherHook } from '../../event-dispatcher.base'; export function useLocalizationEvent(type: string, handler: (event: NitroEvent) => void): void { - CreateEventDispatcherHook(type, Nitro.instance.localization.events, handler); + CreateEventDispatcherHook(type, GetNitroInstance().localization.events, handler); } diff --git a/src/hooks/events/nitro/main-event.tsx b/src/hooks/events/nitro/main-event.tsx index da4ef70c..1266e3fd 100644 --- a/src/hooks/events/nitro/main-event.tsx +++ b/src/hooks/events/nitro/main-event.tsx @@ -1,12 +1,13 @@ -import { Nitro, NitroEvent } from 'nitro-renderer'; +import { NitroEvent } from 'nitro-renderer'; +import { GetNitroInstance } from '../../../api'; import { CreateEventDispatcherHook, DispatchEventHook } from '../event-dispatcher.base'; export function useMainEvent(type: string, handler: (event: NitroEvent) => void): void { - CreateEventDispatcherHook(type, Nitro.instance.events, handler); + CreateEventDispatcherHook(type, GetNitroInstance().events, handler); } export function dispatchMainEvent(event: NitroEvent): void { - DispatchEventHook(Nitro.instance.events, event); + DispatchEventHook(GetNitroInstance().events, event); } diff --git a/src/hooks/events/nitro/room/room-engine-event.tsx b/src/hooks/events/nitro/room/room-engine-event.tsx index c5e65d15..f4e4ce39 100644 --- a/src/hooks/events/nitro/room/room-engine-event.tsx +++ b/src/hooks/events/nitro/room/room-engine-event.tsx @@ -1,8 +1,8 @@ import { NitroEvent } from 'nitro-renderer'; -import { Nitro } from 'nitro-renderer/src/nitro/Nitro'; +import { GetRoomEngine } from '../../../../api'; import { CreateEventDispatcherHook } from '../../event-dispatcher.base'; export function useRoomEngineEvent(type: string, handler: (event: NitroEvent) => void): void { - CreateEventDispatcherHook(type, Nitro.instance.roomEngine.events, handler); + CreateEventDispatcherHook(type, GetRoomEngine().events, handler); } diff --git a/src/hooks/events/nitro/session/room-session-manager-event.tsx b/src/hooks/events/nitro/session/room-session-manager-event.tsx index 518e90df..4335a72b 100644 --- a/src/hooks/events/nitro/session/room-session-manager-event.tsx +++ b/src/hooks/events/nitro/session/room-session-manager-event.tsx @@ -1,7 +1,8 @@ -import { Nitro, NitroEvent } from 'nitro-renderer'; +import { NitroEvent } from 'nitro-renderer'; +import { GetRoomSessionManager } from '../../../../api'; import { CreateEventDispatcherHook } from '../../event-dispatcher.base'; export function useRoomSessionManagerEvent(type: string, handler: (event: NitroEvent) => void): void { - CreateEventDispatcherHook(type, Nitro.instance.roomSessionManager.events, handler); + CreateEventDispatcherHook(type, GetRoomSessionManager().events, handler); } diff --git a/src/hooks/index.ts b/src/hooks/index.ts index 41928f94..0068322f 100644 --- a/src/hooks/index.ts +++ b/src/hooks/index.ts @@ -1,13 +1,6 @@ export * from './events'; export * from './events/core'; -export * from './events/core/configuration'; export * from './events/nitro'; -export * from './events/nitro/avatar'; -export * from './events/nitro/camera'; -export * from './events/nitro/communication'; -export * from './events/nitro/localization'; -export * from './events/nitro/room'; -export * from './events/nitro/session'; export * from './events/ui'; export * from './messages'; export * from './UseMountEffect'; diff --git a/src/hooks/messages/message-event.tsx b/src/hooks/messages/message-event.tsx index d81ab22d..c530586c 100644 --- a/src/hooks/messages/message-event.tsx +++ b/src/hooks/messages/message-event.tsx @@ -1,6 +1,6 @@ import { IMessageComposer, IMessageEvent, MessageEvent } from 'nitro-renderer'; -import { Nitro } from 'nitro-renderer/src/nitro/Nitro'; import { useEffect } from 'react'; +import { GetCommunication, GetConnection } from '../../api'; export function CreateMessageHook(eventType: typeof MessageEvent, handler: (event: IMessageEvent) => void): void { @@ -9,13 +9,13 @@ export function CreateMessageHook(eventType: typeof MessageEvent, handler: (even //@ts-ignore const event = new eventType(handler); - Nitro.instance.communication.registerMessageEvent(event); + GetCommunication().registerMessageEvent(event); - return () => Nitro.instance.communication.removeMessageEvent(event); + return () => GetCommunication().removeMessageEvent(event); }, [ eventType, handler ]); } export function SendMessageHook(event: IMessageComposer): void { - Nitro.instance.communication.connection.send(event); + GetConnection().send(event); } diff --git a/src/layout/card/grid/item/NitroCardGridItemView.scss b/src/layout/card/grid/item/NitroCardGridItemView.scss index 69de83c1..b2959864 100644 --- a/src/layout/card/grid/item/NitroCardGridItemView.scss +++ b/src/layout/card/grid/item/NitroCardGridItemView.scss @@ -64,11 +64,9 @@ } .avatar-image { - width: 100% !important; - height: 100% !important; background-position: center; background-repeat: no-repeat; - background-position-y: -32px !important; + background-position-y: 12px !important; } .trade-button { diff --git a/src/utils/LocalizeBageName.ts b/src/utils/LocalizeBageName.ts index cb5e6ef2..ad579262 100644 --- a/src/utils/LocalizeBageName.ts +++ b/src/utils/LocalizeBageName.ts @@ -1,6 +1,6 @@ -import { Nitro } from 'nitro-renderer'; +import { GetNitroInstance } from '../api'; export function LocalizeBadgeName(key: string): string { - return Nitro.instance.localization.getBadgeName(key); + return GetNitroInstance().localization.getBadgeName(key); } diff --git a/src/utils/LocalizeText.ts b/src/utils/LocalizeText.ts index defa078f..ed3c8b18 100644 --- a/src/utils/LocalizeText.ts +++ b/src/utils/LocalizeText.ts @@ -1,6 +1,6 @@ -import { Nitro } from 'nitro-renderer'; +import { GetNitroInstance } from '../api'; export function LocalizeText(key: string, parameters: string[] = null, replacements: string[] = null): string { - return Nitro.instance.getLocalizationWithParameters(key, parameters, replacements); + return GetNitroInstance().getLocalizationWithParameters(key, parameters, replacements); } diff --git a/src/views/avatar-editor/AvatarEditorView.scss b/src/views/avatar-editor/AvatarEditorView.scss index c17999bb..8c2f6b0d 100644 --- a/src/views/avatar-editor/AvatarEditorView.scss +++ b/src/views/avatar-editor/AvatarEditorView.scss @@ -83,8 +83,36 @@ .wardrobe-grid { .grid-item-container { - height: 100% !important; - max-height: 100% !important; + height: 142px !important; + max-height: 142px !important; + + .grid-item { + background-color: $ghost; + + .avatar-image { + position: absolute; + bottom: 0; + background-position-y: -23px !important; + z-index: 3; + } + + .figure-button-container { + background-color: $gray-chateau; + z-index: 2; + } + + &:after { + position: absolute; + content: ''; + height: 50%; + bottom: 0; + left: 0; + right: 0; + background-color: $gray-chateau; + box-shadow: 0 0 8px 2px rgba($white,.6); + z-index: 1; + } + } } } } diff --git a/src/views/avatar-editor/AvatarEditorView.tsx b/src/views/avatar-editor/AvatarEditorView.tsx index 378d53e4..35cadc42 100644 --- a/src/views/avatar-editor/AvatarEditorView.tsx +++ b/src/views/avatar-editor/AvatarEditorView.tsx @@ -79,12 +79,20 @@ export const AvatarEditorView: FC = props => const onUserWardrobePageEvent = useCallback((event: UserWardrobePageEvent) => { const parser = event.getParser(); + const savedFigures: [ string, string ][] = []; - const savedFigures: [ string, string ][] = new Array(MAX_SAVED_FIGURES); + let i = 0; - for(const value of parser.looks.values()) + while(i < MAX_SAVED_FIGURES) { - console.log(value); + savedFigures.push([ null, null ]); + + i++; + } + + for(let [ index, value ] of parser.looks.entries()) + { + savedFigures[(index - 1)] = [ value[0], value[1] ]; } setSavedFigures(savedFigures) @@ -280,7 +288,7 @@ export const AvatarEditorView: FC = props =>
{ (activeCategory && !isWardrobeVisible) && } - { isWardrobeVisible && } + { isWardrobeVisible && }
diff --git a/src/views/avatar-editor/common/AvatarEditorUtilities.ts b/src/views/avatar-editor/common/AvatarEditorUtilities.ts index 224ce1f7..2977a315 100644 --- a/src/views/avatar-editor/common/AvatarEditorUtilities.ts +++ b/src/views/avatar-editor/common/AvatarEditorUtilities.ts @@ -162,7 +162,7 @@ export class AvatarEditorUtilities partItems.sort(this.clubItemsFirst ? this.clubSorter : this.noobSorter); - // if(this._forceSellableClothingVisibility || Nitro.instance.getConfiguration("avatareditor.support.sellablefurni", false)) + // if(this._forceSellableClothingVisibility || GetNitroInstance().getConfiguration("avatareditor.support.sellablefurni", false)) // { // _local_31 = (this._manager.windowManager.assets.getAssetByName("camera_zoom_in") as BitmapDataAsset); // _local_32 = (_local_31.content as BitmapData).clone(); diff --git a/src/views/avatar-editor/common/FigureData.ts b/src/views/avatar-editor/common/FigureData.ts index d186b4c0..51744a4e 100644 --- a/src/views/avatar-editor/common/FigureData.ts +++ b/src/views/avatar-editor/common/FigureData.ts @@ -206,7 +206,7 @@ export class FigureData { const colors = this._colors.get(setType); - if(colors === undefined) continue; + if(!colors) continue; let setId = this._data.get(setType); diff --git a/src/views/avatar-editor/views/wardrobe/AvatarEditorWardrobeView.tsx b/src/views/avatar-editor/views/wardrobe/AvatarEditorWardrobeView.tsx index 31a45db8..d33a9d2e 100644 --- a/src/views/avatar-editor/views/wardrobe/AvatarEditorWardrobeView.tsx +++ b/src/views/avatar-editor/views/wardrobe/AvatarEditorWardrobeView.tsx @@ -1,4 +1,7 @@ -import { FC, useMemo } from 'react'; +import { UserWardrobeSaveComposer } from 'nitro-renderer'; +import { FC, useCallback, useMemo } from 'react'; +import { Button } from 'react-bootstrap'; +import { SendMessageHook } from '../../../../hooks'; import { NitroCardGridItemView } from '../../../../layout/card/grid/item/NitroCardGridItemView'; import { NitroCardGridView } from '../../../../layout/card/grid/NitroCardGridView'; import { NitroCardGridThemes } from '../../../../layout/card/grid/NitroCardGridView.types'; @@ -7,48 +10,68 @@ import { AvatarEditorWardrobeViewProps } from './AvatarEditorWardrobeView.types' export const AvatarEditorWardrobeView: FC = props => { - const { figures = [] } = props; + const { figureData = null, savedFigures = [], setSavedFigures = null, loadAvatarInEditor = null } = props; - const savedFigures = useMemo(() => + const wearFigureAtIndex = useCallback((index: number) => { - if(!figures) return []; + if((index >= savedFigures.length) || (index < 0)) return; - let i = 0; + const [ figure, gender ] = savedFigures[index]; + + loadAvatarInEditor(figure, gender); + }, [ savedFigures, loadAvatarInEditor ]); + + const saveFigureAtWardrobeIndex = useCallback((index: number) => + { + if(!figureData || (index >= savedFigures.length) || (index < 0)) return; + + const newFigures = [ ...savedFigures ]; + + const figure = figureData.getFigureString(); + const gender = figureData.gender; + + newFigures[index] = [ figure, gender ]; + + setSavedFigures(newFigures); + SendMessageHook(new UserWardrobeSaveComposer((index + 1), figure, gender)); + }, [ figureData, savedFigures, setSavedFigures ]); + + const figures = useMemo(() => + { + if(!savedFigures) return []; const items: JSX.Element[] = []; - while(i < figures.length) - { - const figure = figures[i]; - - let figureString = null; - let gender = null; - - if(figure) + savedFigures.forEach((figure, index) => { - figureString = (figure[0] || null); - gender = (figure[1] || null); - } + let figureString = null; + let gender = null; - items.push( - - - - ); - - i++ - } + if(figure) + { + figureString = (figure[0] || null); + gender = (figure[1] || null); + } + + items.push( + + { figureString && } +
+ + { figureString && } +
+
+ ); + }); return items; - }, [ figures ]); - - console.log(figures.length); + }, [ savedFigures, saveFigureAtWardrobeIndex, wearFigureAtIndex ]); return (
- - { savedFigures } + + { figures }
diff --git a/src/views/avatar-editor/views/wardrobe/AvatarEditorWardrobeView.types.ts b/src/views/avatar-editor/views/wardrobe/AvatarEditorWardrobeView.types.ts index a6d5c978..2311c58e 100644 --- a/src/views/avatar-editor/views/wardrobe/AvatarEditorWardrobeView.types.ts +++ b/src/views/avatar-editor/views/wardrobe/AvatarEditorWardrobeView.types.ts @@ -1,4 +1,10 @@ +import { Dispatch, SetStateAction } from 'react'; +import { FigureData } from '../../common/FigureData'; + export interface AvatarEditorWardrobeViewProps { - figures: [ string, string ][]; + figureData: FigureData; + savedFigures: [ string, string ][]; + setSavedFigures: Dispatch>; + loadAvatarInEditor: (figure: string, gender: string, reset?: boolean) => void; } diff --git a/src/views/catalog/CatalogMessageHandler.tsx b/src/views/catalog/CatalogMessageHandler.tsx index bcc13b40..70ddf952 100644 --- a/src/views/catalog/CatalogMessageHandler.tsx +++ b/src/views/catalog/CatalogMessageHandler.tsx @@ -127,11 +127,11 @@ export const CatalogMessageHandler: FC = props => type: CatalogActions.SET_SUBSCRIPTION_INFO, payload: { subscriptionInfo: new SubscriptionInfo( - Math.max(0, parser.days), - Math.max(0, parser.months), + Math.max(0, parser.daysToPeriodEnd), + Math.max(0, parser.periodsSubscribedAhead), parser.isVip, parser.pastClubDays, - parser.pastVIPDays + parser.pastVipDays ) } }); @@ -149,8 +149,6 @@ export const CatalogMessageHandler: FC = props => { const parser = event.getParser(); - console.log(parser); - dispatchCatalogState({ type: CatalogActions.SET_GIFT_CONFIGURATION, payload: { diff --git a/src/views/catalog/CatalogView.tsx b/src/views/catalog/CatalogView.tsx index 8f6c6ff5..0162cffd 100644 --- a/src/views/catalog/CatalogView.tsx +++ b/src/views/catalog/CatalogView.tsx @@ -1,7 +1,6 @@ -import { CatalogModeComposer, CatalogRequestGiftConfigurationComposer, ICatalogPageData, RoomPreviewer } from 'nitro-renderer'; +import { CatalogModeComposer, CatalogPageComposer, CatalogRequestGiftConfigurationComposer, ICatalogPageData, ILinkEventTracker, RoomPreviewer } from 'nitro-renderer'; import { FC, useCallback, useEffect, useReducer, useState } from 'react'; -import { GetRoomEngine } from '../../api'; -import { GetCatalogPageComposer } from '../../api/catalog/GetCatalogPageComposer'; +import { AddEventLinkTracker, GetRoomEngine, RemoveLinkEventTracker } from '../../api'; import { CatalogEvent } from '../../events'; import { useUiEvent } from '../../hooks/events/ui/ui-event'; import { SendMessageHook } from '../../hooks/messages/message-event'; @@ -9,6 +8,7 @@ import { NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, Nitro import { LocalizeText } from '../../utils/LocalizeText'; import { CatalogMessageHandler } from './CatalogMessageHandler'; import { CatalogMode, CatalogViewProps } from './CatalogView.types'; +import { GetCatalogPageTree } from './common/CatalogUtilities'; import { CatalogContextProvider } from './context/CatalogContext'; import { CatalogActions, CatalogReducer, initialCatalog } from './reducers/CatalogReducer'; import { CatalogNavigationView } from './views/navigation/CatalogNavigationView'; @@ -18,8 +18,10 @@ export const CatalogView: FC = props => { const [ isVisible, setIsVisible ] = useState(false); const [ roomPreviewer, setRoomPreviewer ] = useState(null); + const [ pendingPageId, setPendingPageId ] = useState(-1); + const [ pendingTree, setPendingTree ] = useState(null); const [ catalogState, dispatchCatalogState ] = useReducer(CatalogReducer, initialCatalog); - const { root = null, currentTab = null, pageParser = null, activeOffer = null, searchResult = null } = catalogState; + const { root = null, currentTab = null, pageParser = null, activeOffer = null, searchResult = null} = catalogState; const onCatalogEvent = useCallback((event: CatalogEvent) => { @@ -42,22 +44,99 @@ export const CatalogView: FC = props => useUiEvent(CatalogEvent.TOGGLE_CATALOG, onCatalogEvent); useUiEvent(CatalogEvent.CATALOG_RESET, onCatalogEvent); + const setCurrentTab = useCallback((page: ICatalogPageData) => + { + dispatchCatalogState({ + type: CatalogActions.SET_CATALOG_CURRENT_TAB, + payload: { + currentTab: page + } + }); + }, [ dispatchCatalogState ]); + + const buildCatalogPageTree = useCallback((page: ICatalogPageData, targetPageId: number) => + { + const pageTree: ICatalogPageData[] = []; + + GetCatalogPageTree(page, targetPageId, pageTree); + + if(pageTree.length) pageTree.reverse(); + + return pageTree; + }, []); + + const linkReceived = useCallback((url: string) => + { + const parts = url.split('/'); + + if(parts.length < 2) return; + + switch(parts[1]) + { + case 'open': + if(parts.length > 2) + { + dispatchCatalogState({ + type: CatalogActions.SET_PENDING_PAGE_ID, + payload: { + pendingPageId: parseInt(parts[2]) + } + }); + } + else + { + setIsVisible(true); + } + return; + } + }, [ dispatchCatalogState ]); + useEffect(() => { - if(!isVisible) return; - - if(!catalogState.root) + const linkTracker: ILinkEventTracker = { + linkReceived, + eventUrlPrefix: 'catalog/' + }; + + AddEventLinkTracker(linkTracker); + + return () => RemoveLinkEventTracker(linkTracker); + }, [ linkReceived]); + + useEffect(() => + { + const loadCatalog = (((pendingPageId > -1) && !catalogState.root) || (isVisible && !catalogState.root)); + + if(loadCatalog) { SendMessageHook(new CatalogModeComposer(CatalogMode.MODE_NORMAL)); SendMessageHook(new CatalogRequestGiftConfigurationComposer()); } - }, [ isVisible, catalogState.root ]); + + if(catalogState.root) + { + if(!isVisible && (pendingPageId > -1)) + { + setIsVisible(true); + + return; + } + + if(pendingPageId > -1) + { + const tree = buildCatalogPageTree(catalogState.root, pendingPageId); + + setCurrentTab(tree.shift()); + setPendingTree(tree); + } + } + }, [ isVisible, pendingPageId, catalogState.root, buildCatalogPageTree, setCurrentTab ]); useEffect(() => { if(!currentTab) return; - SendMessageHook(GetCatalogPageComposer(currentTab.pageId, -1, CatalogMode.MODE_NORMAL)); + SendMessageHook(new CatalogPageComposer(currentTab.pageId, -1, CatalogMode.MODE_NORMAL)); }, [ currentTab ]); useEffect(() => @@ -75,16 +154,6 @@ export const CatalogView: FC = props => } }, []); - const setCurrentTab = useCallback((page: ICatalogPageData) => - { - dispatchCatalogState({ - type: CatalogActions.SET_CATALOG_CURRENT_TAB, - payload: { - currentTab: page - } - }); - }, [ dispatchCatalogState ]); - const currentNavigationPage = ((searchResult && searchResult.page) || currentTab); return ( @@ -105,7 +174,7 @@ export const CatalogView: FC = props =>
- { pageParser && !pageParser.frontPageItems.length && + { (!pageParser || (pageParser && !pageParser.frontPageItems.length)) &&
} diff --git a/src/views/catalog/common/CatalogUtilities.ts b/src/views/catalog/common/CatalogUtilities.ts index 26aac5d1..d8cd2a3f 100644 --- a/src/views/catalog/common/CatalogUtilities.ts +++ b/src/views/catalog/common/CatalogUtilities.ts @@ -149,3 +149,20 @@ export function GetPetAvailableColors(petIndex: number, palettes: SellablePetPal } } } + +export function GetCatalogPageTree(page: ICatalogPageData, targetPageId: number, tree: ICatalogPageData[]) +{ + if(page.pageId === targetPageId) return page; + + for(const pageData of page.children) + { + const foundPageData = GetCatalogPageTree(pageData, targetPageId, tree); + + if(foundPageData) + { + tree.push(pageData); + + return pageData; + } + } +} diff --git a/src/views/catalog/common/Purse.ts b/src/views/catalog/common/Purse.ts index a044cd05..eebaacf8 100644 --- a/src/views/catalog/common/Purse.ts +++ b/src/views/catalog/common/Purse.ts @@ -1,4 +1,4 @@ -import { Nitro } from 'nitro-renderer'; +import { GetNitroInstance } from '../../../api'; import { IPurse } from './IPurse'; export class Purse implements IPurse @@ -22,7 +22,7 @@ export class Purse implements IPurse public set credits(k: number) { - this._lastUpdated = Nitro.instance.time; + this._lastUpdated = GetNitroInstance().time; this._credits = k; } @@ -33,7 +33,7 @@ export class Purse implements IPurse public set clubDays(k: number) { - this._lastUpdated = Nitro.instance.time; + this._lastUpdated = GetNitroInstance().time; this._clubDays = k; } @@ -44,7 +44,7 @@ export class Purse implements IPurse public set clubPeriods(k: number) { - this._lastUpdated = Nitro.instance.time; + this._lastUpdated = GetNitroInstance().time; this._clubPeriods = k; } @@ -80,7 +80,7 @@ export class Purse implements IPurse public set _Str_6288(k: number) { - this._lastUpdated = Nitro.instance.time; + this._lastUpdated = GetNitroInstance().time; this._pastClubDays = k; } @@ -91,7 +91,7 @@ export class Purse implements IPurse public set _Str_4605(k: number) { - this._lastUpdated = Nitro.instance.time; + this._lastUpdated = GetNitroInstance().time; this._pastVipDays = k; } @@ -102,7 +102,7 @@ export class Purse implements IPurse public set _Str_18527(k: Map) { - this._lastUpdated = Nitro.instance.time; + this._lastUpdated = GetNitroInstance().time; this._activityPoints = k; } @@ -113,14 +113,14 @@ export class Purse implements IPurse public set _Str_4458(k: number) { - this._lastUpdated = Nitro.instance.time; + this._lastUpdated = GetNitroInstance().time; this._minutesUntilExpiration = k; } public get _Str_4458(): number { - const k = ((Nitro.instance.time - this._lastUpdated) / (1000 * 60)); + const k = ((GetNitroInstance().time - this._lastUpdated) / (1000 * 60)); const _local_2 = (this._minutesUntilExpiration - k); return (_local_2 > 0) ? _local_2 : 0; @@ -128,7 +128,7 @@ export class Purse implements IPurse public set _Str_6312(k: number) { - this._lastUpdated = Nitro.instance.time; + this._lastUpdated = GetNitroInstance().time; this._minutesSinceLastModified = k; } diff --git a/src/views/catalog/reducers/CatalogReducer.tsx b/src/views/catalog/reducers/CatalogReducer.tsx index 0d70095e..3ee02bdb 100644 --- a/src/views/catalog/reducers/CatalogReducer.tsx +++ b/src/views/catalog/reducers/CatalogReducer.tsx @@ -19,6 +19,7 @@ export interface ICatalogState clubOffers: CatalogClubOfferData[]; subscriptionInfo: SubscriptionInfo; giftConfiguration: GiftWrappingConfiguration; + pendingPageId: number; } export interface ICatalogAction @@ -37,6 +38,7 @@ export interface ICatalogAction clubOffers?: CatalogClubOfferData[]; subscriptionInfo?: SubscriptionInfo; giftConfiguration?: CatalogGiftConfigurationParser; + pendingPageId?: number; } } @@ -54,6 +56,7 @@ export class CatalogActions public static SET_SEARCH_RESULT: string = 'CA_SET_SEARCH_RESULT'; public static SET_SUBSCRIPTION_INFO: string = 'CA_SET_SUBSCRIPTION_INFO'; public static SET_GIFT_CONFIGURATION: string = 'CA_SET_GIFT_CONFIGURATION'; + public static SET_PENDING_PAGE_ID: string = 'CA_SET_PENDING_PAGE_ID'; } export const initialCatalog: ICatalogState = { @@ -68,7 +71,8 @@ export const initialCatalog: ICatalogState = { petPalettes: [], clubOffers: null, subscriptionInfo: new SubscriptionInfo(), - giftConfiguration: null + giftConfiguration: null, + pendingPageId: -1 } export const CatalogReducer: Reducer = (state, action) => @@ -168,6 +172,11 @@ export const CatalogReducer: Reducer = (state, ac return { ...state, giftConfiguration }; } + case CatalogActions.SET_PENDING_PAGE_ID: { + const pendingPageId = (action.payload.pendingPageId || -1); + + return { ...state, pendingPageId }; + } default: return state; } diff --git a/src/views/catalog/views/navigation/item/CatalogNavigationItemView.tsx b/src/views/catalog/views/navigation/item/CatalogNavigationItemView.tsx index 4fcabb6b..85878246 100644 --- a/src/views/catalog/views/navigation/item/CatalogNavigationItemView.tsx +++ b/src/views/catalog/views/navigation/item/CatalogNavigationItemView.tsx @@ -1,7 +1,8 @@ +import { CatalogPageComposer, ICatalogPageData } from 'nitro-renderer'; import { FC, useCallback, useEffect, useState } from 'react'; -import { GetCatalogPageComposer } from '../../../../../api/catalog/GetCatalogPageComposer'; import { SendMessageHook } from '../../../../../hooks/messages/message-event'; import { CatalogMode } from '../../../CatalogView.types'; +import { useCatalogContext } from '../../../context/CatalogContext'; import { CatalogIconView } from '../../catalog-icon/CatalogIconView'; import { CatalogNavigationSetView } from '../set/CatalogNavigationSetView'; import { CatalogNavigationItemViewProps } from './CatalogNavigationItemView.types'; @@ -10,42 +11,46 @@ export const CatalogNavigationItemView: FC = pro { const { page = null, isActive = false, setActiveChild = null } = props; const [ isExpanded, setIsExpanded ] = useState(false); + const [ myTree, setMyTree ] = useState(null); + const { dispatchCatalogState = null } = useCatalogContext(); - useEffect(() => + const select = useCallback((selectPage: ICatalogPageData) => { - if(!isActive || !page) return; - - setIsExpanded(true); - - SendMessageHook(GetCatalogPageComposer(page.pageId, -1, CatalogMode.MODE_NORMAL)); - }, [ isActive, page ]); - - const select = useCallback(() => - { - if(!page) return; + if(!selectPage) return; setActiveChild(prevValue => { - if(prevValue === page) + if(prevValue === selectPage) { - SendMessageHook(GetCatalogPageComposer(page.pageId, -1, CatalogMode.MODE_NORMAL)); + SendMessageHook(new CatalogPageComposer(selectPage.pageId, -1, CatalogMode.MODE_NORMAL)); } - return page; + return selectPage; }); - if(page.children && page.children.length) + if(selectPage.children && selectPage.children.length) { setIsExpanded(prevValue => { return !prevValue; }); } - }, [ page, setActiveChild ]); + }, [ setActiveChild ]); + + useEffect(() => + { + if(!isActive || !page) return; + + setIsExpanded(true); + + SendMessageHook(new CatalogPageComposer(page.pageId, -1, CatalogMode.MODE_NORMAL)); + }, [ isActive, page, select, dispatchCatalogState ]); + + if(!page.visible) return null; return (
-
+
select(page) }>
{ page.localization }
{ (page.children.length > 0) && } diff --git a/src/views/catalog/views/page/layout/CatalogLayout.scss b/src/views/catalog/views/page/layout/CatalogLayout.scss index 7482c804..ff111f8a 100644 --- a/src/views/catalog/views/page/layout/CatalogLayout.scss +++ b/src/views/catalog/views/page/layout/CatalogLayout.scss @@ -1,3 +1,4 @@ +@import './badge-display/CatalogLayoutBadgeDisplayView'; @import './default/CatalogLayoutDefaultView'; @import './frontpage4/CatalogLayoutFrontpage4View'; @import './pets/CatalogLayoutPetView'; diff --git a/src/views/catalog/views/page/layout/GetCatalogLayout.tsx b/src/views/catalog/views/page/layout/GetCatalogLayout.tsx index 0094e746..7e514a6d 100644 --- a/src/views/catalog/views/page/layout/GetCatalogLayout.tsx +++ b/src/views/catalog/views/page/layout/GetCatalogLayout.tsx @@ -1,4 +1,5 @@ import { ICatalogPageParser, RoomPreviewer } from 'nitro-renderer'; +import { CatalogLayoutBadgeDisplayView } from './badge-display/CatalogLayoutBadgeDisplayView'; import { CatalogLayoutDefaultView } from './default/CatalogLayoutDefaultView'; import { CatalogLayoutFrontpage4View } from './frontpage4/CatalogLayoutFrontpage4View'; import { CatalogLayouGuildCustomFurniView } from './guild-custom-furni/CatalogLayoutGuildCustomFurniView'; @@ -47,9 +48,11 @@ export const GetCatalogLayout = (pageParser: ICatalogPageParser, roomPreviewer: case 'spaces_new': return ; case 'trophies': - return ; + return ; case 'info_loyalty': return ; + case 'badge_display': + return ; case 'bots': case 'default_3x3': default: diff --git a/src/views/catalog/views/page/layout/badge-display/CatalogLayoutBadgeDisplayView.scss b/src/views/catalog/views/page/layout/badge-display/CatalogLayoutBadgeDisplayView.scss new file mode 100644 index 00000000..1229e018 --- /dev/null +++ b/src/views/catalog/views/page/layout/badge-display/CatalogLayoutBadgeDisplayView.scss @@ -0,0 +1,7 @@ +.nitro-catalog-layout-badge-display { + + .inventory-badge-grid { + height: 200px; + max-height: 200px; + } +} diff --git a/src/views/catalog/views/page/layout/badge-display/CatalogLayoutBadgeDisplayView.tsx b/src/views/catalog/views/page/layout/badge-display/CatalogLayoutBadgeDisplayView.tsx new file mode 100644 index 00000000..5e05b594 --- /dev/null +++ b/src/views/catalog/views/page/layout/badge-display/CatalogLayoutBadgeDisplayView.tsx @@ -0,0 +1,80 @@ +import { StringDataType } from 'nitro-renderer'; +import { FC, useCallback, useEffect, useMemo, useState } from 'react'; +import { InventoryBadgesUpdatedEvent } from '../../../../../../events'; +import { InventoryBadgesRequestEvent } from '../../../../../../events/inventory/InventoryBadgesRequestEvent'; +import { dispatchUiEvent, useUiEvent } from '../../../../../../hooks'; +import { NitroCardGridItemView } from '../../../../../../layout/card/grid/item/NitroCardGridItemView'; +import { NitroCardGridView } from '../../../../../../layout/card/grid/NitroCardGridView'; +import { BadgeImageView } from '../../../../../shared/badge-image/BadgeImageView'; +import { GetOfferName } from '../../../../common/CatalogUtilities'; +import { useCatalogContext } from '../../../../context/CatalogContext'; +import { CatalogRoomPreviewerView } from '../../../catalog-room-previewer/CatalogRoomPreviewerView'; +import { CatalogPageOffersView } from '../../offers/CatalogPageOffersView'; +import { CatalogPurchaseView } from '../../purchase/CatalogPurchaseView'; +import { CatalogLayoutBadgeDisplayViewProps } from './CatalogLayoutBadgeDisplayView.types'; + +export const CatalogLayoutBadgeDisplayView: FC = props => +{ + const { roomPreviewer = null, pageParser = null } = props; + const { catalogState = null, dispatchCatalogState = null } = useCatalogContext(); + const { activeOffer = null } = catalogState; + const [ currentBadge, setCurrentBadge ] = useState(null); + const [ badges, setBadges ] = useState([]); + + const product = ((activeOffer && activeOffer.products[0]) || null); + + const onInventoryBadgesUpdatedEvent = useCallback((event: InventoryBadgesUpdatedEvent) => + { + console.log(event); + setBadges(event.badges); + }, []); + + useUiEvent(InventoryBadgesUpdatedEvent.BADGES_UPDATED, onInventoryBadgesUpdatedEvent); + + const badgeElements = useMemo(() => + { + return badges.map(code => + { + return ( + setCurrentBadge(code) }> + + + ); + }); + }, [ badges, currentBadge ]); + + useEffect(() => + { + dispatchUiEvent(new InventoryBadgesRequestEvent(InventoryBadgesRequestEvent.REQUEST_BADGES)); + }, []); + + useEffect(() => + { + if(!currentBadge || !activeOffer) return; + + const stuffData = new StringDataType(); + + stuffData.setValue([ null, currentBadge ]); + + roomPreviewer.updateObjectStuffData(stuffData); + }, [ currentBadge, activeOffer, roomPreviewer ]); + + return ( +
+
+ +
+ + { badgeElements } + +
+
+ { product && +
+ +
{ GetOfferName(activeOffer) }
+ +
} +
+ ); +} diff --git a/src/views/catalog/views/page/layout/badge-display/CatalogLayoutBadgeDisplayView.types.ts b/src/views/catalog/views/page/layout/badge-display/CatalogLayoutBadgeDisplayView.types.ts new file mode 100644 index 00000000..172af17b --- /dev/null +++ b/src/views/catalog/views/page/layout/badge-display/CatalogLayoutBadgeDisplayView.types.ts @@ -0,0 +1,6 @@ +import { CatalogLayoutProps } from '../CatalogLayout.types'; + +export interface CatalogLayoutBadgeDisplayViewProps extends CatalogLayoutProps +{ + +} diff --git a/src/views/catalog/views/page/layout/vip-buy/CatalogLayoutVipBuyView.scss b/src/views/catalog/views/page/layout/vip-buy/CatalogLayoutVipBuyView.scss index 00fac98f..fd44278a 100644 --- a/src/views/catalog/views/page/layout/vip-buy/CatalogLayoutVipBuyView.scss +++ b/src/views/catalog/views/page/layout/vip-buy/CatalogLayoutVipBuyView.scss @@ -1,7 +1,10 @@ .nitro-catalog-layout-vip-buy { - .catalog-offer-item-container { - height: 60px !important; - max-height: 60px !important; + .vip-buy-grid { + + .grid-item-container { + height: 70px !important; + max-height: 70px !important; + } } } diff --git a/src/views/catalog/views/page/layout/vip-buy/CatalogLayoutVipBuyView.tsx b/src/views/catalog/views/page/layout/vip-buy/CatalogLayoutVipBuyView.tsx index 554e1c58..2fdd4a9e 100644 --- a/src/views/catalog/views/page/layout/vip-buy/CatalogLayoutVipBuyView.tsx +++ b/src/views/catalog/views/page/layout/vip-buy/CatalogLayoutVipBuyView.tsx @@ -1,7 +1,11 @@ -import { CatalogClubOfferData, CatalogRequestVipOffersComposer } from 'nitro-renderer'; -import { FC, useCallback, useEffect, useMemo } from 'react'; +import { CatalogClubOfferData, CatalogPurchaseComposer, CatalogRequestVipOffersComposer } from 'nitro-renderer'; +import { FC, useCallback, useEffect, useMemo, useState } from 'react'; +import { Button } from 'react-bootstrap'; import { SendMessageHook } from '../../../../../../hooks/messages/message-event'; +import { NitroCardGridItemView } from '../../../../../../layout/card/grid/item/NitroCardGridItemView'; +import { NitroCardGridView } from '../../../../../../layout/card/grid/NitroCardGridView'; import { LocalizeText } from '../../../../../../utils/LocalizeText'; +import { GLOBAL_PURSE } from '../../../../../purse/PurseView'; import { CurrencyIcon } from '../../../../../shared/currency-icon/CurrencyIcon'; import { GetCatalogPageImage } from '../../../../common/CatalogUtilities'; import { useCatalogContext } from '../../../../context/CatalogContext'; @@ -11,16 +15,7 @@ export const CatalogLayoutVipBuyView: FC = props = { const { catalogState = null } = useCatalogContext(); const { pageParser = null, clubOffers = null, subscriptionInfo = null } = catalogState; - - useEffect(() => - { - if(clubOffers === null) - { - SendMessageHook(new CatalogRequestVipOffersComposer(1)); - - return; - } - }, [ clubOffers ]); + const [ pendingOffer, setPendingOffer ] = useState(null); const getOfferText = useCallback((offer: CatalogClubOfferData) => { @@ -41,6 +36,31 @@ export const CatalogLayoutVipBuyView: FC = props = return offerText; }, []); + const getPurchaseHeader = useCallback(() => + { + const purse = GLOBAL_PURSE; + + if(!purse) return ''; + + const extensionOrSubscription = (purse.clubDays > 0 || purse.clubPeriods > 0) ? 'extension.' : 'subscription.'; + const daysOrMonths = ((pendingOffer.months === 0) ? 'days' : 'months'); + const daysOrMonthsText = ((pendingOffer.months === 0) ? pendingOffer.extraDays : pendingOffer.months); + const locale = LocalizeText('catalog.vip.buy.confirm.' + extensionOrSubscription + daysOrMonths); + + return locale.replace('%NUM_' + daysOrMonths.toUpperCase() + '%', daysOrMonthsText.toString()); + }, [ pendingOffer ]); + + const getPurchaseValidUntil = useCallback(() => + { + let locale = LocalizeText('catalog.vip.buy.confirm.end_date'); + + locale = locale.replace('%month%', pendingOffer.month.toString()); + locale = locale.replace('%day%', pendingOffer.day.toString()); + locale = locale.replace('%year%', pendingOffer.year.toString()); + + return locale; + }, [ pendingOffer ]); + const getSubscriptionDetails = useMemo(() => { if(!subscriptionInfo) return ''; @@ -52,41 +72,100 @@ export const CatalogLayoutVipBuyView: FC = props = return LocalizeText('catalog.vip.extend.info', [ 'days' ], [ totalDays.toString() ]); }, [ subscriptionInfo ]); + const purchaseSubscription = useCallback(() => + { + if(!pendingOffer) return; + + SendMessageHook(new CatalogPurchaseComposer(pageParser.pageId, pendingOffer.offerId, null, 1)); + }, [ pendingOffer, pageParser ]) + + useEffect(() => + { + if(clubOffers === null) + { + SendMessageHook(new CatalogRequestVipOffersComposer(1)); + + return; + } + }, [ clubOffers ]); + return ( -
-
-
- { clubOffers && (clubOffers.length > 0) && clubOffers.map((offer, index) => - { - return
-
-
- - { getOfferText(offer) } -
-
- { (offer.priceCredits > 0) && -
- { offer.priceCredits } - -
} - { (offer.priceActivityPoints > 0) && -
- { offer.priceActivityPoints } - + <> +
+
+ + { clubOffers && (clubOffers.length > 0) && clubOffers.map((offer, index) => + { + return ( + + { (pendingOffer === offer) && +
+
{ getPurchaseHeader() }
+
{ getPurchaseValidUntil() }
+
} + { (pendingOffer !== offer) && + <> +
+
+ + { getOfferText(offer) } +
+
+ { (offer.priceCredits > 0) && +
+ { offer.priceCredits } + +
} + { (offer.priceActivityPoints > 0) && +
+ { offer.priceActivityPoints } + +
} +
+
+ + } +
+ ); + }) } +
+ {/*
+ { clubOffers && (clubOffers.length > 0) && clubOffers.map((offer, index) => + { + return ( +
+
+
+ + { getOfferText(offer) } +
+
+ { (offer.priceCredits > 0) && +
+ { offer.priceCredits } + +
} + { (offer.priceActivityPoints > 0) && +
+ { offer.priceActivityPoints } + +
} +
+
-
-
; - })} + ); + }) } +
*/} +
+
+
+ +
+
-
-
- -
-
-
-
+ ); } diff --git a/src/views/hotel-view/HotelView.tsx b/src/views/hotel-view/HotelView.tsx index e870654e..d2abb427 100644 --- a/src/views/hotel-view/HotelView.tsx +++ b/src/views/hotel-view/HotelView.tsx @@ -1,6 +1,6 @@ -import { Nitro, RoomSessionEvent } from 'nitro-renderer'; +import { RoomSessionEvent } from 'nitro-renderer'; import { FC, useCallback, useState } from 'react'; -import { GetConfiguration } from '../../api'; +import { GetConfiguration, GetConfigurationManager } from '../../api'; import { useRoomSessionManagerEvent } from '../../hooks/events/nitro/session/room-session-manager-event'; import { HotelViewProps } from './HotelView.types'; import { WidgetSlotView } from './views/widget-slot/WidgetSlotView'; @@ -29,12 +29,12 @@ export const HotelView: FC = props => if (!isVisible) return null; const backgroundColor = GetConfiguration('hotelview')['images']['background.colour']; - const background = Nitro.instance.core.configuration.interpolate(GetConfiguration('hotelview')['images']['background']); - const sun = Nitro.instance.core.configuration.interpolate(GetConfiguration('hotelview')['images']['sun']); - const drape = Nitro.instance.core.configuration.interpolate(GetConfiguration('hotelview')['images']['drape']); - const left = Nitro.instance.core.configuration.interpolate(GetConfiguration('hotelview')['images']['left']); - const rightRepeat = Nitro.instance.core.configuration.interpolate(GetConfiguration('hotelview')['images']['right.repeat']); - const right = Nitro.instance.core.configuration.interpolate(GetConfiguration('hotelview')['images']['right']); + const background = GetConfigurationManager().interpolate(GetConfiguration('hotelview')['images']['background']); + const sun = GetConfigurationManager().interpolate(GetConfiguration('hotelview')['images']['sun']); + const drape = GetConfigurationManager().interpolate(GetConfiguration('hotelview')['images']['drape']); + const left = GetConfigurationManager().interpolate(GetConfiguration('hotelview')['images']['left']); + const rightRepeat = GetConfigurationManager().interpolate(GetConfiguration('hotelview')['images']['right.repeat']); + const right = GetConfigurationManager().interpolate(GetConfiguration('hotelview')['images']['right']); return (
diff --git a/src/views/inventory/InventoryMessageHandler.tsx b/src/views/inventory/InventoryMessageHandler.tsx index febf3af9..0a00a79b 100644 --- a/src/views/inventory/InventoryMessageHandler.tsx +++ b/src/views/inventory/InventoryMessageHandler.tsx @@ -1,7 +1,10 @@ -import { AdvancedMap, BadgesEvent, BotAddedToInventoryEvent, BotInventoryMessageEvent, BotRemovedFromInventoryEvent, FurnitureListAddOrUpdateEvent, FurnitureListEvent, FurnitureListInvalidateEvent, FurnitureListItemParser, FurnitureListRemovedEvent, FurniturePostItPlacedEvent, PetAddedToInventoryEvent, PetData, PetInventoryEvent, PetRemovedFromInventory, TradingAcceptEvent, TradingCloseEvent, TradingCompletedEvent, TradingConfirmationEvent, TradingListItemEvent, TradingNotOpenEvent, TradingOpenEvent, TradingOpenFailedEvent, TradingOtherNotAllowedEvent, TradingYouAreNotAllowedEvent, UnseenItemsEvent } from 'nitro-renderer'; +import { AdvancedMap, BadgeReceivedEvent, BadgesEvent, BotAddedToInventoryEvent, BotInventoryMessageEvent, BotRemovedFromInventoryEvent, FurnitureListAddOrUpdateEvent, FurnitureListEvent, FurnitureListInvalidateEvent, FurnitureListItemParser, FurnitureListRemovedEvent, FurniturePostItPlacedEvent, PetAddedToInventoryEvent, PetData, PetInventoryEvent, PetRemovedFromInventory, RequestBadgesComposer, TradingAcceptEvent, TradingCloseEvent, TradingCompletedEvent, TradingConfirmationEvent, TradingListItemEvent, TradingNotOpenEvent, TradingOpenEvent, TradingOpenFailedEvent, TradingOtherNotAllowedEvent, TradingYouAreNotAllowedEvent, UnseenItemsEvent } from 'nitro-renderer'; import { FC, useCallback } from 'react'; import { GetRoomSession, GetSessionDataManager } from '../../api'; -import { CreateMessageHook } from '../../hooks/messages/message-event'; +import { InventoryBadgesUpdatedEvent } from '../../events'; +import { InventoryBadgesRequestEvent } from '../../events/inventory/InventoryBadgesRequestEvent'; +import { dispatchUiEvent, useUiEvent } from '../../hooks'; +import { CreateMessageHook, SendMessageHook } from '../../hooks/messages/message-event'; import { mergeFurniFragments } from './common/FurnitureUtilities'; import { mergePetFragments } from './common/PetUtilities'; import { TradeState } from './common/TradeState'; @@ -17,7 +20,7 @@ let petMsgFragments: Map[] = null; export const InventoryMessageHandler: FC = props => { - const { dispatchFurnitureState = null, dispatchBotState = null, dispatchPetState = null, dispatchBadgeState = null, unseenTracker = null } = useInventoryContext(); + const { dispatchFurnitureState = null, dispatchBotState = null, dispatchPetState = null, badgeState = null, dispatchBadgeState = null, unseenTracker = null } = useInventoryContext(); const onFurnitureListAddOrUpdateEvent = useCallback((event: FurnitureListAddOrUpdateEvent) => { @@ -163,6 +166,18 @@ export const InventoryMessageHandler: FC = props = }); }, [ dispatchBadgeState ]); + const onBadgeReceivedEvent = useCallback((event: BadgeReceivedEvent) => + { + const parser = event.getParser(); + + dispatchBadgeState({ + type: InventoryBadgeActions.ADD_BADGE, + payload: { + badgeCode: parser.badgeCode + } + }); + }, [ dispatchBadgeState ]); + const onTradingAcceptEvent = useCallback((event: TradingAcceptEvent) => { const parser = event.getParser(); @@ -318,6 +333,7 @@ export const InventoryMessageHandler: FC = props = CreateMessageHook(PetRemovedFromInventory, onPetRemovedFromInventory); CreateMessageHook(PetAddedToInventoryEvent, onPetAddedToInventoryEvent); CreateMessageHook(BadgesEvent, onBadgesEvent); + CreateMessageHook(BadgeReceivedEvent, onBadgeReceivedEvent); CreateMessageHook(TradingAcceptEvent, onTradingAcceptEvent); CreateMessageHook(TradingCloseEvent, onTradingCloseEvent); CreateMessageHook(TradingCompletedEvent, onTradingCompletedEvent); @@ -330,5 +346,19 @@ export const InventoryMessageHandler: FC = props = CreateMessageHook(TradingYouAreNotAllowedEvent, onTradingYouAreNotAllowedEvent); CreateMessageHook(UnseenItemsEvent, onUnseenItemsEvent); + const onInventoryBadgesRequestEvent = useCallback((event: InventoryBadgesRequestEvent) => + { + if(badgeState.needsBadgeUpdate) + { + SendMessageHook(new RequestBadgesComposer()); + + return; + } + + dispatchUiEvent(new InventoryBadgesUpdatedEvent(InventoryBadgesUpdatedEvent.BADGES_UPDATED, badgeState.badges)); + }, [ badgeState ]) + + useUiEvent(InventoryBadgesRequestEvent.REQUEST_BADGES, onInventoryBadgesRequestEvent); + return null; } diff --git a/src/views/inventory/InventoryView.tsx b/src/views/inventory/InventoryView.tsx index 3a0a3f63..3d8b2601 100644 --- a/src/views/inventory/InventoryView.tsx +++ b/src/views/inventory/InventoryView.tsx @@ -1,10 +1,10 @@ import { IRoomSession, RoomEngineObjectEvent, RoomEngineObjectPlacedEvent, RoomPreviewer, RoomSessionEvent, TradingCancelComposer, TradingCloseComposer, TradingOpenComposer } from 'nitro-renderer'; import { FC, useCallback, useEffect, useReducer, useState } from 'react'; import { GetRoomEngine } from '../../api'; -import { InventoryEvent, InventoryTradeRequestEvent } from '../../events'; +import { InventoryBadgesUpdatedEvent, InventoryEvent, InventoryTradeRequestEvent } from '../../events'; import { useRoomEngineEvent } from '../../hooks/events/nitro/room/room-engine-event'; import { useRoomSessionManagerEvent } from '../../hooks/events/nitro/session/room-session-manager-event'; -import { useUiEvent } from '../../hooks/events/ui/ui-event'; +import { dispatchUiEvent, useUiEvent } from '../../hooks/events/ui/ui-event'; import { SendMessageHook } from '../../hooks/messages'; import { NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../layout'; import { LocalizeText } from '../../utils/LocalizeText'; @@ -186,6 +186,13 @@ export const InventoryView: FC = props => } }, [ furnitureState.tradeData, isVisible ]); + useEffect(() => + { + if(!badgeState.badges) return; + + dispatchUiEvent(new InventoryBadgesUpdatedEvent(InventoryBadgesUpdatedEvent.BADGES_UPDATED, badgeState.badges)); + }, [ badgeState.badges ]); + return ( diff --git a/src/views/inventory/common/FurnitureItem.ts b/src/views/inventory/common/FurnitureItem.ts index e063c9f0..d82b22e0 100644 --- a/src/views/inventory/common/FurnitureItem.ts +++ b/src/views/inventory/common/FurnitureItem.ts @@ -1,4 +1,5 @@ -import { IFurnitureItemData, IObjectData, Nitro } from 'nitro-renderer'; +import { IFurnitureItemData, IObjectData } from 'nitro-renderer'; +import { GetNitroInstance } from '../../../api'; import { IFurnitureItem } from './IFurnitureItem'; export class FurnitureItem implements IFurnitureItem @@ -122,7 +123,7 @@ export class FurnitureItem implements IFurnitureItem if(this._hasRentPeriodStarted) { - time = (this._secondsToExpiration - ((Nitro.instance.time - this._expirationTimeStamp) / 1000)); + time = (this._secondsToExpiration - ((GetNitroInstance().time - this._expirationTimeStamp) / 1000)); if(time < 0) time = 0; } diff --git a/src/views/inventory/reducers/InventoryBadgeReducer.tsx b/src/views/inventory/reducers/InventoryBadgeReducer.tsx index 912d9375..62b2c59d 100644 --- a/src/views/inventory/reducers/InventoryBadgeReducer.tsx +++ b/src/views/inventory/reducers/InventoryBadgeReducer.tsx @@ -23,11 +23,12 @@ export interface IInventoryBadgeAction export class InventoryBadgeActions { - public static SET_NEEDS_UPDATE: string = 'IBDA_SET_NEEDS_UPDATE'; - public static SET_BADGE: string = 'IBDA_SET_BADGE'; - public static SET_BADGES: string = 'IBDA_SET_BADGES'; - public static ADD_ACTIVE_BADGE: string = 'IBDA_ADD_ACTIVE_BADGE'; - public static REMOVE_ACTIVE_BADGE: string = 'IBDA_REMOVE_ACTIVE_BADGE'; + public static SET_NEEDS_UPDATE: string = 'IBA_SET_NEEDS_UPDATE'; + public static SET_BADGE: string = 'IBA_SET_BADGE'; + public static SET_BADGES: string = 'IBA_SET_BADGES'; + public static ADD_BADGE: string = 'IBA_ADD_BADGE'; + public static ADD_ACTIVE_BADGE: string = 'IBA_ADD_ACTIVE_BADGE'; + public static REMOVE_ACTIVE_BADGE: string = 'IBA_REMOVE_ACTIVE_BADGE'; } export const initialInventoryBadge: IInventoryBadgeState = { @@ -77,6 +78,14 @@ export const InventoryBadgeReducer: Reducer = props => { if(needsBadgeUpdate) { + console.log('yee') dispatchBadgeState({ type: InventoryBadgeActions.SET_NEEDS_UPDATE, payload: { diff --git a/src/views/main/MainView.tsx b/src/views/main/MainView.tsx index 92f222f5..db7f79c4 100644 --- a/src/views/main/MainView.tsx +++ b/src/views/main/MainView.tsx @@ -1,5 +1,6 @@ -import { Nitro, RoomSessionEvent } from 'nitro-renderer'; +import { RoomSessionEvent } from 'nitro-renderer'; import { FC, useCallback, useEffect, useState } from 'react'; +import { GetCommunication } from '../../api'; import { useRoomSessionManagerEvent } from '../../hooks/events/nitro/session/room-session-manager-event'; import { AchievementsView } from '../achievements/AchievementsView'; import { AvatarEditorView } from '../avatar-editor/AvatarEditorView'; @@ -41,7 +42,7 @@ export const MainView: FC = props => { setIsReady(true); - Nitro.instance.communication.connection.onReady(); + GetCommunication().connection.onReady(); }, []); return ( diff --git a/src/views/navigator/NavigatorView.tsx b/src/views/navigator/NavigatorView.tsx index 3b4d5c52..9318e48e 100644 --- a/src/views/navigator/NavigatorView.tsx +++ b/src/views/navigator/NavigatorView.tsx @@ -1,5 +1,7 @@ -import { NavigatorInitComposer, NavigatorSearchComposer, RoomSessionEvent } from 'nitro-renderer'; +import { ILinkEventTracker, NavigatorInitComposer, NavigatorSearchComposer, RoomSessionEvent } from 'nitro-renderer'; import { FC, useCallback, useEffect, useReducer, useState } from 'react'; +import { AddEventLinkTracker, RemoveLinkEventTracker } from '../../api'; +import { TryVisitRoom } from '../../api/navigator/TryVisitRoom'; import { NavigatorEvent } from '../../events'; import { useRoomSessionManagerEvent } from '../../hooks/events/nitro/session/room-session-manager-event'; import { useUiEvent } from '../../hooks/events/ui/ui-event'; @@ -73,6 +75,45 @@ export const NavigatorView: FC = props => SendMessageHook(new NavigatorSearchComposer(contextCode, searchValue)); }, []); + const linkReceived = useCallback((url: string) => + { + const parts = url.split('/'); + + if(parts.length < 2) return; + + switch(parts[1]) + { + case 'goto': + if(parts.length > 2) + { + switch(parts[2]) + { + case 'home': + //goToHomeRoom(); + break; + default: { + const roomId = parseInt(parts[2]); + + TryVisitRoom(roomId); + } + } + } + return; + } + }, []); + + useEffect(() => + { + const linkTracker: ILinkEventTracker = { + linkReceived, + eventUrlPrefix: 'navigator/' + }; + + AddEventLinkTracker(linkTracker); + + return () => RemoveLinkEventTracker(linkTracker); + }, [ linkReceived]); + useEffect(() => { if(!isVisible || !needsNavigatorUpdate) return; diff --git a/src/views/navigator/views/room-link/NavigatorRoomLinkView.tsx b/src/views/navigator/views/room-link/NavigatorRoomLinkView.tsx index cf697e19..38850aa7 100644 --- a/src/views/navigator/views/room-link/NavigatorRoomLinkView.tsx +++ b/src/views/navigator/views/room-link/NavigatorRoomLinkView.tsx @@ -1,6 +1,5 @@ -import { Nitro } from 'nitro-renderer'; import { FC, useCallback, useEffect, useRef, useState } from 'react'; -import { GetConfiguration } from '../../../../api'; +import { GetConfiguration, GetNitroInstance } from '../../../../api'; import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout'; import { LocalizeText } from '../../../../utils/LocalizeText'; import { useNavigatorContext } from '../../context/NavigatorContext'; @@ -26,7 +25,7 @@ export const NavigatorRoomLinkView: FC = props => setRoomThumbnail(GetConfiguration('image.library.url') + roomInfoData.enteredGuestRoom.officialRoomPicRef); } - const roomLinkRaw = Nitro.instance.core.configuration.interpolate(LocalizeText('navigator.embed.src', ['roomId'], [roomInfoData.enteredGuestRoom.roomId.toString()])); + const roomLinkRaw = GetNitroInstance().core.configuration.interpolate(LocalizeText('navigator.embed.src', ['roomId'], [roomInfoData.enteredGuestRoom.roomId.toString()])); setRoomLink(roomLinkRaw); }, [ roomInfoData ]); diff --git a/src/views/notification-center/NotificationCenterView.scss b/src/views/notification-center/NotificationCenterView.scss index d2a9445f..78a94d63 100644 --- a/src/views/notification-center/NotificationCenterView.scss +++ b/src/views/notification-center/NotificationCenterView.scss @@ -3,6 +3,7 @@ .content-area { min-height: 125px; + max-height: 300px; } } diff --git a/src/views/purse/PurseMessageHandler.tsx b/src/views/purse/PurseMessageHandler.tsx index 23d474e2..acab48c5 100644 --- a/src/views/purse/PurseMessageHandler.tsx +++ b/src/views/purse/PurseMessageHandler.tsx @@ -1,69 +1,59 @@ -import { UserCreditsEvent, UserCurrencyEvent, UserCurrencyUpdateEvent, UserSubscriptionEvent } from 'nitro-renderer'; +import { UserCreditsEvent, UserCurrencyEvent, UserCurrencyUpdateEvent, UserSubscriptionEvent, UserSubscriptionParser } from 'nitro-renderer'; import { FC, useCallback } from 'react'; import { CreateMessageHook } from '../../hooks/messages/message-event'; -import { Currency } from './common/Currency'; import { usePurseContext } from './context/PurseContext'; import { PurseMessageHandlerProps } from './PurseMessageHandler.types'; -import { PurseActions } from './reducers/PurseReducer'; export const PurseMessageHandler: FC = props => { - const { dispatchPurseState = null } = usePurseContext(); + const { purse = null } = usePurseContext(); const onUserCreditsEvent = useCallback((event: UserCreditsEvent) => { const parser = event.getParser(); - dispatchPurseState({ - type: PurseActions.SET_CURRENCY, - payload: { - currency: { type: -1, amount: parseFloat(parser.credits) } - } - }); - }, [ dispatchPurseState ]); + purse.credits = parseFloat(parser.credits); + + purse.notify(); + }, [ purse ]); const onUserCurrencyEvent = useCallback((event: UserCurrencyEvent) => { const parser = event.getParser(); - const currencies: Currency[] = []; + purse.activityPoints = parser.currencies; - for(const [ key, value ] of parser.currencies.entries()) currencies.push({ type: key, amount: value }); - - dispatchPurseState({ - type: PurseActions.SET_CURRENCIES, - payload: { currencies } - }); - }, [ dispatchPurseState ]); + purse.notify(); + }, [ purse ]); const onUserCurrencyUpdateEvent = useCallback((event: UserCurrencyUpdateEvent) => { const parser = event.getParser(); - dispatchPurseState({ - type: PurseActions.SET_CURRENCY, - payload: { - currency: { type: parser.type, amount: parser.amount } - } - }); - }, [ dispatchPurseState ]); + purse.activityPoints.set(parser.type, parser.amount); + + purse.notify(); + }, [ purse ]); const onUserSubscriptionEvent = useCallback((event: UserSubscriptionEvent) => { const parser = event.getParser(); - switch(parser.name) - { - case 'habbo_club': - dispatchPurseState({ - type: PurseActions.SET_CLUB_SUBSCRIPTION, - payload: { - clubSubscription: parser - } - }); - return; - } - }, [ dispatchPurseState ]); + const productName = parser.productName; + + if((productName !== 'club_habbo') && (productName !== 'habbo_club')) return; + + purse.clubDays = Math.max(0, parser.daysToPeriodEnd); + purse.clubPeriods = Math.max(0, parser.periodsSubscribedAhead); + purse.isVip = parser.isVip; + purse.pastClubDays = parser.pastClubDays; + purse.pastVipDays = parser.pastVipDays; + purse.isExpiring = ((parser.responseType === UserSubscriptionParser.RESPONSE_TYPE_DISCOUNT_AVAILABLE) ? true : false); + purse.minutesUntilExpiration = parser.minutesUntilExpiration; + purse.minutesSinceLastModified = parser.minutesSinceLastModified; + + purse.notify(); + }, [ purse ]); CreateMessageHook(UserCreditsEvent, onUserCreditsEvent); CreateMessageHook(UserCurrencyEvent, onUserCurrencyEvent); diff --git a/src/views/purse/PurseView.scss b/src/views/purse/PurseView.scss index a1afd740..82ea9cc3 100644 --- a/src/views/purse/PurseView.scss +++ b/src/views/purse/PurseView.scss @@ -1,15 +1,37 @@ .nitro-purse { - background: rgba($dark,.95); - border: 1px solid lighten($dark,8.3); - box-shadow: inset 0px 3px lighten(rgba($dark,.6),2.5), inset 0 -2px darken(rgba($dark,.6),4); - font-weight: bolder; + padding: 2px; + background-color: #1c323f; + border: 2px solid rgba($white, 0.5); + border-top: 0; + font-size: $font-size-sm; + pointer-events: all; + margin-bottom:5px; + .notification-button { color:lighten($dark,20); cursor: pointer; font-size: 0.9rem; pointer-events: all; + display: none + } + + .nitro-purse-hc { + background-color: #3d5f6e; + margin:0 2px; + } + + .nitro-purse-button { + background: $bg-mirage-split-background; + + &:not(:first-child) { + margin-top:2px; + } + + &:hover { + background: $bg-cello-split-background; + } } } -@import './currency/CurrencyView'; +@import './views'; diff --git a/src/views/purse/PurseView.tsx b/src/views/purse/PurseView.tsx index 8ab722ca..ac041dbc 100644 --- a/src/views/purse/PurseView.tsx +++ b/src/views/purse/PurseView.tsx @@ -1,52 +1,144 @@ -import { UserCurrencyComposer } from 'nitro-renderer'; -import { FC, useCallback, useEffect, useMemo, useReducer } from 'react'; +import { FriendlyTime, HabboClubLevelEnum, UserCurrencyComposer, UserSubscriptionComposer } from 'nitro-renderer'; +import { FC, useCallback, useEffect, useMemo, useState } from 'react'; import { GetConfiguration } from '../../api'; -import { NotificationCenterEvent } from '../../events'; -import { dispatchUiEvent } from '../../hooks/events'; import { SendMessageHook } from '../../hooks/messages/message-event'; -import { SetLastCurrencies } from './common/CurrencyHelper'; +import { LocalizeText } from '../../utils/LocalizeText'; +import { CurrencyIcon } from '../shared/currency-icon/CurrencyIcon'; +import { IPurse } from './common/IPurse'; +import { Purse } from './common/Purse'; import { PurseContextProvider } from './context/PurseContext'; -import { CurrencyView } from './currency/CurrencyView'; import { PurseMessageHandler } from './PurseMessageHandler'; -import { PurseViewProps } from './PurseView.types'; -import { initialPurse, PurseReducer } from './reducers/PurseReducer'; +import { CurrencyView } from './views/currency/CurrencyView'; +import { SeasonalView } from './views/seasonal/SeasonalView'; -export const PurseView: FC = props => +export let GLOBAL_PURSE: IPurse = null; + +export const PurseView: FC<{}> = props => { - const [ purseState, dispatchPurseState ] = useReducer(PurseReducer, initialPurse); - const { currencies = [] } = purseState; + const [ purse, setPurse ] = useState(new Purse()); + const [ updateId, setUpdateId ] = useState(-1); const displayedCurrencies = useMemo(() => { return GetConfiguration('system.currency.types', []); }, []); + const getCurrencyElements = useCallback((offset: number, limit: number = -1, seasonal: boolean = false) => + { + if(!purse.activityPoints.size) return null; + + const types = Array.from(purse.activityPoints.keys()).filter(type => (displayedCurrencies.indexOf(type) >= 0)); + + let count = 0; + + while(count < offset) + { + types.shift(); + + count++; + } + + count = 0; + + const elements: JSX.Element[] = []; + + for(const type of types) + { + if((limit > -1) && (count === limit)) break; + + if(seasonal) elements.push(); + else elements.push(); + + count++; + } + + return elements; + }, [ purse, displayedCurrencies ]); + + const getClubText = useCallback(() => + { + const totalDays = ((purse.clubPeriods * 31) + purse.clubDays); + const minutesUntilExpiration = purse.minutesUntilExpiration; + + if(purse.clubLevel === HabboClubLevelEnum.NO_CLUB) + { + return LocalizeText('purse.clubdays.zero.amount.text'); + } + + else if((minutesUntilExpiration > -1) && (minutesUntilExpiration < (60 * 24))) + { + return FriendlyTime.shortFormat(minutesUntilExpiration * 60); + } + + else + { + return FriendlyTime.shortFormat(totalDays * 86400); + } + }, [ purse ]); + useEffect(() => { - SendMessageHook(new UserCurrencyComposer()); + const purse = new Purse(); + + GLOBAL_PURSE = purse; + + purse.notifier = () => setUpdateId(prevValue => (prevValue + 1)); + + setPurse(purse); + + return () => (purse.notifier = null); }, []); - SetLastCurrencies(currencies); - - const toggleNotificationCenter = useCallback(() => + useEffect(() => { - dispatchUiEvent(new NotificationCenterEvent(NotificationCenterEvent.TOGGLE_NOTIFICATION_CENTER)); - }, []); + if(!purse) return; + + SendMessageHook(new UserCurrencyComposer()); + }, [ purse ]); + + useEffect(() => + { + SendMessageHook(new UserSubscriptionComposer('habbo_club')); + + const interval = setInterval(() => + { + SendMessageHook(new UserSubscriptionComposer('habbo_club')); + }, 50000); + + return () => clearInterval(interval); + }, [ purse ]); + + if(!purse) return null; return ( - + -
- { currencies && currencies.map(currency => - { - if(displayedCurrencies.indexOf(currency.type) === -1) return null; - - return ; - }) } -
+
+
+
+
+ + { getCurrencyElements(0, 2) } +
+
+
+
+ + { getClubText() } +
+
+
+
+
+
+
+
+
+ {/*
-
+
*/}
+ { getCurrencyElements(2, -1, true) } ); } diff --git a/src/views/purse/PurseView.types.ts b/src/views/purse/PurseView.types.ts deleted file mode 100644 index c6fdd024..00000000 --- a/src/views/purse/PurseView.types.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface PurseViewProps -{ - -} diff --git a/src/views/purse/common/CurrencyHelper.ts b/src/views/purse/common/CurrencyHelper.ts index 6f382a9b..f9a6c3dd 100644 --- a/src/views/purse/common/CurrencyHelper.ts +++ b/src/views/purse/common/CurrencyHelper.ts @@ -1,19 +1,16 @@ -import { Currency } from './Currency'; - -let lastCurrencies: Currency[] = []; - -export function SetLastCurrencies(currencies: Currency[]): void -{ - lastCurrencies = currencies; -} +import { GLOBAL_PURSE } from '../PurseView'; export function GetCurrencyAmount(type: number): number { - for(const currency of lastCurrencies) - { - if(currency.type !== type) continue; + const purse = GLOBAL_PURSE; - return currency.amount; + if(type === -1) return purse.credits; + + for(const [ key, value ] of purse.activityPoints.entries()) + { + if(key !== type) continue; + + return value; } return 0; diff --git a/src/views/purse/common/IPurse.ts b/src/views/purse/common/IPurse.ts new file mode 100644 index 00000000..2a709938 --- /dev/null +++ b/src/views/purse/common/IPurse.ts @@ -0,0 +1,17 @@ +export interface IPurse +{ + credits: number; + activityPoints: Map; + clubDays: number; + clubPeriods: number; + _Str_13571: boolean; + isVip: boolean; + pastClubDays: number; + pastVipDays: number; + isExpiring: boolean; + minutesUntilExpiration: number; + minutesSinceLastModified: number; + clubLevel: number; + notifier: () => void + notify(): void; +} diff --git a/src/views/purse/common/Purse.ts b/src/views/purse/common/Purse.ts new file mode 100644 index 00000000..63bb2111 --- /dev/null +++ b/src/views/purse/common/Purse.ts @@ -0,0 +1,163 @@ +import { HabboClubLevelEnum } from 'nitro-renderer'; +import { GetNitroInstance } from '../../../api'; +import { IPurse } from './IPurse'; + +export class Purse implements IPurse +{ + private _credits: number = 0; + private _activityPoints: Map = new Map(); + 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; + private _notifier: () => void; + + public get credits(): number + { + return this._credits; + } + + public set credits(credits: number) + { + this._lastUpdated = GetNitroInstance().time; + this._credits = credits; + } + + public get activityPoints(): Map + { + return this._activityPoints; + } + + public set activityPoints(k: Map) + { + this._lastUpdated = GetNitroInstance().time; + this._activityPoints = k; + } + + public get clubDays(): number + { + return this._clubDays; + } + + public set clubDays(k: number) + { + this._lastUpdated = GetNitroInstance().time; + this._clubDays = k; + } + + public get clubPeriods(): number + { + return this._clubPeriods; + } + + public set clubPeriods(k: number) + { + this._lastUpdated = GetNitroInstance().time; + this._clubPeriods = k; + } + + public get _Str_13571(): boolean + { + return (this._clubDays > 0) || (this._clubPeriods > 0); + } + + public get isVip(): boolean + { + return this._isVIP; + } + + public set isVip(k: boolean) + { + this._isVIP = k; + } + + public get pastClubDays(): number + { + return this._pastClubDays; + } + + public set pastClubDays(k: number) + { + this._lastUpdated = GetNitroInstance().time; + this._pastClubDays = k; + } + + public get pastVipDays(): number + { + return this._pastVipDays; + } + + public set pastVipDays(k: number) + { + this._lastUpdated = GetNitroInstance().time; + this._pastVipDays = k; + } + + public get isExpiring(): boolean + { + return this._isExpiring; + } + + public set isExpiring(k: boolean) + { + this._isExpiring = k; + } + + public get minutesUntilExpiration(): number + { + var k: number = ((GetNitroInstance().time - this._lastUpdated) / (1000 * 60)); + var _local_2: number = (this._minutesUntilExpiration - k); + return (_local_2 > 0) ? _local_2 : 0; + } + + public set minutesUntilExpiration(k: number) + { + this._lastUpdated = GetNitroInstance().time; + this._minutesUntilExpiration = k; + } + + public get minutesSinceLastModified(): number + { + return this._minutesSinceLastModified; + } + + public set minutesSinceLastModified(k: number) + { + this._lastUpdated = GetNitroInstance().time; + this._minutesSinceLastModified = k; + } + + public get lastUpdated(): number + { + return this._lastUpdated; + } + + public get notifier(): () => void + { + return this._notifier; + } + + public set notifier(notifier: () => void) + { + this._notifier = notifier; + } + + public get clubLevel(): number + { + if(((this.clubDays === 0) && (this.clubPeriods === 0))) return HabboClubLevelEnum.NO_CLUB; + + if (this.isVip) return HabboClubLevelEnum.VIP; + + return HabboClubLevelEnum.CLUB; + } + + public notify(): void + { + if(this._notifier) this._notifier(); + } +} diff --git a/src/views/purse/context/PurseContext.tsx b/src/views/purse/context/PurseContext.tsx index 788d4d8d..b843f42c 100644 --- a/src/views/purse/context/PurseContext.tsx +++ b/src/views/purse/context/PurseContext.tsx @@ -2,8 +2,7 @@ import { createContext, FC, useContext } from 'react'; import { IPurseContext, PurseContextProps } from './PurseContext.types'; const PurseContext = createContext({ - purseState: null, - dispatchPurseState: null + purse: null }); export const PurseContextProvider: FC = props => diff --git a/src/views/purse/context/PurseContext.types.ts b/src/views/purse/context/PurseContext.types.ts index 4b18f160..7470b465 100644 --- a/src/views/purse/context/PurseContext.types.ts +++ b/src/views/purse/context/PurseContext.types.ts @@ -1,10 +1,9 @@ -import { Dispatch, ProviderProps } from 'react'; -import { IPurseAction, IPurseState } from '../reducers/PurseReducer'; +import { ProviderProps } from 'react'; +import { IPurse } from '../common/IPurse'; export interface IPurseContext { - purseState: IPurseState; - dispatchPurseState: Dispatch; + purse: IPurse; } export interface PurseContextProps extends ProviderProps diff --git a/src/views/purse/currency/CurrencyView.scss b/src/views/purse/currency/CurrencyView.scss deleted file mode 100644 index 5df98f9c..00000000 --- a/src/views/purse/currency/CurrencyView.scss +++ /dev/null @@ -1,10 +0,0 @@ -.nitro-currency { - pointer-events: all; - .nitro-currency-text { - max-width: 60px; - } - &:not(:last-child) { - border-right:1px solid #000; - box-shadow: 1px 0 lighten($dark,8.3) - } -} diff --git a/src/views/purse/currency/CurrencyView.tsx b/src/views/purse/currency/CurrencyView.tsx deleted file mode 100644 index 6e7f5ced..00000000 --- a/src/views/purse/currency/CurrencyView.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { FC } from 'react'; -import { OverlayTrigger, Tooltip } from 'react-bootstrap'; -import { LocalizeShortNumber } from '../../../utils/LocalizeShortNumber'; -import { CurrencyIcon } from '../../shared/currency-icon/CurrencyIcon'; -import { CurrencyViewProps } from './CurrencyView.types'; - -export const CurrencyView: FC = props => -{ - const { currency = null } = props; - - return ( - - { currency.amount } - - }> -
-
{LocalizeShortNumber(currency.amount)}
-
- -
-
-
- ); -} diff --git a/src/views/purse/currency/CurrencyView.types.ts b/src/views/purse/currency/CurrencyView.types.ts deleted file mode 100644 index aa58250d..00000000 --- a/src/views/purse/currency/CurrencyView.types.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { Currency } from '../common/Currency'; - -export interface CurrencyViewProps -{ - currency: Currency; -} diff --git a/src/views/purse/reducers/PurseReducer.tsx b/src/views/purse/reducers/PurseReducer.tsx deleted file mode 100644 index 3e9d5f5b..00000000 --- a/src/views/purse/reducers/PurseReducer.tsx +++ /dev/null @@ -1,77 +0,0 @@ -import { UserSubscriptionParser } from 'nitro-renderer'; -import { Reducer } from 'react'; -import { Currency } from '../common/Currency'; - -export interface IPurseState -{ - currencies: Currency[]; - clubSubscription: UserSubscriptionParser; -} - -export interface IPurseAction -{ - type: string; - payload: { - currency?: Currency; - currencies?: Currency[]; - clubSubscription?: UserSubscriptionParser; - } -} - -export class PurseActions -{ - public static SET_CURRENCY: string = 'PA_SET_CURRENCY'; - public static SET_CURRENCIES: string = 'PA_SET_CURRENCIES'; - public static SET_CLUB_SUBSCRIPTION: string = 'PA_SET_CLUB_SUBSCRIPTION'; -} - -export const initialPurse: IPurseState = { - currencies: [], - clubSubscription: null -} - -export const PurseReducer: Reducer = (state, action) => -{ - switch(action.type) - { - case PurseActions.SET_CURRENCY: { - const updated = action.payload.currency; - - let didSet = false; - - const currencies = state.currencies.map(existing => - { - if(existing.type !== updated.type) return existing; - - didSet = true; - - return { ...updated }; - }); - - if(!didSet) currencies.push({ ...updated }); - - return { ...state, currencies }; - } - case PurseActions.SET_CURRENCIES: { - const updated = action.payload.currencies; - - const currencies = state.currencies.filter(existing => - { - if(existing.type !== -1) return null; - - return existing; - }); - - if(updated && updated.length) currencies.push(...updated); - - return { ...state, currencies }; - } - case PurseActions.SET_CLUB_SUBSCRIPTION: { - const clubSubscription = action.payload.clubSubscription; - - return { ...state, clubSubscription }; - } - default: - return state; - } -} diff --git a/src/views/purse/views/currency/CurrencyView.scss b/src/views/purse/views/currency/CurrencyView.scss new file mode 100644 index 00000000..492f8454 --- /dev/null +++ b/src/views/purse/views/currency/CurrencyView.scss @@ -0,0 +1,9 @@ +.nitro-currency { + pointer-events: all; + background: $bg-mirage-split-background; + position: relative; + + &:not(:first-of-type) { + margin-top:2px; + } +} diff --git a/src/views/purse/views/currency/CurrencyView.tsx b/src/views/purse/views/currency/CurrencyView.tsx new file mode 100644 index 00000000..32c06007 --- /dev/null +++ b/src/views/purse/views/currency/CurrencyView.tsx @@ -0,0 +1,25 @@ +import { FC } from 'react'; +import { OverlayTrigger, Tooltip } from 'react-bootstrap'; +import { LocalizeShortNumber } from '../../../../utils/LocalizeShortNumber'; +import { CurrencyIcon } from '../../../shared/currency-icon/CurrencyIcon'; +import { CurrencyViewProps } from './CurrencyView.types'; + +export const CurrencyView: FC = props => +{ + const { type = -1, amount = -1 } = props; + + return ( + + { amount } + + }> +
+
{LocalizeShortNumber(amount)}
+ +
+
+ ); +} diff --git a/src/views/purse/common/Currency.ts b/src/views/purse/views/currency/CurrencyView.types.ts similarity index 54% rename from src/views/purse/common/Currency.ts rename to src/views/purse/views/currency/CurrencyView.types.ts index 9a2e2dea..0ff2718e 100644 --- a/src/views/purse/common/Currency.ts +++ b/src/views/purse/views/currency/CurrencyView.types.ts @@ -1,4 +1,4 @@ -export interface Currency +export interface CurrencyViewProps { type: number; amount: number; diff --git a/src/views/purse/views/index.scss b/src/views/purse/views/index.scss new file mode 100644 index 00000000..20184d7b --- /dev/null +++ b/src/views/purse/views/index.scss @@ -0,0 +1,2 @@ +@import './currency/CurrencyView'; +@import './seasonal/SeasonalView'; diff --git a/src/views/purse/views/seasonal/SeasonalView.scss b/src/views/purse/views/seasonal/SeasonalView.scss new file mode 100644 index 00000000..9b5b8e25 --- /dev/null +++ b/src/views/purse/views/seasonal/SeasonalView.scss @@ -0,0 +1,16 @@ +.nitro-seasonal-currency { + pointer-events: all; + padding: 2px; + background-color: #1c323f; + border: 2px solid rgba($white, 0.5); + font-size: $font-size-sm; + margin-bottom: 5px; + + .nitro-currency-text { + background: $bg-mirage-split-background; + } + + .nitro-seasonal-icon { + background-color: #3d5f6e + } +} diff --git a/src/views/purse/views/seasonal/SeasonalView.tsx b/src/views/purse/views/seasonal/SeasonalView.tsx new file mode 100644 index 00000000..4bad9ab5 --- /dev/null +++ b/src/views/purse/views/seasonal/SeasonalView.tsx @@ -0,0 +1,22 @@ +import { FC } from 'react'; +import { LocalizeShortNumber } from '../../../../utils/LocalizeShortNumber'; +import { LocalizeText } from '../../../../utils/LocalizeText'; +import { CurrencyIcon } from '../../../shared/currency-icon/CurrencyIcon'; +import { SeasonalViewProps } from './SeasonalView.types'; + +export const SeasonalView: FC = props => +{ + const { type = -1, amount = -1 } = props; + + return ( +
+
+ { LocalizeText(`purse.seasonal.currency.${ type }`) } + { LocalizeShortNumber(amount) } +
+
+ +
+
+ ); +} diff --git a/src/views/purse/views/seasonal/SeasonalView.types.ts b/src/views/purse/views/seasonal/SeasonalView.types.ts new file mode 100644 index 00000000..c7b8db5a --- /dev/null +++ b/src/views/purse/views/seasonal/SeasonalView.types.ts @@ -0,0 +1,6 @@ + +export interface SeasonalViewProps +{ + type: number; + amount: number; +} diff --git a/src/views/right-side/RightSideView.scss b/src/views/right-side/RightSideView.scss index febd7891..fd2c00c3 100644 --- a/src/views/right-side/RightSideView.scss +++ b/src/views/right-side/RightSideView.scss @@ -1,6 +1,6 @@ .nitro-right-side { position: absolute; - top: 10px; + top: 0px; right: 10px; min-width: 200px; max-width: 400px; diff --git a/src/views/room/RoomColorView.tsx b/src/views/room/RoomColorView.tsx index b7616615..3ac8a8f0 100644 --- a/src/views/room/RoomColorView.tsx +++ b/src/views/room/RoomColorView.tsx @@ -1,6 +1,6 @@ -import { ColorConverter, Nitro, NitroAdjustmentFilter, NitroContainer, NitroSprite, NitroTexture, RoomBackgroundColorEvent, RoomEngineEvent, RoomId, RoomObjectHSLColorEnabledEvent } from 'nitro-renderer'; +import { ColorConverter, NitroAdjustmentFilter, NitroContainer, NitroSprite, NitroTexture, RoomBackgroundColorEvent, RoomEngineEvent, RoomId, RoomObjectHSLColorEnabledEvent } from 'nitro-renderer'; import { FC, useCallback, useState } from 'react'; -import { GetRoomEngine } from '../../api'; +import { GetNitroInstance, GetRoomEngine } from '../../api'; import { UseMountEffect } from '../../hooks'; import { CreateEventDispatcherHook, useRoomEngineEvent } from '../../hooks/events'; import { useRoomContext } from './context/RoomContext'; @@ -48,8 +48,8 @@ export const RoomColorView: FC<{}> = props => if(color === undefined) color = 0x000000; background.tint = color; - background.width = Nitro.instance.width; - background.height = Nitro.instance.height; + background.width = GetNitroInstance().width; + background.height = GetNitroInstance().height; }, [ getRoomBackground ]); const updateRoomBackgroundColor = useCallback((hue: number, saturation: number, lightness: number, original: boolean = false) => diff --git a/src/views/room/RoomView.tsx b/src/views/room/RoomView.tsx index 3c187e72..babde88d 100644 --- a/src/views/room/RoomView.tsx +++ b/src/views/room/RoomView.tsx @@ -1,7 +1,7 @@ -import { EventDispatcher, Nitro, NitroRectangle, RoomGeometry, RoomVariableEnum, Vector3d } from 'nitro-renderer'; +import { EventDispatcher, NitroRectangle, RoomGeometry, RoomVariableEnum, Vector3d } from 'nitro-renderer'; import { FC, useEffect, useState } from 'react'; import { createPortal } from 'react-dom'; -import { InitializeRoomInstanceRenderingCanvas } from '../../api'; +import { GetNitroInstance, InitializeRoomInstanceRenderingCanvas } from '../../api'; import { DispatchMouseEvent } from '../../api/nitro/room/DispatchMouseEvent'; import { DispatchTouchEvent } from '../../api/nitro/room/DispatchTouchEvent'; import { GetRoomEngine } from '../../api/nitro/room/GetRoomEngine'; @@ -47,11 +47,11 @@ export const RoomView: FC = props => setWidgetHandler(widgetHandlerManager); - Nitro.instance.renderer.resize(window.innerWidth, window.innerHeight); + GetNitroInstance().renderer.resize(window.innerWidth, window.innerHeight); const canvasId = 1; - const displayObject = GetRoomEngine().getRoomInstanceDisplay(roomSession.roomId, canvasId, Nitro.instance.width, Nitro.instance.height, RoomGeometry.SCALE_ZOOMED_IN); + const displayObject = GetRoomEngine().getRoomInstanceDisplay(roomSession.roomId, canvasId, GetNitroInstance().width, GetNitroInstance().height, RoomGeometry.SCALE_ZOOMED_IN); if(!displayObject) return; @@ -77,13 +77,13 @@ export const RoomView: FC = props => geometry.location = new Vector3d(x, y, z); } - const stage = Nitro.instance.stage; + const stage = GetNitroInstance().stage; if(!stage) return; stage.addChild(displayObject); - const canvas = Nitro.instance.renderer.view; + const canvas = GetNitroInstance().renderer.view; if(!canvas) return; @@ -99,16 +99,16 @@ export const RoomView: FC = props => window.onresize = () => { - Nitro.instance.renderer.resize(window.innerWidth, window.innerHeight); + GetNitroInstance().renderer.resize(window.innerWidth, window.innerHeight); - InitializeRoomInstanceRenderingCanvas(roomSession.roomId, canvasId, Nitro.instance.width, Nitro.instance.height); + InitializeRoomInstanceRenderingCanvas(roomSession.roomId, canvasId, GetNitroInstance().width, GetNitroInstance().height); const bounds = canvas.getBoundingClientRect(); const rectangle = new NitroRectangle((bounds.x || 0), (bounds.y || 0), (bounds.width || 0), (bounds.height || 0)); widgetHandlerManager.eventDispatcher.dispatchEvent(new RoomWidgetUpdateRoomViewEvent(RoomWidgetUpdateRoomViewEvent.SIZE_CHANGED, rectangle)); - Nitro.instance.render(); + GetNitroInstance().render(); } setRoomCanvas(canvas); diff --git a/src/views/room/events/RoomWidgetUpdateInfostandFurniEvent.ts b/src/views/room/events/RoomWidgetUpdateInfostandFurniEvent.ts index 1eaa0bc4..f1e2bacf 100644 --- a/src/views/room/events/RoomWidgetUpdateInfostandFurniEvent.ts +++ b/src/views/room/events/RoomWidgetUpdateInfostandFurniEvent.ts @@ -30,4 +30,6 @@ export class RoomWidgetUpdateInfostandFurniEvent extends RoomWidgetUpdateInfosta public purchaseCouldBeUsedForBuyout: boolean = false; public rentCouldBeUsedForBuyout: boolean = false; public availableForBuildersClub: boolean = false; + public tileSizeX: number = 1; + public tileSizeY: number = 1; } diff --git a/src/views/room/handlers/RoomWidgetInfostandHandler.ts b/src/views/room/handlers/RoomWidgetInfostandHandler.ts index 53d4c86b..a7b898aa 100644 --- a/src/views/room/handlers/RoomWidgetInfostandHandler.ts +++ b/src/views/room/handlers/RoomWidgetInfostandHandler.ts @@ -1,5 +1,5 @@ -import { IFurnitureData, Nitro, NitroEvent, ObjectDataFactory, PetFigureData, PetRespectComposer, PetSupplementComposer, PetType, RoomAdsUpdateComposer, RoomControllerLevel, RoomModerationSettings, RoomObjectCategory, RoomObjectOperationType, RoomObjectType, RoomObjectVariable, RoomSessionPetInfoUpdateEvent, RoomSessionUserBadgesEvent, RoomTradingLevelEnum, RoomUnitDropHandItemComposer, RoomUnitGiveHandItemComposer, RoomUnitGiveHandItemPetComposer, RoomUserData, RoomWidgetEnum, RoomWidgetEnumItemExtradataParameter, SecurityLevel, Vector3d } from 'nitro-renderer'; -import { GetRoomEngine, GetSessionDataManager, IsOwnerOfFurniture } from '../../../api'; +import { IFurnitureData, NitroEvent, ObjectDataFactory, PetFigureData, PetRespectComposer, PetSupplementComposer, PetType, RoomAdsUpdateComposer, RoomControllerLevel, RoomModerationSettings, RoomObjectCategory, RoomObjectOperationType, RoomObjectType, RoomObjectVariable, RoomSessionPetInfoUpdateEvent, RoomSessionUserBadgesEvent, RoomTradingLevelEnum, RoomUnitDropHandItemComposer, RoomUnitGiveHandItemComposer, RoomUnitGiveHandItemPetComposer, RoomUserData, RoomWidgetEnum, RoomWidgetEnumItemExtradataParameter, SecurityLevel, Vector3d } from 'nitro-renderer'; +import { GetNitroInstance, GetRoomEngine, GetSessionDataManager, IsOwnerOfFurniture } from '../../../api'; import { InventoryTradeRequestEvent, WiredSelectObjectEvent } from '../../../events'; import { FriendListSendFriendRequestEvent } from '../../../events/friend-list/FriendListSendFriendRequestEvent'; import { dispatchUiEvent } from '../../../hooks/events'; @@ -390,6 +390,8 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler event.rentOfferId = furnitureData.rentOfferId; event.rentCouldBeUsedForBuyout = furnitureData.rentCouldBeUsedForBuyout; event.availableForBuildersClub = furnitureData.availableForBuildersClub; + event.tileSizeX = furnitureData.tileSizeX; + event.tileSizeY = furnitureData.tileSizeY; dispatchUiEvent(new WiredSelectObjectEvent(event.id, event.category)); } @@ -400,7 +402,7 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler const expiryTime = model.getValue(RoomObjectVariable.FURNITURE_EXPIRY_TIME); const expiryTimestamp = model.getValue(RoomObjectVariable.FURNITURE_EXPIRTY_TIMESTAMP); - event.expiration = ((expiryTime < 0) ? expiryTime : Math.max(0, (expiryTime - ((Nitro.instance.time - expiryTimestamp) / 1000)))); + event.expiration = ((expiryTime < 0) ? expiryTime : Math.max(0, (expiryTime - ((GetNitroInstance().time - expiryTimestamp) / 1000)))); let roomObjectImage = GetRoomEngine().getRoomObjectImage(roomId, message.id, message.category, new Vector3d(180), 64, null); diff --git a/src/views/room/widgets/avatar-info/views/own-avatar/AvatarInfoWidgetOwnAvatarView.tsx b/src/views/room/widgets/avatar-info/views/own-avatar/AvatarInfoWidgetOwnAvatarView.tsx index 1fa8cb40..93df5e2c 100644 --- a/src/views/room/widgets/avatar-info/views/own-avatar/AvatarInfoWidgetOwnAvatarView.tsx +++ b/src/views/room/widgets/avatar-info/views/own-avatar/AvatarInfoWidgetOwnAvatarView.tsx @@ -1,6 +1,8 @@ import { AvatarAction, AvatarExpressionEnum, RoomObjectCategory } from 'nitro-renderer'; import { FC, useCallback, useState } from 'react'; import { GetCanStandUp, GetCanUseExpression, GetOwnPosture, HasHabboClub, HasHabboVip, IsRidingHorse } from '../../../../../../api'; +import { AvatarEditorEvent } from '../../../../../../events'; +import { dispatchUiEvent } from '../../../../../../hooks'; import { LocalizeText } from '../../../../../../utils/LocalizeText'; import { CurrencyIcon } from '../../../../../shared/currency-icon/CurrencyIcon'; import { useRoomContext } from '../../../../context/RoomContext'; @@ -43,6 +45,7 @@ export const AvatarInfoWidgetOwnAvatarView: FC = props => let x = (location.x - (elementRef.current.offsetWidth / 2)); let y = (deltaY + offset); - const maxLeft = ((Nitro.instance.width - elementRef.current.offsetWidth) - SPACE_AROUND_EDGES); - const maxTop = ((Nitro.instance.height - elementRef.current.offsetHeight) - SPACE_AROUND_EDGES); + const maxLeft = ((GetNitroInstance().width - elementRef.current.offsetWidth) - SPACE_AROUND_EDGES); + const maxTop = ((GetNitroInstance().height - elementRef.current.offsetHeight) - SPACE_AROUND_EDGES); if(x < SPACE_AROUND_EDGES) x = SPACE_AROUND_EDGES; else if(x > maxLeft) x = maxLeft; diff --git a/src/views/room/widgets/furniture/mannequin/FurnitureMannequinView.tsx b/src/views/room/widgets/furniture/mannequin/FurnitureMannequinView.tsx index 151e0a3e..3c31b0a9 100644 --- a/src/views/room/widgets/furniture/mannequin/FurnitureMannequinView.tsx +++ b/src/views/room/widgets/furniture/mannequin/FurnitureMannequinView.tsx @@ -1,5 +1,6 @@ -import { AvatarFigurePartType, FurnitureMannequinSaveLookComposer, FurnitureMannequinSaveNameComposer, FurnitureMultiStateComposer, IAvatarFigureContainer, Nitro, NitroEvent, RoomEngineTriggerWidgetEvent, RoomObjectVariable } from 'nitro-renderer'; +import { AvatarFigurePartType, FurnitureMannequinSaveLookComposer, FurnitureMannequinSaveNameComposer, FurnitureMultiStateComposer, IAvatarFigureContainer, NitroEvent, RoomEngineTriggerWidgetEvent, RoomObjectVariable } from 'nitro-renderer'; import { FC, KeyboardEvent, useCallback, useEffect, useState } from 'react'; +import { GetNitroInstance } from '../../../../../api'; import { GetRoomEngine } from '../../../../../api/nitro/room/GetRoomEngine'; import { GetRoomSession } from '../../../../../api/nitro/session/GetRoomSession'; import { GetSessionDataManager } from '../../../../../api/nitro/session/GetSessionDataManager'; @@ -49,7 +50,7 @@ export const FurnitureMannequinView: FC<{}> = props => { if(mannequinData && !mannequinData.renderedFigure) { - const figureContainer = Nitro.instance.avatar.createFigureContainer(mannequinData.figure); + const figureContainer = GetNitroInstance().avatar.createFigureContainer(mannequinData.figure); loadMannequinFigure(figureContainer); } }, [loadMannequinFigure, mannequinData]); @@ -59,8 +60,8 @@ export const FurnitureMannequinView: FC<{}> = props => if(!mannequinData) return; const userCanEdit = (GetRoomSession().isRoomOwner || GetSessionDataManager().isModerator); - const userGender = Nitro.instance.sessionDataManager.gender; - const userClubLevel = Nitro.instance.sessionDataManager.clubLevel; + const userGender = GetNitroInstance().sessionDataManager.gender; + const userClubLevel = GetNitroInstance().sessionDataManager.clubLevel; if(userCanEdit) { @@ -100,8 +101,8 @@ export const FurnitureMannequinView: FC<{}> = props => const gender = roomObject.model.getValue(RoomObjectVariable.FURNITURE_MANNEQUIN_GENDER); const name = roomObject.model.getValue(RoomObjectVariable.FURNITURE_MANNEQUIN_NAME); - const figureContainer = Nitro.instance.avatar.createFigureContainer(figure); - const clubLevel = Nitro.instance.avatar.getFigureClubLevel(figureContainer, gender, parts); + const figureContainer = GetNitroInstance().avatar.createFigureContainer(figure); + const clubLevel = GetNitroInstance().avatar.getFigureClubLevel(figureContainer, gender, parts); const mannequinData = new FurnitureMannequinData(widgetEvent.objectId, widgetEvent.category, name, figure, gender, clubLevel); @@ -137,11 +138,11 @@ export const FurnitureMannequinView: FC<{}> = props => setMannequinData(mannequinData => new FurnitureMannequinData(mannequinData.objectId, mannequinData.category, value, mannequinData.figure, mannequinData.gender, mannequinData.clubLevel, mannequinData.renderedFigure)); return; case 'load_figure': - loadMannequinFigure(Nitro.instance.avatar.createFigureContainer(Nitro.instance.sessionDataManager.figure)); + loadMannequinFigure(GetNitroInstance().avatar.createFigureContainer(GetNitroInstance().sessionDataManager.figure)); setViewMode(MannequinViewMode.SAVE); return; case 'back': - loadMannequinFigure(Nitro.instance.avatar.createFigureContainer(mannequinData.figure)); + loadMannequinFigure(GetNitroInstance().avatar.createFigureContainer(mannequinData.figure)); setViewMode(MannequinViewMode.EDIT); return; case 'save_name': diff --git a/src/views/room/widgets/object-location/ObjectLocationView.tsx b/src/views/room/widgets/object-location/ObjectLocationView.tsx index 04bf1f20..36a735c9 100644 --- a/src/views/room/widgets/object-location/ObjectLocationView.tsx +++ b/src/views/room/widgets/object-location/ObjectLocationView.tsx @@ -1,6 +1,5 @@ -import { Nitro } from 'nitro-renderer'; import { FC, useCallback, useEffect, useRef, useState } from 'react'; -import { GetRoomEngine, GetRoomSession } from '../../../../api'; +import { GetNitroInstance, GetRoomEngine, GetRoomSession } from '../../../../api'; import { ObjectLocationViewProps } from './ObjectLocationView.types'; export const ObjectLocationView: FC = props => @@ -41,12 +40,12 @@ export const ObjectLocationView: FC = props => { remove = true; - Nitro.instance.ticker.add(updatePosition); + GetNitroInstance().ticker.add(updatePosition); } return () => { - if(remove) Nitro.instance.ticker.remove(updatePosition); + if(remove) GetNitroInstance().ticker.remove(updatePosition); } }, [ updatePosition, noFollow ]); diff --git a/src/views/shared/room-previewer/RoomPreviewerView.tsx b/src/views/shared/room-previewer/RoomPreviewerView.tsx index b2e972a4..d7894d54 100644 --- a/src/views/shared/room-previewer/RoomPreviewerView.tsx +++ b/src/views/shared/room-previewer/RoomPreviewerView.tsx @@ -1,5 +1,6 @@ -import { ColorConverter, IRoomRenderingCanvas, Nitro, TextureUtils } from 'nitro-renderer'; +import { ColorConverter, IRoomRenderingCanvas, TextureUtils } from 'nitro-renderer'; import { FC, useCallback, useEffect, useRef, useState } from 'react'; +import { GetNitroInstance } from '../../../api'; import { RoomPreviewerViewProps } from './RoomPreviewerView.types'; export const RoomPreviewerView: FC = props => @@ -56,7 +57,7 @@ export const RoomPreviewerView: FC = props => if(!renderingCanvas) setupPreviewer(); - Nitro.instance.ticker.add(update); + GetNitroInstance().ticker.add(update); function resize(): void { @@ -76,7 +77,7 @@ export const RoomPreviewerView: FC = props => return () => { - Nitro.instance.ticker.remove(update); + GetNitroInstance().ticker.remove(update); window.removeEventListener('resize', resize); }