diff --git a/src/App.scss b/src/App.scss index 9ae7fa7c..3ab4f7fd 100644 --- a/src/App.scss +++ b/src/App.scss @@ -35,6 +35,15 @@ $navigator-height: 420px; $chat-input-style-selector-widget-width: 200px; $chat-input-style-selector-widget-height: 200px; +$user-profile-width: 560px; +$user-profile-height: 500px; + +$nitro-widget-custom-stack-height-width: 275px; +$nitro-widget-custom-stack-height-height: 220px; + +$nitro-widget-exchange-credit-width: 375px; +$nitro-widget-exchange-credit-height: 150px; + .nitro-app { width: 100%; height: 100%; diff --git a/src/api/nitro/room/widgets/events/RoomWidgetUpdateMannequinEvent.ts b/src/api/nitro/room/widgets/events/RoomWidgetUpdateMannequinEvent.ts new file mode 100644 index 00000000..1894a9fb --- /dev/null +++ b/src/api/nitro/room/widgets/events/RoomWidgetUpdateMannequinEvent.ts @@ -0,0 +1,41 @@ +import { RoomWidgetUpdateEvent } from './RoomWidgetUpdateEvent'; + +export class RoomWidgetUpdateMannequinEvent extends RoomWidgetUpdateEvent +{ + public static MANNEQUIN_UPDATE: string = 'RWUME_MANNEQUIN_UPDATE'; + + private _objectId: number; + private _figure: string; + private _gender: string; + private _name: string; + + constructor(type: string, objectId: number, figure: string, gender: string, name: string) + { + super(type); + + this._objectId = objectId; + this._figure = figure; + this._gender = gender; + this._name = name; + } + + public get objectId(): number + { + return this._objectId; + } + + public get figure(): string + { + return this._figure; + } + + public get gender(): string + { + return this._gender; + } + + public get name(): string + { + return this._name; + } +} diff --git a/src/api/nitro/room/widgets/events/RoomWidgetRoomEngineUpdateEvent.ts b/src/api/nitro/room/widgets/events/RoomWidgetUpdateRoomEngineEvent.ts similarity index 62% rename from src/api/nitro/room/widgets/events/RoomWidgetRoomEngineUpdateEvent.ts rename to src/api/nitro/room/widgets/events/RoomWidgetUpdateRoomEngineEvent.ts index c7e433a2..0e72f2c3 100644 --- a/src/api/nitro/room/widgets/events/RoomWidgetRoomEngineUpdateEvent.ts +++ b/src/api/nitro/room/widgets/events/RoomWidgetUpdateRoomEngineEvent.ts @@ -1,9 +1,9 @@ import { RoomWidgetUpdateEvent } from './RoomWidgetUpdateEvent'; -export class RoomWidgetRoomEngineUpdateEvent extends RoomWidgetUpdateEvent +export class RoomWidgetUpdateRoomEngineEvent extends RoomWidgetUpdateEvent { - public static GAME_MODE: string = 'RWREUE_GAME_MODE'; - public static NORMAL_MODE: string = 'RWREUE_NORMAL_MODE'; + public static GAME_MODE: string = 'RWUREE_GAME_MODE'; + public static NORMAL_MODE: string = 'RWUREE_NORMAL_MODE'; private _roomId: number = 0; diff --git a/src/api/nitro/room/widgets/events/RoomWidgetRoomObjectUpdateEvent.ts b/src/api/nitro/room/widgets/events/RoomWidgetUpdateRoomObjectEvent.ts similarity index 54% rename from src/api/nitro/room/widgets/events/RoomWidgetRoomObjectUpdateEvent.ts rename to src/api/nitro/room/widgets/events/RoomWidgetUpdateRoomObjectEvent.ts index 8c63ab4c..cbc1d9c9 100644 --- a/src/api/nitro/room/widgets/events/RoomWidgetRoomObjectUpdateEvent.ts +++ b/src/api/nitro/room/widgets/events/RoomWidgetUpdateRoomObjectEvent.ts @@ -1,16 +1,16 @@ import { RoomWidgetUpdateEvent } from './RoomWidgetUpdateEvent'; -export class RoomWidgetRoomObjectUpdateEvent extends RoomWidgetUpdateEvent +export class RoomWidgetUpdateRoomObjectEvent extends RoomWidgetUpdateEvent { - public static OBJECT_SELECTED: string = 'RWROUE_OBJECT_SELECTED'; - public static OBJECT_DESELECTED: string = 'RWROUE_OBJECT_DESELECTED'; - public static USER_REMOVED: string = 'RWROUE_USER_REMOVED'; - public static FURNI_REMOVED: string = 'RWROUE_FURNI_REMOVED'; - public static FURNI_ADDED: string = 'RWROUE_FURNI_ADDED'; - public static USER_ADDED: string = 'RWROUE_USER_ADDED'; - public static OBJECT_ROLL_OVER: string = 'RWROUE_OBJECT_ROLL_OVER'; - public static OBJECT_ROLL_OUT: string = 'RWROUE_OBJECT_ROLL_OUT'; - public static OBJECT_REQUEST_MANIPULATION: string = 'RWROUE_OBJECT_REQUEST_MANIPULATION'; + public static OBJECT_SELECTED: string = 'RWUROE_OBJECT_SELECTED'; + public static OBJECT_DESELECTED: string = 'RWUROE_OBJECT_DESELECTED'; + public static USER_REMOVED: string = 'RWUROE_USER_REMOVED'; + public static FURNI_REMOVED: string = 'RWUROE_FURNI_REMOVED'; + public static FURNI_ADDED: string = 'RWUROE_FURNI_ADDED'; + public static USER_ADDED: string = 'RWUROE_USER_ADDED'; + public static OBJECT_ROLL_OVER: string = 'RWUROE_OBJECT_ROLL_OVER'; + public static OBJECT_ROLL_OUT: string = 'RWUROE_OBJECT_ROLL_OUT'; + public static OBJECT_REQUEST_MANIPULATION: string = 'RWUROE_OBJECT_REQUEST_MANIPULATION'; private _id: number; private _category: number; diff --git a/src/api/nitro/room/widgets/events/RoomWidgetUpdateTrophyEvent.ts b/src/api/nitro/room/widgets/events/RoomWidgetUpdateTrophyEvent.ts new file mode 100644 index 00000000..b13b2b66 --- /dev/null +++ b/src/api/nitro/room/widgets/events/RoomWidgetUpdateTrophyEvent.ts @@ -0,0 +1,48 @@ +import { RoomWidgetUpdateEvent } from './RoomWidgetUpdateEvent'; + +export class RoomWidgetUpdateTrophyEvent extends RoomWidgetUpdateEvent +{ + public static TROPHY_UPDATE: string = 'RWUTE_TROPHY_UPDATE'; + + private _color: number; + private _name: string; + private _date: string; + private _message: string; + private _extra: number; + + constructor(type: string, color: number, name: string, date: string, message: string, extra: number) + { + super(type); + + this._color = color; + this._name = name; + this._date = date; + this._message = message; + this._extra = extra; + } + + public get color(): number + { + return this._color; + } + + public get name(): string + { + return this._name; + } + + public get date(): string + { + return this._date; + } + + public get message(): string + { + return this._message; + } + + public get extra(): number + { + return this._extra; + } +} diff --git a/src/api/nitro/room/widgets/events/index.ts b/src/api/nitro/room/widgets/events/index.ts index 775d210e..f4415bb9 100644 --- a/src/api/nitro/room/widgets/events/index.ts +++ b/src/api/nitro/room/widgets/events/index.ts @@ -6,8 +6,6 @@ export * from './RoomWidgetChooserContentEvent'; export * from './RoomWidgetDoorbellEvent'; export * from './RoomWidgetFloodControlEvent'; export * from './RoomWidgetObjectNameEvent'; -export * from './RoomWidgetRoomEngineUpdateEvent'; -export * from './RoomWidgetRoomObjectUpdateEvent'; export * from './RoomWidgetUpdateBackgroundColorPreviewEvent'; export * from './RoomWidgetUpdateChatEvent'; export * from './RoomWidgetUpdateChatInputContentEvent'; @@ -24,10 +22,14 @@ export * from './RoomWidgetUpdateInfostandFurniEvent'; export * from './RoomWidgetUpdateInfostandPetEvent'; export * from './RoomWidgetUpdateInfostandRentableBotEvent'; export * from './RoomWidgetUpdateInfostandUserEvent'; +export * from './RoomWidgetUpdateMannequinEvent'; export * from './RoomWidgetUpdatePresentDataEvent'; export * from './RoomWidgetUpdateRentableBotChatEvent'; +export * from './RoomWidgetUpdateRoomEngineEvent'; +export * from './RoomWidgetUpdateRoomObjectEvent'; export * from './RoomWidgetUpdateRoomViewEvent'; export * from './RoomWidgetUpdateSongEvent'; +export * from './RoomWidgetUpdateTrophyEvent'; export * from './RoomWidgetUpdateUserDataEvent'; export * from './RoomWidgetUseProductBubbleEvent'; export * from './UseProductItem'; diff --git a/src/api/nitro/room/widgets/handlers/FurnitureMannequinWidgetHandler.ts b/src/api/nitro/room/widgets/handlers/FurnitureMannequinWidgetHandler.ts new file mode 100644 index 00000000..a2fc46bd --- /dev/null +++ b/src/api/nitro/room/widgets/handlers/FurnitureMannequinWidgetHandler.ts @@ -0,0 +1,54 @@ +import { NitroEvent, RoomEngineTriggerWidgetEvent, RoomObjectVariable, RoomWidgetEnum } from '@nitrots/nitro-renderer'; +import { RoomWidgetUpdateMannequinEvent } from '..'; +import { GetRoomEngine } from '../../GetRoomEngine'; +import { RoomWidgetUpdateEvent } from '../events/RoomWidgetUpdateEvent'; +import { RoomWidgetMessage } from '../messages/RoomWidgetMessage'; +import { RoomWidgetHandler } from './RoomWidgetHandler'; + +export class FurnitureMannequinWidgetHandler extends RoomWidgetHandler +{ + public processEvent(event: NitroEvent): void + { + switch(event.type) + { + case RoomEngineTriggerWidgetEvent.REQUEST_MANNEQUIN: { + const widgetEvent = (event as RoomEngineTriggerWidgetEvent); + const roomObject = GetRoomEngine().getRoomObject(widgetEvent.roomId, widgetEvent.objectId, widgetEvent.category); + + if(!roomObject) return; + + const model = roomObject.model; + const figure = model.getValue(RoomObjectVariable.FURNITURE_MANNEQUIN_FIGURE); + const gender = model.getValue(RoomObjectVariable.FURNITURE_MANNEQUIN_GENDER); + const name = model.getValue(RoomObjectVariable.FURNITURE_MANNEQUIN_NAME); + + this.container.eventDispatcher.dispatchEvent(new RoomWidgetUpdateMannequinEvent(RoomWidgetUpdateMannequinEvent.MANNEQUIN_UPDATE, roomObject.id, figure, gender, name)); + return; + } + } + } + + public processWidgetMessage(message: RoomWidgetMessage): RoomWidgetUpdateEvent + { + switch(message.type) + { + } + + return null; + } + + public get type(): string + { + return RoomWidgetEnum.MANNEQUIN; + } + + public get eventTypes(): string[] + { + return [ RoomEngineTriggerWidgetEvent.REQUEST_MANNEQUIN ]; + } + + public get messageTypes(): string[] + { + return []; + } +} diff --git a/src/api/nitro/room/widgets/handlers/index.ts b/src/api/nitro/room/widgets/handlers/index.ts index f2a12569..51f10e1a 100644 --- a/src/api/nitro/room/widgets/handlers/index.ts +++ b/src/api/nitro/room/widgets/handlers/index.ts @@ -5,6 +5,7 @@ export * from './FurnitureCreditWidgetHandler'; export * from './FurnitureCustomStackHeightWidgetHandler'; export * from './FurnitureDimmerWidgetHandler'; export * from './FurnitureExternalImageWidgetHandler'; +export * from './FurnitureMannequinWidgetHandler'; export * from './FurniturePresentWidgetHandler'; export * from './IRoomWidgetHandler'; export * from './IRoomWidgetHandlerManager'; diff --git a/src/assets/images/room-widgets/exchange-credit/exchange-credit-image.png b/src/assets/images/room-widgets/exchange-credit/exchange-credit-image.png new file mode 100644 index 00000000..eef5da6c Binary files /dev/null and b/src/assets/images/room-widgets/exchange-credit/exchange-credit-image.png differ diff --git a/src/layout/card/NitroCardView.scss b/src/layout/card/NitroCardView.scss index 9f11cdef..b604cd44 100644 --- a/src/layout/card/NitroCardView.scss +++ b/src/layout/card/NitroCardView.scss @@ -13,6 +13,7 @@ $nitro-card-tabs-height: 33px; width: 100%; height: 100%; pointer-events: none; + overflow: hidden; .theme-primary { border: $border-width solid $border-color; @@ -25,7 +26,7 @@ $nitro-card-tabs-height: 33px; left: 0 !important; width: 100%; height: 100%; - transform: none !important; + //transform: none !important; overflow: hidden; } @@ -39,6 +40,29 @@ $nitro-card-tabs-height: 33px; // } } } + + @include media-breakpoint-down(sm) { + + .draggable-window { + top: 0 !important; + left: 0 !important; + width: 100%; + height: 100%; + //transform: none !important; + overflow: hidden; + } + + .nitro-card { + width: 100%; + max-width: 100%; + max-height: calc(100% - #{$toolbar-height}); + margin: 0; + + &.rounded { + border-radius: 0 !important; + } + } + } } @import './accordion/NitroCardAccordionView'; diff --git a/src/layout/common/NitroLayoutSpacing.type.ts b/src/layout/common/NitroLayoutSpacing.type.ts index 96e53311..4f2bd26a 100644 --- a/src/layout/common/NitroLayoutSpacing.type.ts +++ b/src/layout/common/NitroLayoutSpacing.type.ts @@ -1 +1 @@ -export type NitroLayoutSpacing = 1 | 2 | 3 | 4 | 5; +export type NitroLayoutSpacing = 0 | 1 | 2 | 3 | 4 | 5; diff --git a/src/layout/draggable-window/DraggableWindow.tsx b/src/layout/draggable-window/DraggableWindow.tsx index a5cab370..d9d1fb03 100644 --- a/src/layout/draggable-window/DraggableWindow.tsx +++ b/src/layout/draggable-window/DraggableWindow.tsx @@ -1,5 +1,5 @@ -import { MouseEventType } from '@nitrots/nitro-renderer'; -import { FC, Key, MouseEvent as ReactMouseEvent, useCallback, useEffect, useRef, useState } from 'react'; +import { MouseEventType, TouchEventType } from '@nitrots/nitro-renderer'; +import { FC, Key, MouseEvent as ReactMouseEvent, TouchEvent as ReactTouchEvent, useCallback, useEffect, useRef, useState } from 'react'; import { DraggableWindowPosition, DraggableWindowProps } from './DraggableWindow.types'; const CURRENT_WINDOWS: HTMLElement[] = []; @@ -29,7 +29,7 @@ export const DraggableWindow: FC = props => } }, []); - const onMouseDown = useCallback((event: ReactMouseEvent) => + const moveCurrentWindow = useCallback(() => { const index = CURRENT_WINDOWS.indexOf(elementRef.current); @@ -50,18 +50,47 @@ export const DraggableWindow: FC = props => bringToTop(); }, [ bringToTop ]); - const onDragMouseDown = useCallback((event: MouseEvent) => + const onMouseDown = useCallback((event: ReactMouseEvent) => { - setStart({ x: event.clientX, y: event.clientY }); + moveCurrentWindow(); + }, [ moveCurrentWindow ]); + + const onTouchStart = useCallback((event: ReactTouchEvent) => + { + moveCurrentWindow(); + }, [ moveCurrentWindow ]); + + const startDragging = useCallback((startX: number, startY: number) => + { + setStart({ x: startX, y: startY }); setIsDragging(true); }, []); + const onDragMouseDown = useCallback((event: MouseEvent) => + { + startDragging(event.clientX, event.clientY); + }, [ startDragging ]); + + const onTouchDown = useCallback((event: TouchEvent) => + { + const touch = event.touches[0]; + + startDragging(touch.clientX, touch.clientY); + }, [ startDragging ]); + const onDragMouseMove = useCallback((event: MouseEvent) => { setDelta({ x: (event.clientX - start.x), y: (event.clientY - start.y) }); }, [ start ]); - const onDragMouseUp = useCallback((event: MouseEvent) => + const onDragTouchMove = useCallback((event: TouchEvent) => + { + const touch = event.touches[0]; + + setDelta({ x: (touch.clientX - start.x), y: (touch.clientY - start.y) }); + }, [ start ]); + + const completeDrag = useCallback(() => { if(!elementRef.current || !dragHandler) return; @@ -98,6 +127,16 @@ export const DraggableWindow: FC = props => if(uniqueKey !== null) POS_MEMORY.set(uniqueKey, { x: offsetX, y: offsetY }); }, [ dragHandler, delta, offset, uniqueKey ]); + const onDragMouseUp = useCallback((event: MouseEvent) => + { + completeDrag(); + }, [ completeDrag ]); + + const onDragTouchUp = useCallback((event: TouchEvent) => + { + completeDrag(); + }, [ completeDrag ]); + useEffect(() => { const element = (elementRef.current as HTMLElement); @@ -169,29 +208,35 @@ export const DraggableWindow: FC = props => if(!dragHandler) return; dragHandler.addEventListener(MouseEventType.MOUSE_DOWN, onDragMouseDown); + dragHandler.addEventListener(TouchEventType.TOUCH_START, onTouchDown); return () => { dragHandler.removeEventListener(MouseEventType.MOUSE_DOWN, onDragMouseDown); + dragHandler.removeEventListener(TouchEventType.TOUCH_START, onTouchDown); } - }, [ dragHandler, onDragMouseDown ]); + }, [ dragHandler, onDragMouseDown, onTouchDown ]); useEffect(() => { if(!isDragging) return; document.addEventListener(MouseEventType.MOUSE_UP, onDragMouseUp); + document.addEventListener(TouchEventType.TOUCH_END, onDragTouchUp); document.addEventListener(MouseEventType.MOUSE_MOVE, onDragMouseMove); + document.addEventListener(TouchEventType.TOUCH_MOVE, onDragTouchMove); return () => { document.removeEventListener(MouseEventType.MOUSE_UP, onDragMouseUp); + document.removeEventListener(TouchEventType.TOUCH_END, onDragTouchUp); document.removeEventListener(MouseEventType.MOUSE_MOVE, onDragMouseMove); + document.removeEventListener(TouchEventType.TOUCH_MOVE, onDragTouchMove); } - }, [ isDragging, onDragMouseUp, onDragMouseMove ]); + }, [ isDragging, onDragMouseUp, onDragMouseMove, onDragTouchUp, onDragTouchMove ]); return ( -
+
{ children }
); diff --git a/src/layout/notification-bubble/NotificationBubbleView.tsx b/src/layout/notification-bubble/NotificationBubbleView.tsx index 49a45b9f..5c91505d 100644 --- a/src/layout/notification-bubble/NotificationBubbleView.tsx +++ b/src/layout/notification-bubble/NotificationBubbleView.tsx @@ -1,28 +1,46 @@ -import { FC, useEffect, useState } from 'react'; +import { FC, useEffect, useMemo, useState } from 'react'; +import { NitroLayoutBase } from '../base'; +import { TransitionAnimation, TransitionAnimationTypes } from '../transitions'; import { NotificationBubbleViewProps } from './NotificationBubbleView.types'; export const NotificationBubbleView: FC = props => { - const { fadesOut = false, close = null, className = '', children = null, ...rest } = props; - const [ isFading, setIsFading ] = useState(false); + const { fadesOut = true, timeoutMs = 8000, close = null, className = '', ...rest } = props; + const [ isVisible, setIsVisible ] = useState(false); + + const getClassName = useMemo(() => + { + let newClassName = 'nitro-notification-bubble rounded'; + + if(className && className.length) newClassName += ` ${ className }`; + + return newClassName; + }, [ className ]); + + useEffect(() => + { + setIsVisible(true); + + return () => setIsVisible(false); + }, []); useEffect(() => { if(!fadesOut) return; const timeout = setTimeout(() => - { - setIsFading(true); + { + setIsVisible(false); - setTimeout(() => close()); - }, 8000); + setTimeout(() => close(), 300); + }, timeoutMs); return () => clearTimeout(timeout); - }, [ fadesOut, close ]); + }, [ fadesOut, timeoutMs, close ]); return ( -
- { children } -
- ) + + + + ); } diff --git a/src/layout/notification-bubble/NotificationBubbleView.types.ts b/src/layout/notification-bubble/NotificationBubbleView.types.ts index 1fac4e46..5c160b4e 100644 --- a/src/layout/notification-bubble/NotificationBubbleView.types.ts +++ b/src/layout/notification-bubble/NotificationBubbleView.types.ts @@ -1,7 +1,8 @@ -import { DetailsHTMLAttributes } from 'react'; +import { NitroLayoutBaseProps } from '../base'; -export interface NotificationBubbleViewProps extends DetailsHTMLAttributes +export interface NotificationBubbleViewProps extends NitroLayoutBaseProps { fadesOut?: boolean; + timeoutMs?: number; close: () => void; } diff --git a/src/layout/trophy/NitroLayoutTrophyView.scss b/src/layout/trophy/NitroLayoutTrophyView.scss index edcc05f8..795169b4 100644 --- a/src/layout/trophy/NitroLayoutTrophyView.scss +++ b/src/layout/trophy/NitroLayoutTrophyView.scss @@ -3,6 +3,7 @@ width: 340px; height: 173px; color: black; + pointer-events: all; background-position: 0px 0px; background-image: url('../../assets/images/room-widgets/trophy-widget/trophy-spritesheet.png'); diff --git a/src/views/achievements/AchievementsView.tsx b/src/views/achievements/AchievementsView.tsx index 9ef315a6..a3bfbaca 100644 --- a/src/views/achievements/AchievementsView.tsx +++ b/src/views/achievements/AchievementsView.tsx @@ -158,6 +158,11 @@ export const AchievementsView: FC = props => return progress; }, [ achievementCategories ]); + const scaledProgressPercent = useMemo(() => + { + return ~~((((getProgress - 0) * (100 - 0)) / (getMaxProgress - 0)) + 0); + }, [ getProgress, getMaxProgress ]); + const getSelectedCategory = useMemo(() => { if(!achievementCategories || !achievementCategories.length) return null; @@ -220,8 +225,10 @@ export const AchievementsView: FC = props => <> - - { LocalizeText('achievements.categories.totalprogress', [ 'progress', 'limit' ], [ getProgress.toString(), getMaxProgress.toString() ]) } + + + { LocalizeText('achievements.categories.totalprogress', [ 'progress', 'limit' ], [ getProgress.toString(), getMaxProgress.toString() ]) } + { LocalizeText('achievements.categories.score', [ 'score' ], [ achievementScore.toString() ]) } diff --git a/src/views/achievements/common/GetAchievementLevel.ts b/src/views/achievements/common/GetAchievementLevel.ts new file mode 100644 index 00000000..c62bf7aa --- /dev/null +++ b/src/views/achievements/common/GetAchievementLevel.ts @@ -0,0 +1,8 @@ +import { AchievementData } from '@nitrots/nitro-renderer'; + +export const GetAchievementLevel = (achievement: AchievementData) => +{ + if(achievement.finalLevel) return achievement.level; + + return (achievement.level - 1); +} diff --git a/src/views/achievements/common/GetScaledProgressPercent.ts b/src/views/achievements/common/GetScaledProgressPercent.ts new file mode 100644 index 00000000..8708a709 --- /dev/null +++ b/src/views/achievements/common/GetScaledProgressPercent.ts @@ -0,0 +1,8 @@ +import { AchievementData } from '@nitrots/nitro-renderer'; + +export const GetScaledProgressPercent = (achievement: AchievementData) => +{ + if(!achievement) return 0; + + return ~~(((((achievement.currentPoints + achievement.scoreAtStartOfLevel) - 0) * (100 - 0)) / ((achievement.scoreLimit + achievement.scoreAtStartOfLevel) - 0)) + 0); +} diff --git a/src/views/achievements/views/achievement-details/AchievementDetailsView.tsx b/src/views/achievements/views/achievement-details/AchievementDetailsView.tsx index be50d707..5ab5d320 100644 --- a/src/views/achievements/views/achievement-details/AchievementDetailsView.tsx +++ b/src/views/achievements/views/achievement-details/AchievementDetailsView.tsx @@ -1,9 +1,11 @@ -import { FC, useMemo } from 'react'; +import { FC } from 'react'; import { LocalizeBadgeDescription, LocalizeBadgeName, LocalizeText } from '../../../../api'; import { NitroLayoutFlex, NitroLayoutFlexColumn } from '../../../../layout'; import { NitroLayoutBase } from '../../../../layout/base'; import { CurrencyIcon } from '../../../shared/currency-icon/CurrencyIcon'; import { AchievementUtilities } from '../../common/AchievementUtilities'; +import { GetAchievementLevel } from '../../common/GetAchievementLevel'; +import { GetScaledProgressPercent } from '../../common/GetScaledProgressPercent'; import { AchievementBadgeView } from '../achievement-badge/AchievementBadgeView'; import { AchievementDetailsViewProps } from './AchievementDetailsView.types'; @@ -11,25 +13,17 @@ export const AchievementDetailsView: FC = props => { const { achievement = null } = props; - const getAchievementLevel = useMemo(() => - { - if(achievement.finalLevel) return achievement.level; - - return (achievement.level - 1); - }, [ achievement ]); - if(!achievement) return null; - const currentAmount = achievement.currentPoints; - const maxAmount = achievement.scoreLimit; - const scoreAtStartOfLevel = achievement.scoreAtStartOfLevel; + const achievementLevel = GetAchievementLevel(achievement); + const scaledProgressPercent = GetScaledProgressPercent(achievement); return ( - { LocalizeText('achievements.details.level', [ 'level', 'limit' ], [ getAchievementLevel.toString(), achievement.levelCount.toString() ]) } + { LocalizeText('achievements.details.level', [ 'level', 'limit' ], [ achievementLevel.toString(), achievement.levelCount.toString() ]) } @@ -41,20 +35,24 @@ export const AchievementDetailsView: FC = props => { LocalizeBadgeDescription(AchievementUtilities.getBadgeCode(achievement)) } - { ((achievement.levelRewardPoints > 0) || (maxAmount > 0)) && + { ((achievement.levelRewardPoints > 0) || (achievement.scoreLimit > 0)) && { (achievement.levelRewardPoints > 0) && - + { LocalizeText('achievements.details.reward') } - + { achievement.levelRewardPoints } } - { (maxAmount > 0) && - LocalizeText('achievements.details.progress', [ 'progress', 'limit' ], [ (currentAmount + scoreAtStartOfLevel).toString(), (maxAmount + scoreAtStartOfLevel).toString() ]) } + { (achievement.scoreLimit > 0) && + + + { LocalizeText('achievements.details.progress', [ 'progress', 'limit' ], [ (achievement.currentPoints + achievement.scoreAtStartOfLevel).toString(), (achievement.scoreLimit + achievement.scoreAtStartOfLevel).toString() ]) } + + } } diff --git a/src/views/achievements/views/achievement-list/AchievementListView.tsx b/src/views/achievements/views/achievement-list/AchievementListView.tsx index 8cb6d7e1..4475e263 100644 --- a/src/views/achievements/views/achievement-list/AchievementListView.tsx +++ b/src/views/achievements/views/achievement-list/AchievementListView.tsx @@ -9,9 +9,9 @@ export const AchievementListView: FC = props => return ( - { achievements && (achievements.length > 0) && achievements.map(achievement => + { achievements && (achievements.length > 0) && achievements.map((achievement, index) => { - return setSelectedAchievementId(achievement.achievementId) } />; + return setSelectedAchievementId(achievement.achievementId) } />; }) } ); diff --git a/src/views/catalog/views/gift/CatalogGiftView.tsx b/src/views/catalog/views/gift/CatalogGiftView.tsx index d466d5b6..258d07f5 100644 --- a/src/views/catalog/views/gift/CatalogGiftView.tsx +++ b/src/views/catalog/views/gift/CatalogGiftView.tsx @@ -54,8 +54,11 @@ export const CatalogGiftView: FC<{}> = props => if(giftData.colors && giftData.colors.length > 0) newColors.push({ id: colorId, color: `#${giftData.colors[0].toString(16)}` }); } - setSelectedColorId(newColors[0].id); - setColors(newColors); + if(newColors.length) + { + setSelectedColorId(newColors[0].id); + setColors(newColors); + } }, [ giftConfiguration ]); const close = useCallback(() => @@ -68,7 +71,8 @@ export const CatalogGiftView: FC<{}> = props => setMessage(''); setSelectedBoxIndex(0); setSelectedRibbonIndex(0); - setSelectedColorId(colors[0].id); + + if(colors.length) setSelectedColorId(colors[0].id); }, [ colors ]); const onCatalogEvent = useCallback((event: CatalogEvent) => diff --git a/src/views/inventory/views/badge/InventoryBadgeView.tsx b/src/views/inventory/views/badge/InventoryBadgeView.tsx index 506db989..342cc15a 100644 --- a/src/views/inventory/views/badge/InventoryBadgeView.tsx +++ b/src/views/inventory/views/badge/InventoryBadgeView.tsx @@ -85,7 +85,7 @@ export const InventoryBadgeView: FC = props => - { LocalizeText('inventory.badges.activebadges') } + { LocalizeText('inventory.badges.activebadges') } { badge && (badge.length > 0) && diff --git a/src/views/notification-center/views/bubble-layouts/club-gift/NotificationClubGiftBubbleView.tsx b/src/views/notification-center/views/bubble-layouts/club-gift/NotificationClubGiftBubbleView.tsx index 0c03c440..e0913072 100644 --- a/src/views/notification-center/views/bubble-layouts/club-gift/NotificationClubGiftBubbleView.tsx +++ b/src/views/notification-center/views/bubble-layouts/club-gift/NotificationClubGiftBubbleView.tsx @@ -10,7 +10,7 @@ export const NotificationClubGiftBubbleView: FC +
{ LocalizeText('notifications.text.club_gift') } diff --git a/src/views/notification-center/views/bubble-layouts/default/NotificationDefaultBubbleView.tsx b/src/views/notification-center/views/bubble-layouts/default/NotificationDefaultBubbleView.tsx index 3e70b32c..4b748636 100644 --- a/src/views/notification-center/views/bubble-layouts/default/NotificationDefaultBubbleView.tsx +++ b/src/views/notification-center/views/bubble-layouts/default/NotificationDefaultBubbleView.tsx @@ -7,7 +7,7 @@ export const NotificationDefaultBubbleView: FC + { (item.iconUrl && item.iconUrl.length) && } { item.message } diff --git a/src/views/room/RoomView.tsx b/src/views/room/RoomView.tsx index 7c9e4252..2ad37017 100644 --- a/src/views/room/RoomView.tsx +++ b/src/views/room/RoomView.tsx @@ -1,6 +1,6 @@ import { EventDispatcher, NitroRectangle, RoomGeometry, RoomVariableEnum, Vector3d } from '@nitrots/nitro-renderer'; import { FC, useEffect, useRef, useState } from 'react'; -import { DispatchMouseEvent, DispatchTouchEvent, DoorbellWidgetHandler, FurniChooserWidgetHandler, FurnitureContextMenuWidgetHandler, FurnitureCreditWidgetHandler, FurnitureCustomStackHeightWidgetHandler, FurnitureDimmerWidgetHandler, FurnitureExternalImageWidgetHandler, FurniturePresentWidgetHandler, GetNitroInstance, GetRoomEngine, InitializeRoomInstanceRenderingCanvas, IRoomWidgetHandlerManager, RoomWidgetAvatarInfoHandler, RoomWidgetChatHandler, RoomWidgetChatInputHandler, RoomWidgetHandlerManager, RoomWidgetInfostandHandler, RoomWidgetRoomToolsHandler, RoomWidgetUpdateRoomViewEvent, UserChooserWidgetHandler } from '../../api'; +import { DispatchMouseEvent, DispatchTouchEvent, DoorbellWidgetHandler, FurniChooserWidgetHandler, FurnitureContextMenuWidgetHandler, FurnitureCreditWidgetHandler, FurnitureCustomStackHeightWidgetHandler, FurnitureDimmerWidgetHandler, FurnitureExternalImageWidgetHandler, FurnitureMannequinWidgetHandler, FurniturePresentWidgetHandler, GetNitroInstance, GetRoomEngine, InitializeRoomInstanceRenderingCanvas, IRoomWidgetHandlerManager, RoomWidgetAvatarInfoHandler, RoomWidgetChatHandler, RoomWidgetChatInputHandler, RoomWidgetHandlerManager, RoomWidgetInfostandHandler, RoomWidgetRoomToolsHandler, RoomWidgetUpdateRoomViewEvent, UserChooserWidgetHandler } from '../../api'; import { RoomContextProvider } from './context/RoomContext'; import { RoomColorView } from './RoomColorView'; import { RoomViewProps } from './RoomView.types'; @@ -44,6 +44,7 @@ export const RoomView: FC = props => widgetHandlerManager.registerHandler(new FurnitureExternalImageWidgetHandler()); widgetHandlerManager.registerHandler(new FurniturePresentWidgetHandler()); widgetHandlerManager.registerHandler(new FurnitureDimmerWidgetHandler()); + widgetHandlerManager.registerHandler(new FurnitureMannequinWidgetHandler()); setWidgetHandler(widgetHandlerManager); diff --git a/src/views/room/widgets/RoomWidgetsView.tsx b/src/views/room/widgets/RoomWidgetsView.tsx index 61e40bc6..3fd67cdc 100644 --- a/src/views/room/widgets/RoomWidgetsView.tsx +++ b/src/views/room/widgets/RoomWidgetsView.tsx @@ -1,6 +1,6 @@ import { RoomEngineEvent, RoomEngineObjectEvent, RoomEngineRoomAdEvent, RoomEngineTriggerWidgetEvent, RoomEngineUseProductEvent, RoomId, RoomObjectCategory, RoomObjectOperationType, RoomObjectVariable, RoomSessionChatEvent, RoomSessionDanceEvent, RoomSessionDimmerPresetsEvent, RoomSessionDoorbellEvent, RoomSessionErrorMessageEvent, RoomSessionEvent, RoomSessionFriendRequestEvent, RoomSessionPetInfoUpdateEvent, RoomSessionPresentEvent, RoomSessionUserBadgesEvent, RoomZoomEvent } from '@nitrots/nitro-renderer'; import { FC, useCallback } from 'react'; -import { CanManipulateFurniture, GetRoomEngine, GetSessionDataManager, IsFurnitureSelectionDisabled, LocalizeText, ProcessRoomObjectOperation, RoomWidgetFurniToWidgetMessage, RoomWidgetRoomEngineUpdateEvent, RoomWidgetRoomObjectUpdateEvent } from '../../../api'; +import { CanManipulateFurniture, GetRoomEngine, GetSessionDataManager, IsFurnitureSelectionDisabled, LocalizeText, ProcessRoomObjectOperation, RoomWidgetFurniToWidgetMessage, RoomWidgetUpdateRoomEngineEvent, RoomWidgetUpdateRoomObjectEvent } from '../../../api'; import { useRoomEngineEvent, useRoomSessionManagerEvent } from '../../../hooks/events'; import { NotificationAlertType } from '../../notification-center/common/NotificationAlertType'; import { NotificationUtilities } from '../../notification-center/common/NotificationUtilities'; @@ -27,10 +27,10 @@ export const RoomWidgetsView: FC = props => switch(event.type) { case RoomEngineEvent.NORMAL_MODE: - eventDispatcher.dispatchEvent(new RoomWidgetRoomEngineUpdateEvent(RoomWidgetRoomEngineUpdateEvent.NORMAL_MODE, event.roomId)); + eventDispatcher.dispatchEvent(new RoomWidgetUpdateRoomEngineEvent(RoomWidgetUpdateRoomEngineEvent.NORMAL_MODE, event.roomId)); return; case RoomEngineEvent.GAME_MODE: - eventDispatcher.dispatchEvent(new RoomWidgetRoomEngineUpdateEvent(RoomWidgetRoomEngineUpdateEvent.GAME_MODE, event.roomId)); + eventDispatcher.dispatchEvent(new RoomWidgetUpdateRoomEngineEvent(RoomWidgetUpdateRoomEngineEvent.GAME_MODE, event.roomId)); return; case RoomZoomEvent.ROOM_ZOOM: { const zoomEvent = (event as RoomZoomEvent); @@ -67,15 +67,15 @@ export const RoomWidgetsView: FC = props => const objectId = event.objectId; const category = event.category; - let updateEvent: RoomWidgetRoomObjectUpdateEvent = null; + let updateEvent: RoomWidgetUpdateRoomObjectEvent = null; switch(event.type) { case RoomEngineObjectEvent.SELECTED: - if(!IsFurnitureSelectionDisabled(event)) updateEvent = new RoomWidgetRoomObjectUpdateEvent(RoomWidgetRoomObjectUpdateEvent.OBJECT_SELECTED, objectId, category, event.roomId); + if(!IsFurnitureSelectionDisabled(event)) updateEvent = new RoomWidgetUpdateRoomObjectEvent(RoomWidgetUpdateRoomObjectEvent.OBJECT_SELECTED, objectId, category, event.roomId); break; case RoomEngineObjectEvent.DESELECTED: - updateEvent = new RoomWidgetRoomObjectUpdateEvent(RoomWidgetRoomObjectUpdateEvent.OBJECT_DESELECTED, objectId, category, event.roomId); + updateEvent = new RoomWidgetUpdateRoomObjectEvent(RoomWidgetUpdateRoomObjectEvent.OBJECT_DESELECTED, objectId, category, event.roomId); break; case RoomEngineObjectEvent.ADDED: { let addedEventType: string = null; @@ -84,14 +84,14 @@ export const RoomWidgetsView: FC = props => { case RoomObjectCategory.FLOOR: case RoomObjectCategory.WALL: - addedEventType = RoomWidgetRoomObjectUpdateEvent.FURNI_ADDED; + addedEventType = RoomWidgetUpdateRoomObjectEvent.FURNI_ADDED; break; case RoomObjectCategory.UNIT: - addedEventType = RoomWidgetRoomObjectUpdateEvent.USER_ADDED; + addedEventType = RoomWidgetUpdateRoomObjectEvent.USER_ADDED; break; } - if(addedEventType) updateEvent = new RoomWidgetRoomObjectUpdateEvent(addedEventType, objectId, category, event.roomId); + if(addedEventType) updateEvent = new RoomWidgetUpdateRoomObjectEvent(addedEventType, objectId, category, event.roomId); break; } case RoomEngineObjectEvent.REMOVED: { @@ -101,14 +101,14 @@ export const RoomWidgetsView: FC = props => { case RoomObjectCategory.FLOOR: case RoomObjectCategory.WALL: - removedEventType = RoomWidgetRoomObjectUpdateEvent.FURNI_REMOVED; + removedEventType = RoomWidgetUpdateRoomObjectEvent.FURNI_REMOVED; break; case RoomObjectCategory.UNIT: - removedEventType = RoomWidgetRoomObjectUpdateEvent.USER_REMOVED; + removedEventType = RoomWidgetUpdateRoomObjectEvent.USER_REMOVED; break; } - if(removedEventType) updateEvent = new RoomWidgetRoomObjectUpdateEvent(removedEventType, objectId, category, event.roomId); + if(removedEventType) updateEvent = new RoomWidgetUpdateRoomObjectEvent(removedEventType, objectId, category, event.roomId); break; } case RoomEngineObjectEvent.REQUEST_MOVE: @@ -118,13 +118,13 @@ export const RoomWidgetsView: FC = props => if(CanManipulateFurniture(roomSession, objectId, category)) ProcessRoomObjectOperation(objectId, category, RoomObjectOperationType.OBJECT_ROTATE_POSITIVE); break; case RoomEngineObjectEvent.REQUEST_MANIPULATION: - if(CanManipulateFurniture(roomSession, objectId, category)) updateEvent = new RoomWidgetRoomObjectUpdateEvent(RoomWidgetRoomObjectUpdateEvent.OBJECT_REQUEST_MANIPULATION, objectId, category, event.roomId); + if(CanManipulateFurniture(roomSession, objectId, category)) updateEvent = new RoomWidgetUpdateRoomObjectEvent(RoomWidgetUpdateRoomObjectEvent.OBJECT_REQUEST_MANIPULATION, objectId, category, event.roomId); break; case RoomEngineObjectEvent.MOUSE_ENTER: - updateEvent = new RoomWidgetRoomObjectUpdateEvent(RoomWidgetRoomObjectUpdateEvent.OBJECT_ROLL_OVER, objectId, category, event.roomId); + updateEvent = new RoomWidgetUpdateRoomObjectEvent(RoomWidgetUpdateRoomObjectEvent.OBJECT_ROLL_OVER, objectId, category, event.roomId); break; case RoomEngineObjectEvent.MOUSE_LEAVE: - updateEvent = new RoomWidgetRoomObjectUpdateEvent(RoomWidgetRoomObjectUpdateEvent.OBJECT_ROLL_OUT, objectId, category, event.roomId); + updateEvent = new RoomWidgetUpdateRoomObjectEvent(RoomWidgetUpdateRoomObjectEvent.OBJECT_ROLL_OUT, objectId, category, event.roomId); break; case RoomEngineTriggerWidgetEvent.REQUEST_CREDITFURNI: widgetHandler.processWidgetMessage(new RoomWidgetFurniToWidgetMessage(RoomWidgetFurniToWidgetMessage.REQUEST_CREDITFURNI, objectId, category, event.roomId)); @@ -202,7 +202,7 @@ export const RoomWidgetsView: FC = props => { let dispatchEvent = true; - if(updateEvent instanceof RoomWidgetRoomObjectUpdateEvent) dispatchEvent = (!RoomId.isRoomPreviewerId(updateEvent.roomId)); + if(updateEvent instanceof RoomWidgetUpdateRoomObjectEvent) dispatchEvent = (!RoomId.isRoomPreviewerId(updateEvent.roomId)); if(dispatchEvent) widgetHandler.eventDispatcher.dispatchEvent(updateEvent); } diff --git a/src/views/room/widgets/avatar-info/AvatarInfoWidgetView.tsx b/src/views/room/widgets/avatar-info/AvatarInfoWidgetView.tsx index a12d17bc..7014b2f7 100644 --- a/src/views/room/widgets/avatar-info/AvatarInfoWidgetView.tsx +++ b/src/views/room/widgets/avatar-info/AvatarInfoWidgetView.tsx @@ -1,6 +1,6 @@ import { RoomEnterEffect, RoomObjectCategory } from '@nitrots/nitro-renderer'; import { FC, useCallback, useMemo, useState } from 'react'; -import { GetRoomSession, GetSessionDataManager, RoomWidgetObjectNameEvent, RoomWidgetRoomEngineUpdateEvent, RoomWidgetRoomObjectMessage, RoomWidgetRoomObjectUpdateEvent, RoomWidgetUpdateDanceStatusEvent, RoomWidgetUpdateDecorateModeEvent, RoomWidgetUpdateInfostandEvent, RoomWidgetUpdateInfostandFurniEvent, RoomWidgetUpdateInfostandPetEvent, RoomWidgetUpdateInfostandRentableBotEvent, RoomWidgetUpdateInfostandUserEvent, RoomWidgetUpdateRentableBotChatEvent, RoomWidgetUseProductBubbleEvent, UseProductItem } from '../../../../api'; +import { GetRoomSession, GetSessionDataManager, RoomWidgetObjectNameEvent, RoomWidgetRoomObjectMessage, RoomWidgetUpdateDanceStatusEvent, RoomWidgetUpdateDecorateModeEvent, RoomWidgetUpdateInfostandEvent, RoomWidgetUpdateInfostandFurniEvent, RoomWidgetUpdateInfostandPetEvent, RoomWidgetUpdateInfostandRentableBotEvent, RoomWidgetUpdateInfostandUserEvent, RoomWidgetUpdateRentableBotChatEvent, RoomWidgetUpdateRoomEngineEvent, RoomWidgetUpdateRoomObjectEvent, RoomWidgetUseProductBubbleEvent, UseProductItem } from '../../../../api'; import { CreateEventDispatcherHook } from '../../../../hooks/events/event-dispatcher.base'; import { useRoomContext } from '../../context/RoomContext'; import { AvatarInfoWidgetAvatarView } from './views/avatar/AvatarInfoWidgetAvatarView'; @@ -73,25 +73,25 @@ export const AvatarInfoWidgetView: FC<{}> = props => setProductBubbles([]); }, []); - const onRoomWidgetRoomEngineUpdateEvent = useCallback((event: RoomWidgetRoomEngineUpdateEvent) => + const onRoomWidgetRoomEngineUpdateEvent = useCallback((event: RoomWidgetUpdateRoomEngineEvent) => { switch(event.type) { - case RoomWidgetRoomEngineUpdateEvent.NORMAL_MODE: { + case RoomWidgetUpdateRoomEngineEvent.NORMAL_MODE: { if(isGameMode) setGameMode(false); return; } - case RoomWidgetRoomEngineUpdateEvent.GAME_MODE: { + case RoomWidgetUpdateRoomEngineEvent.GAME_MODE: { if(!isGameMode) setGameMode(true); return; } } }, [ isGameMode ]); - CreateEventDispatcherHook(RoomWidgetRoomEngineUpdateEvent.NORMAL_MODE, eventDispatcher, onRoomWidgetRoomEngineUpdateEvent); - CreateEventDispatcherHook(RoomWidgetRoomEngineUpdateEvent.GAME_MODE, eventDispatcher, onRoomWidgetRoomEngineUpdateEvent); + CreateEventDispatcherHook(RoomWidgetUpdateRoomEngineEvent.NORMAL_MODE, eventDispatcher, onRoomWidgetRoomEngineUpdateEvent); + CreateEventDispatcherHook(RoomWidgetUpdateRoomEngineEvent.GAME_MODE, eventDispatcher, onRoomWidgetRoomEngineUpdateEvent); - const onRoomObjectRemoved = useCallback((event: RoomWidgetRoomObjectUpdateEvent) => + const onRoomObjectRemoved = useCallback((event: RoomWidgetUpdateRoomObjectEvent) => { if(name) { @@ -152,15 +152,15 @@ export const AvatarInfoWidgetView: FC<{}> = props => } }, [ name, infoStandEvent, nameBubbles, productBubbles, removeNameBubble, clearInfoStandEvent ]); - CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.USER_REMOVED, eventDispatcher, onRoomObjectRemoved); - CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.FURNI_REMOVED, eventDispatcher, onRoomObjectRemoved); + CreateEventDispatcherHook(RoomWidgetUpdateRoomObjectEvent.USER_REMOVED, eventDispatcher, onRoomObjectRemoved); + CreateEventDispatcherHook(RoomWidgetUpdateRoomObjectEvent.FURNI_REMOVED, eventDispatcher, onRoomObjectRemoved); - const onObjectRolled = useCallback((event: RoomWidgetRoomObjectUpdateEvent) => + const onObjectRolled = useCallback((event: RoomWidgetUpdateRoomObjectEvent) => { switch(event.type) { - case RoomWidgetRoomObjectUpdateEvent.OBJECT_ROLL_OVER: { - const roomObjectEvent = (event as RoomWidgetRoomObjectUpdateEvent); + case RoomWidgetUpdateRoomObjectEvent.OBJECT_ROLL_OVER: { + const roomObjectEvent = (event as RoomWidgetUpdateRoomObjectEvent); if(infoStandEvent) return; @@ -168,8 +168,8 @@ export const AvatarInfoWidgetView: FC<{}> = props => return; } - case RoomWidgetRoomObjectUpdateEvent.OBJECT_ROLL_OUT: { - const roomObjectEvent = (event as RoomWidgetRoomObjectUpdateEvent); + case RoomWidgetUpdateRoomObjectEvent.OBJECT_ROLL_OUT: { + const roomObjectEvent = (event as RoomWidgetUpdateRoomObjectEvent); if(!name || (name.roomIndex !== roomObjectEvent.id)) return; @@ -180,16 +180,16 @@ export const AvatarInfoWidgetView: FC<{}> = props => } }, [ infoStandEvent, name, widgetHandler ]); - CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.OBJECT_ROLL_OVER, eventDispatcher, onObjectRolled); - CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.OBJECT_ROLL_OUT, eventDispatcher, onObjectRolled); + CreateEventDispatcherHook(RoomWidgetUpdateRoomObjectEvent.OBJECT_ROLL_OVER, eventDispatcher, onObjectRolled); + CreateEventDispatcherHook(RoomWidgetUpdateRoomObjectEvent.OBJECT_ROLL_OUT, eventDispatcher, onObjectRolled); - const onObjectDeselected = useCallback((event: RoomWidgetRoomObjectUpdateEvent) => + const onObjectDeselected = useCallback((event: RoomWidgetUpdateRoomObjectEvent) => { if(infoStandEvent) clearInfoStandEvent(); if(productBubbles.length) setProductBubbles([]); }, [ infoStandEvent, productBubbles, clearInfoStandEvent ]); - CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.OBJECT_DESELECTED, eventDispatcher, onObjectDeselected); + CreateEventDispatcherHook(RoomWidgetUpdateRoomObjectEvent.OBJECT_DESELECTED, eventDispatcher, onObjectDeselected); const onRoomWidgetObjectNameEvent = useCallback((event: RoomWidgetObjectNameEvent) => { diff --git a/src/views/room/widgets/chat-input/ChatInputView.scss b/src/views/room/widgets/chat-input/ChatInputView.scss index 90f754e5..d2814d44 100644 --- a/src/views/room/widgets/chat-input/ChatInputView.scss +++ b/src/views/room/widgets/chat-input/ChatInputView.scss @@ -71,7 +71,7 @@ max-height: $chat-input-style-selector-widget-height; .content-area { - max-height: $chat-input-style-selector-widget-height; + max-height: $chat-input-style-selector-widget-height !important; } .grid-item { diff --git a/src/views/room/widgets/chat-input/ChatInputView.tsx b/src/views/room/widgets/chat-input/ChatInputView.tsx index 4ad7f3ba..ca2b54d7 100644 --- a/src/views/room/widgets/chat-input/ChatInputView.tsx +++ b/src/views/room/widgets/chat-input/ChatInputView.tsx @@ -1,7 +1,7 @@ import { HabboClubLevelEnum, RoomControllerLevel } from '@nitrots/nitro-renderer'; import { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { createPortal } from 'react-dom'; -import { GetConfiguration, GetSessionDataManager, LocalizeText, RoomWidgetChatMessage, RoomWidgetChatTypingMessage, RoomWidgetRoomObjectUpdateEvent, RoomWidgetUpdateChatInputContentEvent, RoomWidgetUpdateInfostandUserEvent } from '../../../../api'; +import { GetConfiguration, GetSessionDataManager, LocalizeText, RoomWidgetChatMessage, RoomWidgetChatTypingMessage, RoomWidgetUpdateChatInputContentEvent, RoomWidgetUpdateInfostandUserEvent, RoomWidgetUpdateRoomObjectEvent } from '../../../../api'; import { CreateEventDispatcherHook } from '../../../../hooks/events'; import { useRoomContext } from '../../context/RoomContext'; import { ChatInputStyleSelectorView } from './style-selector/ChatInputStyleSelectorView'; @@ -177,12 +177,12 @@ export const ChatInputView: FC<{}> = props => }, [ inputRef, chatModeIdWhisper, anotherInputHasFocus, setInputFocus, checkSpecialKeywordForInput, sendChatValue ]); - const onRoomWidgetRoomObjectUpdateEvent = useCallback((event: RoomWidgetRoomObjectUpdateEvent) => + const onRoomWidgetRoomObjectUpdateEvent = useCallback((event: RoomWidgetUpdateRoomObjectEvent) => { setSelectedUsername(''); }, []); - CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.OBJECT_DESELECTED, eventDispatcher, onRoomWidgetRoomObjectUpdateEvent); + CreateEventDispatcherHook(RoomWidgetUpdateRoomObjectEvent.OBJECT_DESELECTED, eventDispatcher, onRoomWidgetRoomObjectUpdateEvent); const onRoomWidgetUpdateInfostandUserEvent = useCallback((event: RoomWidgetUpdateInfostandUserEvent) => { diff --git a/src/views/room/widgets/choosers/FurniChooserWidgetView.tsx b/src/views/room/widgets/choosers/FurniChooserWidgetView.tsx index ac257419..68a2971f 100644 --- a/src/views/room/widgets/choosers/FurniChooserWidgetView.tsx +++ b/src/views/room/widgets/choosers/FurniChooserWidgetView.tsx @@ -1,5 +1,5 @@ import { FC, useCallback, useState } from 'react'; -import { LocalizeText, RoomObjectItem, RoomWidgetChooserContentEvent, RoomWidgetRequestWidgetMessage, RoomWidgetRoomObjectUpdateEvent } from '../../../../api'; +import { LocalizeText, RoomObjectItem, RoomWidgetChooserContentEvent, RoomWidgetRequestWidgetMessage, RoomWidgetUpdateRoomObjectEvent } from '../../../../api'; import { CreateEventDispatcherHook } from '../../../../hooks'; import { useRoomContext } from '../../context/RoomContext'; import { ChooserWidgetView } from './ChooserWidgetView'; @@ -31,21 +31,21 @@ export const FurniChooserWidgetView: FC<{}> = props => CreateEventDispatcherHook(RoomWidgetChooserContentEvent.FURNI_CHOOSER_CONTENT, eventDispatcher, onRoomWidgetChooserContentEvent); - const onRoomWidgetRoomObjectUpdateEvent = useCallback((event: RoomWidgetRoomObjectUpdateEvent) => + const onRoomWidgetRoomObjectUpdateEvent = useCallback((event: RoomWidgetUpdateRoomObjectEvent) => { if(!isVisible) return; switch(event.type) { - case RoomWidgetRoomObjectUpdateEvent.FURNI_ADDED: - case RoomWidgetRoomObjectUpdateEvent.FURNI_REMOVED: + case RoomWidgetUpdateRoomObjectEvent.FURNI_ADDED: + case RoomWidgetUpdateRoomObjectEvent.FURNI_REMOVED: refreshChooser(); return; } }, [ isVisible, refreshChooser ]); - CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.FURNI_ADDED, eventDispatcher, onRoomWidgetRoomObjectUpdateEvent); - CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.FURNI_REMOVED, eventDispatcher, onRoomWidgetRoomObjectUpdateEvent); + CreateEventDispatcherHook(RoomWidgetUpdateRoomObjectEvent.FURNI_ADDED, eventDispatcher, onRoomWidgetRoomObjectUpdateEvent); + CreateEventDispatcherHook(RoomWidgetUpdateRoomObjectEvent.FURNI_REMOVED, eventDispatcher, onRoomWidgetRoomObjectUpdateEvent); const close = useCallback(() => { diff --git a/src/views/room/widgets/choosers/UserChooserWidgetView.tsx b/src/views/room/widgets/choosers/UserChooserWidgetView.tsx index 327b7bd2..b9ab2460 100644 --- a/src/views/room/widgets/choosers/UserChooserWidgetView.tsx +++ b/src/views/room/widgets/choosers/UserChooserWidgetView.tsx @@ -1,5 +1,5 @@ import { FC, useCallback, useState } from 'react'; -import { LocalizeText, RoomObjectItem, RoomWidgetChooserContentEvent, RoomWidgetRequestWidgetMessage, RoomWidgetRoomObjectUpdateEvent } from '../../../../api'; +import { LocalizeText, RoomObjectItem, RoomWidgetChooserContentEvent, RoomWidgetRequestWidgetMessage, RoomWidgetUpdateRoomObjectEvent } from '../../../../api'; import { CreateEventDispatcherHook } from '../../../../hooks'; import { useRoomContext } from '../../context/RoomContext'; import { ChooserWidgetView } from './ChooserWidgetView'; @@ -31,21 +31,21 @@ export const UserChooserWidgetView: FC<{}> = props => CreateEventDispatcherHook(RoomWidgetChooserContentEvent.USER_CHOOSER_CONTENT, eventDispatcher, onRoomWidgetChooserContentEvent); - const onRoomWidgetRoomObjectUpdateEvent = useCallback((event: RoomWidgetRoomObjectUpdateEvent) => + const onRoomWidgetRoomObjectUpdateEvent = useCallback((event: RoomWidgetUpdateRoomObjectEvent) => { if(!isVisible) return; switch(event.type) { - case RoomWidgetRoomObjectUpdateEvent.USER_ADDED: - case RoomWidgetRoomObjectUpdateEvent.USER_REMOVED: + case RoomWidgetUpdateRoomObjectEvent.USER_ADDED: + case RoomWidgetUpdateRoomObjectEvent.USER_REMOVED: refreshChooser(); return; } }, [ isVisible, refreshChooser ]); - CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.USER_ADDED, eventDispatcher, onRoomWidgetRoomObjectUpdateEvent); - CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.USER_REMOVED, eventDispatcher, onRoomWidgetRoomObjectUpdateEvent); + CreateEventDispatcherHook(RoomWidgetUpdateRoomObjectEvent.USER_ADDED, eventDispatcher, onRoomWidgetRoomObjectUpdateEvent); + CreateEventDispatcherHook(RoomWidgetUpdateRoomObjectEvent.USER_REMOVED, eventDispatcher, onRoomWidgetRoomObjectUpdateEvent); const close = useCallback(() => { diff --git a/src/views/room/widgets/context-menu/ContextMenu.scss b/src/views/room/widgets/context-menu/ContextMenu.scss index 4df6199d..b9e313d1 100644 --- a/src/views/room/widgets/context-menu/ContextMenu.scss +++ b/src/views/room/widgets/context-menu/ContextMenu.scss @@ -7,6 +7,7 @@ border-radius: $border-radius; font-size: $font-size-sm; z-index: $context-menu-zindex; + pointer-events: all; &.name-only { background-color: rgba($black, 0.5); @@ -34,8 +35,7 @@ .menu-header { background-color: $william; color: $white; - width: 117px; - max-width: 117px; + min-width: 117px; height: 25px; max-height: 25px; font-size: 16px; diff --git a/src/views/room/widgets/furniture/FurnitureWidgets.scss b/src/views/room/widgets/furniture/FurnitureWidgets.scss index 0fe453bc..563b6733 100644 --- a/src/views/room/widgets/furniture/FurnitureWidgets.scss +++ b/src/views/room/widgets/furniture/FurnitureWidgets.scss @@ -1,3 +1,9 @@ +.nitro-room-widgets { + pointer-events: none; +} + +@import './custom-stack-height/FurnitureCustomStackHeightView'; + @import './dimmer/FurnitureDimmerView'; @import './exchange-credit/FurnitureExchangeCreditView'; @import './external-image/FurnitureExternalImageView'; diff --git a/src/views/room/widgets/furniture/FurnitureWidgetsView.tsx b/src/views/room/widgets/furniture/FurnitureWidgetsView.tsx index 2d152199..16663637 100644 --- a/src/views/room/widgets/furniture/FurnitureWidgetsView.tsx +++ b/src/views/room/widgets/furniture/FurnitureWidgetsView.tsx @@ -17,7 +17,7 @@ import { FurnitureTrophyView } from './trophy/FurnitureTrophyView'; export const FurnitureWidgetsView: FC<{}> = props => { return ( -
+
diff --git a/src/views/room/widgets/furniture/background-color/FurnitureBackgroundColorView.tsx b/src/views/room/widgets/furniture/background-color/FurnitureBackgroundColorView.tsx index 7b2e335e..a29c5454 100644 --- a/src/views/room/widgets/furniture/background-color/FurnitureBackgroundColorView.tsx +++ b/src/views/room/widgets/furniture/background-color/FurnitureBackgroundColorView.tsx @@ -1,7 +1,7 @@ import { ApplyTonerComposer, RoomControllerLevel, RoomEngineObjectEvent, RoomEngineTriggerWidgetEvent, RoomObjectVariable } from '@nitrots/nitro-renderer'; import { FC, useCallback, useEffect, useState } from 'react'; import ReactSlider from 'react-slider'; -import { GetRoomEngine, GetSessionDataManager, LocalizeText, RoomWidgetRoomObjectUpdateEvent, RoomWidgetUpdateBackgroundColorPreviewEvent } from '../../../../../api'; +import { GetRoomEngine, GetSessionDataManager, LocalizeText, RoomWidgetUpdateBackgroundColorPreviewEvent, RoomWidgetUpdateRoomObjectEvent } from '../../../../../api'; import { SendMessageHook } from '../../../../../hooks'; import { CreateEventDispatcherHook, useRoomEngineEvent } from '../../../../../hooks/events'; import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../../layout'; @@ -48,7 +48,7 @@ export const FurnitureBackgroundColorView: FC<{}> = props => return; } - case RoomWidgetRoomObjectUpdateEvent.FURNI_REMOVED: { + case RoomWidgetUpdateRoomObjectEvent.FURNI_REMOVED: { if(objectId !== event.objectId) return; close(); @@ -58,7 +58,7 @@ export const FurnitureBackgroundColorView: FC<{}> = props => }, [ objectId, canOpenBackgroundToner, close ]); useRoomEngineEvent(RoomEngineTriggerWidgetEvent.REQUEST_BACKGROUND_COLOR, onRoomEngineObjectEvent); - CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.FURNI_REMOVED, eventDispatcher, onRoomEngineObjectEvent); + CreateEventDispatcherHook(RoomWidgetUpdateRoomObjectEvent.FURNI_REMOVED, eventDispatcher, onRoomEngineObjectEvent); const processAction = useCallback((name: string) => { diff --git a/src/views/room/widgets/furniture/badge-display/FurnitureBadgeDisplayView.tsx b/src/views/room/widgets/furniture/badge-display/FurnitureBadgeDisplayView.tsx index c9c5fbde..9615bce6 100644 --- a/src/views/room/widgets/furniture/badge-display/FurnitureBadgeDisplayView.tsx +++ b/src/views/room/widgets/furniture/badge-display/FurnitureBadgeDisplayView.tsx @@ -1,6 +1,6 @@ import { NitroEvent, RoomEngineTriggerWidgetEvent, StringDataType } from '@nitrots/nitro-renderer'; import { FC, useCallback, useState } from 'react'; -import { GetRoomEngine, LocalizeBadgeDescription, LocalizeBadgeName, RoomWidgetRoomObjectUpdateEvent } from '../../../../../api'; +import { GetRoomEngine, LocalizeBadgeDescription, LocalizeBadgeName, RoomWidgetUpdateRoomObjectEvent } from '../../../../../api'; import { CreateEventDispatcherHook } from '../../../../../hooks'; import { useRoomEngineEvent } from '../../../../../hooks/events/nitro/room/room-engine-event'; import { NitroLayoutTrophyView } from '../../../../../layout'; @@ -36,8 +36,8 @@ export const FurnitureBadgeDisplayView: FC<{}> = props => setTrophyData(new FurnitureTrophyData(widgetEvent.objectId, widgetEvent.category, '1', senderName, date, badgeDesc, badgeName)); return; } - case RoomWidgetRoomObjectUpdateEvent.FURNI_REMOVED: { - const widgetEvent = (event as RoomWidgetRoomObjectUpdateEvent); + case RoomWidgetUpdateRoomObjectEvent.FURNI_REMOVED: { + const widgetEvent = (event as RoomWidgetUpdateRoomObjectEvent); setTrophyData(prevState => { @@ -52,7 +52,7 @@ export const FurnitureBadgeDisplayView: FC<{}> = props => useRoomEngineEvent(RoomEngineTriggerWidgetEvent.REQUEST_BADGE_DISPLAY_ENGRAVING, onNitroEvent); useRoomEngineEvent(RoomEngineTriggerWidgetEvent.REQUEST_ACHIEVEMENT_RESOLUTION_ENGRAVING, onNitroEvent); - CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.FURNI_REMOVED, widgetHandler.eventDispatcher, onNitroEvent); + CreateEventDispatcherHook(RoomWidgetUpdateRoomObjectEvent.FURNI_REMOVED, widgetHandler.eventDispatcher, onNitroEvent); const processAction = useCallback((type: string, value: string = null) => { diff --git a/src/views/room/widgets/furniture/custom-stack-height/FurnitureCustomStackHeightView.scss b/src/views/room/widgets/furniture/custom-stack-height/FurnitureCustomStackHeightView.scss new file mode 100644 index 00000000..755c73d1 --- /dev/null +++ b/src/views/room/widgets/furniture/custom-stack-height/FurnitureCustomStackHeightView.scss @@ -0,0 +1,4 @@ +.nitro-widget-custom-stack-height { + width: $nitro-widget-custom-stack-height-width; + height: $nitro-widget-custom-stack-height-height; +} diff --git a/src/views/room/widgets/furniture/custom-stack-height/FurnitureCustomStackHeightView.tsx b/src/views/room/widgets/furniture/custom-stack-height/FurnitureCustomStackHeightView.tsx index 16f976a2..0b7c7ee1 100644 --- a/src/views/room/widgets/furniture/custom-stack-height/FurnitureCustomStackHeightView.tsx +++ b/src/views/room/widgets/furniture/custom-stack-height/FurnitureCustomStackHeightView.tsx @@ -2,9 +2,10 @@ import { FurnitureStackHeightComposer, FurnitureStackHeightEvent } from '@nitrot import { FC, useCallback, useEffect, useState } from 'react'; import ReactSlider from 'react-slider'; import { LocalizeText, RoomWidgetUpdateCustomStackHeightEvent } from '../../../../../api'; -import { CreateMessageHook, SendMessageHook } from '../../../../../hooks'; +import { BatchUpdates, CreateMessageHook, SendMessageHook } from '../../../../../hooks'; import { CreateEventDispatcherHook } from '../../../../../hooks/events'; -import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../../layout'; +import { NitroCardContentView, NitroCardHeaderView, NitroCardView, NitroLayoutButton, NitroLayoutFlex, NitroLayoutFlexColumn, NitroLayoutGrid, NitroLayoutGridColumn } from '../../../../../layout'; +import { NitroLayoutBase } from '../../../../../layout/base'; import { useRoomContext } from '../../../context/RoomContext'; const MAX_HEIGHT: number = 40; @@ -14,13 +15,15 @@ export const FurnitureCustomStackHeightView: FC<{}> = props => const [ objectId, setObjectId ] = useState(-1); const [ height, setHeight ] = useState(0); const [ pendingHeight, setPendingHeight ] = useState(-1); - - const { roomSession = null, eventDispatcher = null } = useRoomContext(); + const { eventDispatcher = null } = useRoomContext(); const close = useCallback(() => { - setObjectId(-1); - setHeight(0); + BatchUpdates(() => + { + setObjectId(-1); + setHeight(0); + }); }, []); const updateHeight = useCallback((height: number, fromServer: boolean = false) => @@ -31,9 +34,12 @@ export const FurnitureCustomStackHeightView: FC<{}> = props => if(!fromServer) ((height > MAX_HEIGHT) && (height = MAX_HEIGHT)); - setHeight(parseFloat(height.toFixed(2))); + BatchUpdates(() => + { + setHeight(parseFloat(height.toFixed(2))); - if(!fromServer) setPendingHeight(height * 100); + if(!fromServer) setPendingHeight(height * 100); + }); }, []); const onRoomWidgetUpdateCustomStackHeightEvent = useCallback((event: RoomWidgetUpdateCustomStackHeightEvent) => @@ -65,16 +71,6 @@ export const FurnitureCustomStackHeightView: FC<{}> = props => SendMessageHook(new FurnitureStackHeightComposer(objectId, ~~(height))); }, [ objectId ]); - const placeAboveStack = useCallback(() => - { - sendUpdate(-100); - }, [ sendUpdate ]); - - const placeAtFloor = useCallback(() => - { - sendUpdate(0); - }, [ sendUpdate ]); - useEffect(() => { if((objectId === -1) || (pendingHeight === -1)) return; @@ -87,27 +83,35 @@ export const FurnitureCustomStackHeightView: FC<{}> = props => if(objectId === -1) return null; return ( - + -
- - updateHeight(event) } - renderThumb={ (props, state) =>
{ state.valueNow }
} /> -
-
- updateHeight(parseFloat(event.target.value)) } /> -
-
- - -
+ + + + { LocalizeText('widget.custom.stack.height.text') } + + + + updateHeight(event) } + renderThumb={ (props, state) =>
{ state.valueNow }
} /> + updateHeight(parseFloat(event.target.value)) } /> +
+ sendUpdate(-100) }> + { LocalizeText('furniture.above.stack') } + + sendUpdate(0) }> + { LocalizeText('furniture.floor.level') } + +
+
+
); diff --git a/src/views/room/widgets/furniture/exchange-credit/FurnitureExchangeCreditView.scss b/src/views/room/widgets/furniture/exchange-credit/FurnitureExchangeCreditView.scss index 34b1b665..4c286c5e 100644 --- a/src/views/room/widgets/furniture/exchange-credit/FurnitureExchangeCreditView.scss +++ b/src/views/room/widgets/furniture/exchange-credit/FurnitureExchangeCreditView.scss @@ -1,3 +1,10 @@ -.nitro-exchange-credit { - width: 290px; +.nitro-widget-exchange-credit { + width: $nitro-widget-exchange-credit-width; + height: $nitro-widget-exchange-credit-height; + + .exchange-image { + background-image: url('../../../../../assets/images/room-widgets/exchange-credit/exchange-credit-image.png'); + width: 103px; + height: 103px; + } } diff --git a/src/views/room/widgets/furniture/exchange-credit/FurnitureExchangeCreditView.tsx b/src/views/room/widgets/furniture/exchange-credit/FurnitureExchangeCreditView.tsx index e8f6387b..2ee5d497 100644 --- a/src/views/room/widgets/furniture/exchange-credit/FurnitureExchangeCreditView.tsx +++ b/src/views/room/widgets/furniture/exchange-credit/FurnitureExchangeCreditView.tsx @@ -2,7 +2,8 @@ import { FC, useCallback, useState } from 'react'; import { LocalizeText, RoomWidgetCreditFurniRedeemMessage, RoomWidgetUpdateCreditFurniEvent } from '../../../../../api'; import { BatchUpdates } from '../../../../../hooks'; import { CreateEventDispatcherHook } from '../../../../../hooks/events/event-dispatcher.base'; -import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../../layout'; +import { NitroCardContentView, NitroCardHeaderView, NitroCardView, NitroLayoutButton, NitroLayoutFlexColumn, NitroLayoutGrid, NitroLayoutGridColumn } from '../../../../../layout'; +import { NitroLayoutBase } from '../../../../../layout/base'; import { useRoomContext } from '../../../context/RoomContext'; export const FurnitureExchangeCreditView: FC<{}> = props => @@ -19,35 +20,46 @@ export const FurnitureExchangeCreditView: FC<{}> = props => CreateEventDispatcherHook(RoomWidgetUpdateCreditFurniEvent.CREDIT_FURNI_UPDATE, eventDispatcher, onRoomWidgetUpdateCreditFurniEvent); - const processAction = useCallback((type: string, value: string = null) => + const close = useCallback(() => { - switch(type) + BatchUpdates(() => { - case 'close': - BatchUpdates(() => - { - setObjectId(-1); - setValue(0); - }); - return; - case 'redeem': - widgetHandler.processWidgetMessage(new RoomWidgetCreditFurniRedeemMessage(RoomWidgetCreditFurniRedeemMessage.REDEEM, objectId)); + setObjectId(-1); + setValue(0); + }); + }, []); - processAction('close'); - return; - } - }, [ widgetHandler, objectId ]); + const redeem = useCallback(() => + { + widgetHandler.processWidgetMessage(new RoomWidgetCreditFurniRedeemMessage(RoomWidgetCreditFurniRedeemMessage.REDEEM, objectId)); + + close(); + }, [ widgetHandler, objectId, close ]); if(objectId === -1) return null; return ( - - processAction('close') } /> + + -
- { LocalizeText('widgets.furniture.credit.redeem.value', [ 'value' ], [ value.toString() ]) } -
- + + + + + + + + { LocalizeText('creditfurni.description', [ 'credits' ], [ value.toString() ]) } + + + { LocalizeText('creditfurni.prompt') } + + + + { LocalizeText('catalog.redeem.dialog.button.exchange') } + + +
); diff --git a/src/views/room/widgets/furniture/friend-furni/FurnitureFriendFurniView.tsx b/src/views/room/widgets/furniture/friend-furni/FurnitureFriendFurniView.tsx index c8b5eb0b..b9c8163c 100644 --- a/src/views/room/widgets/furniture/friend-furni/FurnitureFriendFurniView.tsx +++ b/src/views/room/widgets/furniture/friend-furni/FurnitureFriendFurniView.tsx @@ -1,6 +1,6 @@ import { FriendFurniConfirmLockMessageComposer, LoveLockFurniFinishedEvent, LoveLockFurniFriendConfirmedEvent, LoveLockFurniStartEvent, NitroEvent, RoomEngineTriggerWidgetEvent, RoomObjectVariable } from '@nitrots/nitro-renderer'; import { FC, useCallback, useState } from 'react'; -import { GetRoomEngine, GetRoomSession, LocalizeText, RoomWidgetRoomObjectUpdateEvent } from '../../../../../api'; +import { GetRoomEngine, GetRoomSession, LocalizeText, RoomWidgetUpdateRoomObjectEvent } from '../../../../../api'; import { CreateEventDispatcherHook } from '../../../../../hooks/events/event-dispatcher.base'; import { useRoomEngineEvent } from '../../../../../hooks/events/nitro/room/room-engine-event'; import { CreateMessageHook } from '../../../../../hooks/messages/message-event'; @@ -37,8 +37,8 @@ export const FurnitureFriendFurniView: FC<{}> = props => } return; } - case RoomWidgetRoomObjectUpdateEvent.FURNI_REMOVED: { - const widgetEvent = (event as RoomWidgetRoomObjectUpdateEvent); + case RoomWidgetUpdateRoomObjectEvent.FURNI_REMOVED: { + const widgetEvent = (event as RoomWidgetUpdateRoomObjectEvent); setEngravingLockData(prevState => { @@ -52,7 +52,7 @@ export const FurnitureFriendFurniView: FC<{}> = props => }; useRoomEngineEvent(RoomEngineTriggerWidgetEvent.REQUEST_FRIEND_FURNITURE_ENGRAVING, onNitroEvent); - CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.FURNI_REMOVED, eventDispatcher, onNitroEvent); + CreateEventDispatcherHook(RoomWidgetUpdateRoomObjectEvent.FURNI_REMOVED, eventDispatcher, onNitroEvent); const onLoveLockFurniStartEvent = useCallback((event: LoveLockFurniStartEvent) => { diff --git a/src/views/room/widgets/furniture/gift-opening/FurnitureGiftOpeningView.tsx b/src/views/room/widgets/furniture/gift-opening/FurnitureGiftOpeningView.tsx index f0aabaf5..3348cada 100644 --- a/src/views/room/widgets/furniture/gift-opening/FurnitureGiftOpeningView.tsx +++ b/src/views/room/widgets/furniture/gift-opening/FurnitureGiftOpeningView.tsx @@ -1,8 +1,10 @@ import { RoomObjectCategory, RoomObjectOperationType } from '@nitrots/nitro-renderer'; import { FC, useCallback, useMemo, useState } from 'react'; -import { CreateLinkEvent, GetRoomEngine, GetSessionDataManager, LocalizeText, RoomWidgetPresentOpenMessage, RoomWidgetRoomObjectUpdateEvent, RoomWidgetUpdatePresentDataEvent } from '../../../../../api'; +import { CreateLinkEvent, GetRoomEngine, GetSessionDataManager, LocalizeText, RoomWidgetPresentOpenMessage, RoomWidgetUpdatePresentDataEvent, RoomWidgetUpdateRoomObjectEvent } from '../../../../../api'; +import { BatchUpdates } from '../../../../../hooks'; import { CreateEventDispatcherHook } from '../../../../../hooks/events/event-dispatcher.base'; -import { NitroCardContentView, NitroCardHeaderView, NitroCardView, NitroLayoutGiftCardView } from '../../../../../layout'; +import { NitroCardContentView, NitroCardHeaderView, NitroCardView, NitroLayoutButton, NitroLayoutFlex, NitroLayoutFlexColumn, NitroLayoutGiftCardView, NitroLayoutGrid, NitroLayoutGridColumn } from '../../../../../layout'; +import { NitroLayoutBase } from '../../../../../layout/base'; import { ProductTypeEnum } from '../../../../catalog/common/ProductTypeEnum'; import { useRoomContext } from '../../../context/RoomContext'; @@ -10,6 +12,11 @@ const FLOOR: string = 'floor'; const WALLPAPER: string = 'wallpaper'; const LANDSCAPE: string = 'landscape'; +const ACTION_GIVE_GIFT = 0; +const ACTION_OPEN = 1; +const ACTION_PLACE = 2; +const ACTION_INVENTORY = 3; + export const FurnitureGiftOpeningView: FC<{}> = props => { const [ objectId, setObjectId ] = useState(-1); @@ -44,57 +51,67 @@ export const FurnitureGiftOpeningView: FC<{}> = props => switch(event.type) { case RoomWidgetUpdatePresentDataEvent.PACKAGEINFO: { - setOpenRequested(false); - setObjectId(event.objectId); - setText(event.giftMessage); - setIsOwnerOfFurniture(event.isController); - setSenderName(event.purchaserName); - setSenderFigure(event.purchaserFigure); - setImageUrl(event.imageUrl); + BatchUpdates(() => + { + setOpenRequested(false); + setObjectId(event.objectId); + setText(event.giftMessage); + setIsOwnerOfFurniture(event.isController); + setSenderName(event.purchaserName); + setSenderFigure(event.purchaserFigure); + setImageUrl(event.imageUrl); + }); return; } case RoomWidgetUpdatePresentDataEvent.CONTENTS_FLOOR: case RoomWidgetUpdatePresentDataEvent.CONTENTS_LANDSCAPE: case RoomWidgetUpdatePresentDataEvent.CONTENTS_WALLPAPER: { - setObjectId(event.objectId); - setClassId(event.classId); - setItemType(event.itemType); - setText(event.giftMessage); - setIsOwnerOfFurniture(event.isController); - setPlacedItemId(event.placedItemId); - setPlacedItemType(event.placedItemType); - setPlacedInRoom(event.placedInRoom); - let imageType: string = null; if(event.type === RoomWidgetUpdatePresentDataEvent.CONTENTS_FLOOR) imageType = 'packagecard_icon_floor'; else if(event.type === RoomWidgetUpdatePresentDataEvent.CONTENTS_LANDSCAPE) imageType = 'packagecard_icon_landscape'; else if(event.type === RoomWidgetUpdatePresentDataEvent.CONTENTS_WALLPAPER) imageType = 'packagecard_icon_wallpaper'; - setImageUrl(getGiftImageUrl(imageType)); + BatchUpdates(() => + { + setObjectId(event.objectId); + setClassId(event.classId); + setItemType(event.itemType); + setText(event.giftMessage); + setIsOwnerOfFurniture(event.isController); + setPlacedItemId(event.placedItemId); + setPlacedItemType(event.placedItemType); + setPlacedInRoom(event.placedInRoom); + setImageUrl(getGiftImageUrl(imageType)); + }); return; } case RoomWidgetUpdatePresentDataEvent.CONTENTS_CLUB: { - setObjectId(event.objectId); - setClassId(event.classId); - setItemType(event.itemType); - setText(event.giftMessage); - setIsOwnerOfFurniture(event.isController); - setImageUrl(getGiftImageUrl('packagecard_icon_hc')); + BatchUpdates(() => + { + setObjectId(event.objectId); + setClassId(event.classId); + setItemType(event.itemType); + setText(event.giftMessage); + setIsOwnerOfFurniture(event.isController); + setImageUrl(getGiftImageUrl('packagecard_icon_hc')); + }); return; } case RoomWidgetUpdatePresentDataEvent.CONTENTS: { if(!openRequested) return; - setObjectId(event.objectId); - setClassId(event.classId); - setItemType(event.itemType); - setText(event.giftMessage); - setIsOwnerOfFurniture(event.isController); - setPlacedItemId(event.placedItemId); - setPlacedItemType(event.placedItemType); - setPlacedInRoom(event.placedInRoom); - + BatchUpdates(() => + { + setObjectId(event.objectId); + setClassId(event.classId); + setItemType(event.itemType); + setText(event.giftMessage); + setIsOwnerOfFurniture(event.isController); + setPlacedItemId(event.placedItemId); + setPlacedItemType(event.placedItemType); + setPlacedInRoom(event.placedInRoom); + }); return; } case RoomWidgetUpdatePresentDataEvent.CONTENTS_IMAGE: { @@ -113,7 +130,7 @@ export const FurnitureGiftOpeningView: FC<{}> = props => CreateEventDispatcherHook(RoomWidgetUpdatePresentDataEvent.CONTENTS_CLUB, eventDispatcher, onRoomWidgetUpdatePresentDataEvent); CreateEventDispatcherHook(RoomWidgetUpdatePresentDataEvent.CONTENTS_IMAGE, eventDispatcher, onRoomWidgetUpdatePresentDataEvent); - const onRoomWidgetRoomObjectUpdateEvent = useCallback((event: RoomWidgetRoomObjectUpdateEvent) => + const onRoomWidgetRoomObjectUpdateEvent = useCallback((event: RoomWidgetUpdateRoomObjectEvent) => { if(event.id === objectId) clearGift(); @@ -123,17 +140,20 @@ export const FurnitureGiftOpeningView: FC<{}> = props => } }, [ objectId, placedItemId, placedInRoom, clearGift ]); - CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.FURNI_REMOVED, eventDispatcher, onRoomWidgetRoomObjectUpdateEvent); + CreateEventDispatcherHook(RoomWidgetUpdateRoomObjectEvent.FURNI_REMOVED, eventDispatcher, onRoomWidgetRoomObjectUpdateEvent); const close = useCallback(() => { - setObjectId(-1); - setOpenRequested(false); - setPlacedItemId(-1); - setPlacedInRoom(false); - setText(null); - setIsOwnerOfFurniture(false); - }, [ clearGift ]); + BatchUpdates(() => + { + setObjectId(-1); + setOpenRequested(false); + setPlacedItemId(-1); + setPlacedInRoom(false); + setText(null); + setIsOwnerOfFurniture(false); + }); + }, []); const isSpaces = useMemo(() => { @@ -152,26 +172,25 @@ export const FurnitureGiftOpeningView: FC<{}> = props => { if(objectId === -1) return ''; - if(isSpaces) - return 'widget.furni.present.spaces.message_opened'; + if(isSpaces) return 'widget.furni.present.spaces.message_opened'; return 'widget.furni.present.message_opened'; }, [ objectId, isSpaces ]); - const handleAction = useCallback((action: string) => + const handleAction = useCallback((action: number) => { switch(action) { - case 'give_gift': + case ACTION_GIVE_GIFT: CreateLinkEvent('catalog/open'); return; - case 'open': + case ACTION_OPEN: setOpenRequested(true); widgetHandler.processWidgetMessage(new RoomWidgetPresentOpenMessage(RoomWidgetPresentOpenMessage.OPEN_PRESENT, objectId)); return; - case 'room': + case ACTION_PLACE: return; - case 'inventory': + case ACTION_INVENTORY: if((placedItemId > 0) && placedInRoom) { if(placedItemType === ProductTypeEnum.PET) @@ -195,32 +214,48 @@ export const FurnitureGiftOpeningView: FC<{}> = props => return ( - + - { placedItemId === -1 && <> - - { isOwnerOfFurniture &&
- { senderName && } - -
} - } - { placedItemId !== -1 && <> -
-
- -
-
- { LocalizeText(productName, ['product'], [text]) } -
-
-
- - -
- { senderName && <> - - } - } + + { (placedItemId === -1) && + + + + + + { senderName && + handleAction(ACTION_GIVE_GIFT) }> + { LocalizeText('widget.furni.present.give_gift', [ 'name' ], [ senderName ]) } + } + handleAction(ACTION_OPEN) }> + { LocalizeText('widget.furni.present.open_gift') } + + + } + { (placedItemId > -1) && + + + + + { LocalizeText(productName, [ 'product' ], [ text ]) } + + + + + handleAction(ACTION_INVENTORY) }> + { LocalizeText('widget.furni.present.put_in_inventory') } + + handleAction(ACTION_PLACE) }> + { LocalizeText(placedInRoom ? 'widget.furni.present.keep_in_room' : 'widget.furni.present.place_in_room') } + + + { (senderName && senderName.length) && + handleAction(ACTION_GIVE_GIFT) }> + { LocalizeText('widget.furni.present.give_gift', [ 'name' ], [ senderName ]) } + } + + } +
); diff --git a/src/views/room/widgets/furniture/high-score/FurnitureHighScoreView.scss b/src/views/room/widgets/furniture/high-score/FurnitureHighScoreView.scss index 2635164f..a02f8b69 100644 --- a/src/views/room/widgets/furniture/high-score/FurnitureHighScoreView.scss +++ b/src/views/room/widgets/furniture/high-score/FurnitureHighScoreView.scss @@ -1,5 +1,6 @@ -.highscore-widget +.nitro-widget-high-score { - width: 150px; - max-width: 150px; + width: 250px; + max-width: 250px; + height: 200px; } diff --git a/src/views/room/widgets/furniture/high-score/FurnitureHighScoreView.tsx b/src/views/room/widgets/furniture/high-score/FurnitureHighScoreView.tsx index 3a322c20..981fe26a 100644 --- a/src/views/room/widgets/furniture/high-score/FurnitureHighScoreView.tsx +++ b/src/views/room/widgets/furniture/high-score/FurnitureHighScoreView.tsx @@ -2,13 +2,15 @@ import { HighScoreDataType, ObjectDataFactory, RoomEngineTriggerWidgetEvent, Roo import { FC, useCallback, useState } from 'react'; import { GetRoomEngine, LocalizeText } from '../../../../../api'; import { useRoomEngineEvent } from '../../../../../hooks'; +import { NitroLayoutGrid, NitroLayoutGridColumn } from '../../../../../layout'; +import { NitroLayoutBase } from '../../../../../layout/base'; import { useRoomContext } from '../../../context/RoomContext'; import { ContextMenuView } from '../../context-menu/ContextMenuView'; import { ContextMenuHeaderView } from '../../context-menu/views/header/ContextMenuHeaderView'; import { ContextMenuListView } from '../../context-menu/views/list/ContextMenuListView'; -const SCORE_TYPES = ['perteam', 'mostwins', 'classic']; -const CLEAR_TYPES = ['alltime', 'daily', 'weekly', 'monthly']; +const SCORE_TYPES = [ 'perteam', 'mostwins', 'classic' ]; +const CLEAR_TYPES = [ 'alltime', 'daily', 'weekly', 'monthly' ]; export const FurnitureHighScoreView: FC<{}> = props => { @@ -55,33 +57,48 @@ export const FurnitureHighScoreView: FC<{}> = props => if((objectId === -1) || !stuffData) return null; return ( - + { LocalizeText('high.score.display.caption', [ 'scoretype', 'cleartype' ], [LocalizeText(`high.score.display.scoretype.${ SCORE_TYPES[stuffData.scoreType] }`), LocalizeText(`high.score.display.cleartype.${ CLEAR_TYPES[stuffData.clearType] }`) ]) } -
-
{ LocalizeText('high.score.display.users.header') }
-
{ LocalizeText('high.score.display.score.header') }
-
-
-
-
- { stuffData.entries.map((entry, index) => - { - return
{entry.users.join()}
- }) - } -
-
-
+ + + + { LocalizeText('high.score.display.users.header') } + + + + + { LocalizeText('high.score.display.score.header') } + + + +
+ + { stuffData.entries.map((entry, index) => { - return
{entry.score}
+ return ( + + { entry.users.join(', ') } + + ); }) } -
-
+ + + { stuffData.entries.map((entry, index) => + { + return ( + + { entry.score } + + ); + }) + } + +
); diff --git a/src/views/room/widgets/furniture/manipulation-menu/FurnitureManipulationMenuView.tsx b/src/views/room/widgets/furniture/manipulation-menu/FurnitureManipulationMenuView.tsx index 33752c8f..5590392a 100644 --- a/src/views/room/widgets/furniture/manipulation-menu/FurnitureManipulationMenuView.tsx +++ b/src/views/room/widgets/furniture/manipulation-menu/FurnitureManipulationMenuView.tsx @@ -1,6 +1,6 @@ import { RoomObjectOperationType } from '@nitrots/nitro-renderer'; import { FC, useCallback, useEffect, useState } from 'react'; -import { ProcessRoomObjectOperation, RoomWidgetRoomObjectUpdateEvent, RoomWidgetUpdateDecorateModeEvent } from '../../../../../api'; +import { ProcessRoomObjectOperation, RoomWidgetUpdateDecorateModeEvent, RoomWidgetUpdateRoomObjectEvent } from '../../../../../api'; import { BatchUpdates } from '../../../../../hooks'; import { CreateEventDispatcherHook } from '../../../../../hooks/events/event-dispatcher.base'; import { useRoomContext } from '../../../context/RoomContext'; @@ -28,11 +28,11 @@ export const FurnitureManipulationMenuView: FC<{}> = props => ProcessRoomObjectOperation(objectId, objectType, RoomObjectOperationType.OBJECT_PICKUP); }, [ objectId, objectType ]); - const onRoomWidgetRoomObjectUpdateEvent = useCallback((event: RoomWidgetRoomObjectUpdateEvent) => + const onRoomWidgetRoomObjectUpdateEvent = useCallback((event: RoomWidgetUpdateRoomObjectEvent) => { switch(event.type) { - case RoomWidgetRoomObjectUpdateEvent.OBJECT_REQUEST_MANIPULATION: { + case RoomWidgetUpdateRoomObjectEvent.OBJECT_REQUEST_MANIPULATION: { BatchUpdates(() => { setIsVisible(true); @@ -41,7 +41,7 @@ export const FurnitureManipulationMenuView: FC<{}> = props => }); return; } - case RoomWidgetRoomObjectUpdateEvent.FURNI_REMOVED: { + case RoomWidgetUpdateRoomObjectEvent.FURNI_REMOVED: { if(event.id === objectId) { BatchUpdates(() => @@ -53,7 +53,7 @@ export const FurnitureManipulationMenuView: FC<{}> = props => } return; } - case RoomWidgetRoomObjectUpdateEvent.OBJECT_DESELECTED: { + case RoomWidgetUpdateRoomObjectEvent.OBJECT_DESELECTED: { BatchUpdates(() => { setIsVisible(false); @@ -65,8 +65,8 @@ export const FurnitureManipulationMenuView: FC<{}> = props => } }, [ objectId ]); - CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.OBJECT_REQUEST_MANIPULATION, eventDispatcher, onRoomWidgetRoomObjectUpdateEvent); - CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.OBJECT_DESELECTED, eventDispatcher, onRoomWidgetRoomObjectUpdateEvent); + CreateEventDispatcherHook(RoomWidgetUpdateRoomObjectEvent.OBJECT_REQUEST_MANIPULATION, eventDispatcher, onRoomWidgetRoomObjectUpdateEvent); + CreateEventDispatcherHook(RoomWidgetUpdateRoomObjectEvent.OBJECT_DESELECTED, eventDispatcher, onRoomWidgetRoomObjectUpdateEvent); const onRoomWidgetUpdateDecorateModeEvent = useCallback((event: RoomWidgetUpdateDecorateModeEvent) => { diff --git a/src/views/room/widgets/furniture/mannequin/FurnitureMannequinView.tsx b/src/views/room/widgets/furniture/mannequin/FurnitureMannequinView.tsx index 5e3a3972..b0ec3792 100644 --- a/src/views/room/widgets/furniture/mannequin/FurnitureMannequinView.tsx +++ b/src/views/room/widgets/furniture/mannequin/FurnitureMannequinView.tsx @@ -1,15 +1,26 @@ -import { AvatarFigurePartType, FurnitureMannequinSaveLookComposer, FurnitureMannequinSaveNameComposer, FurnitureMultiStateComposer, IAvatarFigureContainer, NitroEvent, RoomEngineTriggerWidgetEvent, RoomObjectVariable } from '@nitrots/nitro-renderer'; +import { AvatarFigurePartType, FurnitureMannequinSaveLookComposer, FurnitureMannequinSaveNameComposer, FurnitureMultiStateComposer, HabboClubLevelEnum, IAvatarFigureContainer, RoomControllerLevel } from '@nitrots/nitro-renderer'; import { FC, KeyboardEvent, useCallback, useEffect, useState } from 'react'; -import { GetAvatarRenderManager, GetNitroInstance, GetRoomEngine, GetRoomSession, GetSessionDataManager, LocalizeText, RoomWidgetRoomObjectUpdateEvent } from '../../../../../api'; +import { GetAvatarRenderManager, GetSessionDataManager, LocalizeText, RoomWidgetUpdateMannequinEvent } from '../../../../../api'; +import { BatchUpdates, SendMessageHook } from '../../../../../hooks'; import { CreateEventDispatcherHook } from '../../../../../hooks/events/event-dispatcher.base'; -import { useRoomEngineEvent } from '../../../../../hooks/events/nitro/room/room-engine-event'; -import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../../layout'; -import { AvatarImageView } from '../../../../shared/avatar-image/AvatarImageView'; +import { NitroCardContentView, NitroCardHeaderView, NitroCardView, NitroLayoutButton, NitroLayoutFlex, NitroLayoutFlexColumn, NitroLayoutGrid, NitroLayoutGridColumn } from '../../../../../layout'; +import { NitroLayoutBase } from '../../../../../layout/base'; import { useRoomContext } from '../../../context/RoomContext'; -import { MannequinViewMode } from './common/MannequinViewMode'; -import { FurnitureMannequinData } from './FurnitureMannequinData'; +import { FurnitureMannequinPreviewView } from './views/preview/FurnitureMannequinPreviewView'; -const parts = [ +const MODE_NONE: number = -1; +const MODE_CONTROLLER: number = 0; +const MODE_UPDATE: number = 1; +const MODE_PEER: number = 2; +const MODE_NO_CLUB: number = 3; +const MODE_WRONG_GENDER: number = 4; + +const ACTION_SET_NAME: number = 1; +const ACTION_WEAR: number = 2; +const ACTION_SAVE: number = 3; + +const MANNEQUIN_FIGURE = ['hd', 99999, [ 99998 ]]; +const MANNEQUIN_CLOTHING_PART_TYPES = [ AvatarFigurePartType.CHEST_ACCESSORY, AvatarFigurePartType.COAT_CHEST, AvatarFigurePartType.CHEST, @@ -17,197 +28,209 @@ const parts = [ AvatarFigurePartType.SHOES, AvatarFigurePartType.WAIST_ACCESSORY ]; -const baseAvatar = ['hd', 99999, 99998]; export const FurnitureMannequinView: FC<{}> = props => { - const { eventDispatcher = null } = useRoomContext(); - - const [ mannequinData, setMannequinData ] = useState(null); - const [ viewMode, setViewMode ] = useState(''); + const [ objectId, setObjectId ] = useState(-1); + const [ figure, setFigure ] = useState(null); + const [ gender, setGender ] = useState(null); + const [ name, setName ] = useState(null); + const [ clubLevel, setClubLevel ] = useState(HabboClubLevelEnum.NO_CLUB); + const [ renderedFigure, setRenderedFigure ] = useState(null); + const [ renderedClubLevel, setRenderedClubLevel ] = useState(HabboClubLevelEnum.NO_CLUB); + const [ mode, setMode ] = useState(MODE_NONE); + const { roomSession = null, eventDispatcher = null } = useRoomContext(); - const loadMannequinFigure = useCallback((figureContainer: IAvatarFigureContainer) => - { - for(const item of figureContainer.getPartTypeIds()) - { - if(parts.indexOf(item) === -1) - { - figureContainer.removePart(item); - } - } - - figureContainer.updatePart(baseAvatar[0].toString(), Number(baseAvatar[1]), [ Number(baseAvatar[2]) ]); - - setMannequinData(mannequinData => new FurnitureMannequinData(mannequinData.objectId, mannequinData.category, mannequinData.name, mannequinData.figure, mannequinData.gender, mannequinData.clubLevel, figureContainer.getFigureString())); - }, []); - - useEffect(() => + const onRoomWidgetUpdateMannequinEvent = useCallback((event: RoomWidgetUpdateMannequinEvent) => { - if(mannequinData && !mannequinData.renderedFigure) - { - const figureContainer = GetAvatarRenderManager().createFigureContainer(mannequinData.figure); - loadMannequinFigure(figureContainer); - } - }, [loadMannequinFigure, mannequinData]); + const figureContainer = GetAvatarRenderManager().createFigureContainer(event.figure); + const figureClubLevel = GetAvatarRenderManager().getFigureClubLevel(figureContainer, event.gender, MANNEQUIN_CLOTHING_PART_TYPES); - const loadViewMode = useCallback((mannequinData: FurnitureMannequinData) => - { - if(!mannequinData) return; - - const userCanEdit = (GetRoomSession().isRoomOwner || GetSessionDataManager().isModerator); - const userGender = GetNitroInstance().sessionDataManager.gender; - const userClubLevel = GetNitroInstance().sessionDataManager.clubLevel; - - if(userCanEdit) + BatchUpdates(() => { - setViewMode(MannequinViewMode.EDIT); - } - else - { - if(!mannequinData.figure || mannequinData.figure.length <= 1) return; + setObjectId(event.objectId); + setFigure(event.figure); + setGender(event.gender); + setName(event.name); + setClubLevel(figureClubLevel); - if(userGender.toUpperCase() !== mannequinData.gender.toUpperCase()) + if(roomSession.isRoomOwner || (roomSession.controllerLevel >= RoomControllerLevel.GUEST) || GetSessionDataManager().isModerator) { - setViewMode(MannequinViewMode.INCOMPATIBLE_GENDER); + setMode(MODE_CONTROLLER); } - else if(userClubLevel < mannequinData.clubLevel) + + else if(GetSessionDataManager().gender.toLowerCase() !== event.gender.toLowerCase()) { - setViewMode(MannequinViewMode.CLUB); + setMode(MODE_WRONG_GENDER); + } + + else if(GetSessionDataManager().clubLevel < figureClubLevel) + { + setMode(MODE_NO_CLUB); } else { - setViewMode(MannequinViewMode.DEFAULT); + setMode(MODE_PEER); } - } - }, []); + }); + }, [ roomSession ]); - const onNitroEvent = useCallback((event: NitroEvent) => + CreateEventDispatcherHook(RoomWidgetUpdateMannequinEvent.MANNEQUIN_UPDATE, eventDispatcher, onRoomWidgetUpdateMannequinEvent); + + const getMergedFigureContainer = (figure: string, targetFigure: string) => { - switch(event.type) + const figureContainer = GetAvatarRenderManager().createFigureContainer(figure); + const targetFigureContainer = GetAvatarRenderManager().createFigureContainer(targetFigure); + + for(const part of MANNEQUIN_CLOTHING_PART_TYPES) figureContainer.removePart(part); + + for(const part of targetFigureContainer.getPartTypeIds()) { - case RoomEngineTriggerWidgetEvent.REQUEST_MANNEQUIN: { - const widgetEvent = (event as RoomEngineTriggerWidgetEvent); - - const roomObject = GetRoomEngine().getRoomObject(widgetEvent.roomId, widgetEvent.objectId, widgetEvent.category); - - if(!roomObject) return; - - const figure = roomObject.model.getValue(RoomObjectVariable.FURNITURE_MANNEQUIN_FIGURE); - const gender = roomObject.model.getValue(RoomObjectVariable.FURNITURE_MANNEQUIN_GENDER); - const name = roomObject.model.getValue(RoomObjectVariable.FURNITURE_MANNEQUIN_NAME); - - const figureContainer = GetAvatarRenderManager().createFigureContainer(figure); - const clubLevel = GetAvatarRenderManager().getFigureClubLevel(figureContainer, gender, parts); - - const mannequinData = new FurnitureMannequinData(widgetEvent.objectId, widgetEvent.category, name, figure, gender, clubLevel); - - setMannequinData(mannequinData); - loadViewMode(mannequinData); - return; - } - case RoomWidgetRoomObjectUpdateEvent.FURNI_REMOVED: { - const widgetEvent = (event as RoomWidgetRoomObjectUpdateEvent); - - setMannequinData(prevState => - { - if(!prevState || (widgetEvent.id !== prevState.objectId) || (widgetEvent.category !== prevState.category)) return prevState; - - return null; - }); - return; - } + figureContainer.updatePart(part, targetFigureContainer.getPartSetId(part), targetFigureContainer.getPartColorIds(part)); } - }, [loadViewMode]); - useRoomEngineEvent(RoomEngineTriggerWidgetEvent.REQUEST_MANNEQUIN, onNitroEvent); - CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.FURNI_REMOVED, eventDispatcher, onNitroEvent); + return figureContainer; + } - const processAction = useCallback((type: string, value: string = null) => + const transformAsMannequinFigure = (figureContainer: IAvatarFigureContainer) => { - switch(type) + for(const part of figureContainer.getPartTypeIds()) { - case 'close': - setMannequinData(null); - return; - case 'set_name': - setMannequinData(mannequinData => new FurnitureMannequinData(mannequinData.objectId, mannequinData.category, value, mannequinData.figure, mannequinData.gender, mannequinData.clubLevel, mannequinData.renderedFigure)); - return; - case 'load_figure': - loadMannequinFigure(GetAvatarRenderManager().createFigureContainer(GetNitroInstance().sessionDataManager.figure)); - setViewMode(MannequinViewMode.SAVE); - return; - case 'back': - loadMannequinFigure(GetAvatarRenderManager().createFigureContainer(mannequinData.figure)); - setViewMode(MannequinViewMode.EDIT); - return; - case 'save_name': - GetRoomSession().connection.send(new FurnitureMannequinSaveNameComposer(mannequinData.objectId, mannequinData.name)); - return; - case 'save_figure': - GetRoomSession().connection.send(new FurnitureMannequinSaveLookComposer(mannequinData.objectId)); - processAction('save_name'); - processAction('close'); - return; - case 'wear': - GetRoomSession().connection.send(new FurnitureMultiStateComposer(mannequinData.objectId)); - processAction('close'); + if(MANNEQUIN_CLOTHING_PART_TYPES.indexOf(part) >= 0) continue; + + figureContainer.removePart(part); + } + + figureContainer.updatePart((MANNEQUIN_FIGURE[0] as string), (MANNEQUIN_FIGURE[1] as number), (MANNEQUIN_FIGURE[2] as number[])); + }; + + const processAction = useCallback((action: number, value: string = null) => + { + switch(action) + { + case ACTION_SAVE: + SendMessageHook(new FurnitureMannequinSaveLookComposer(objectId)); + break; + case ACTION_WEAR: + SendMessageHook(new FurnitureMultiStateComposer(objectId)); + break; + case ACTION_SET_NAME: + SendMessageHook(new FurnitureMannequinSaveNameComposer(objectId, name)); return; } - }, [ loadMannequinFigure, mannequinData ]); + + setMode(MODE_NONE); + }, [ objectId, name ]); const handleKeyDown = (event: KeyboardEvent) => { if(event.key !== 'Enter') return; - processAction('save_name'); + processAction(ACTION_SET_NAME); }; - if(!mannequinData) return null; + useEffect(() => + { + switch(mode) + { + case MODE_CONTROLLER: + case MODE_WRONG_GENDER: { + const figureContainer = GetAvatarRenderManager().createFigureContainer(figure); + + transformAsMannequinFigure(figureContainer); + + setRenderedFigure(figureContainer.getFigureString()); + setRenderedClubLevel(clubLevel); + break; + } + case MODE_UPDATE: { + const figureContainer = GetAvatarRenderManager().createFigureContainer(GetSessionDataManager().figure); + + transformAsMannequinFigure(figureContainer); + + setRenderedFigure(figureContainer.getFigureString()); + setRenderedClubLevel(GetAvatarRenderManager().getFigureClubLevel(figureContainer, GetSessionDataManager().gender, MANNEQUIN_CLOTHING_PART_TYPES)); + break; + } + case MODE_PEER: + case MODE_NO_CLUB: { + const figureContainer = getMergedFigureContainer(GetSessionDataManager().figure, figure); + + setRenderedFigure(figureContainer.getFigureString()); + setRenderedClubLevel(clubLevel); + break; + } + } + }, [ mode, figure, clubLevel ]); + + if(mode === MODE_NONE) return null; return ( - processAction('close') } /> + setMode(MODE_NONE) } /> -
-
-
- -
-
-
- { viewMode === MannequinViewMode.DEFAULT && + + + + + + { (mode === MODE_CONTROLLER) && <> -
-
{ mannequinData.name }
-
{ LocalizeText('mannequin.widget.weartext') }
-
-
processAction('wear') }>{ LocalizeText('mannequin.widget.wear') }
- } - { viewMode === MannequinViewMode.EDIT && - <> - processAction('set_name', event.target.value) } onKeyDown={ event => handleKeyDown(event) } /> -
-
processAction('load_figure') }>{ LocalizeText('mannequin.widget.style') }
-
processAction('wear') }>{ LocalizeText('mannequin.widget.wear') }
-
+ + setName(event.target.value) } onKeyDown={ event => handleKeyDown(event) } /> + + + setMode(MODE_UPDATE) }> + { LocalizeText('mannequin.widget.style') } + + processAction(ACTION_WEAR) }> + { LocalizeText('mannequin.widget.wear') } + + } - { viewMode === MannequinViewMode.SAVE && + { (mode === MODE_UPDATE) && <> -
-
{ mannequinData.name }
-
{ LocalizeText('mannequin.widget.savetext') }
-
-
-
processAction('back') }>{ LocalizeText('mannequin.widget.back') }
-
processAction('save_figure') }>{ LocalizeText('mannequin.widget.save') }
-
+ + + { name } + + + { LocalizeText('mannequin.widget.savetext') } + + + + setMode(MODE_CONTROLLER) }> + { LocalizeText('mannequin.widget.back') } + + processAction(ACTION_SAVE) }> + { LocalizeText('mannequin.widget.save') } + + } - { viewMode === MannequinViewMode.CLUB && -
{ LocalizeText('mannequin.widget.clubnotification') }
} - { viewMode === MannequinViewMode.INCOMPATIBLE_GENDER && -
{ LocalizeText('mannequin.widget.wronggender') }
} -
-
+ { (mode === MODE_PEER) && + <> + + + { name } + + + { LocalizeText('mannequin.widget.weartext') } + + + processAction(ACTION_WEAR) }> + { LocalizeText('mannequin.widget.wear') } + + } + { (mode === MODE_NO_CLUB) && + + { LocalizeText('mannequin.widget.clubnotification') } + } + { (mode === MODE_WRONG_GENDER) && + + { LocalizeText('mannequin.widget.wronggender') } + } + +
); diff --git a/src/views/room/widgets/furniture/mannequin/common/MannequinViewMode.ts b/src/views/room/widgets/furniture/mannequin/common/MannequinViewMode.ts deleted file mode 100644 index e588eea4..00000000 --- a/src/views/room/widgets/furniture/mannequin/common/MannequinViewMode.ts +++ /dev/null @@ -1,8 +0,0 @@ -export class MannequinViewMode -{ - public static readonly EDIT: string = 'edit'; - public static readonly SAVE: string = 'save'; - public static readonly CLUB: string = 'club'; - public static readonly DEFAULT: string = 'default'; - public static readonly INCOMPATIBLE_GENDER: string = 'incompatible_gender'; -} diff --git a/src/views/room/widgets/furniture/mannequin/views/preview/FurnitureMannequinPreviewView.tsx b/src/views/room/widgets/furniture/mannequin/views/preview/FurnitureMannequinPreviewView.tsx new file mode 100644 index 00000000..194700df --- /dev/null +++ b/src/views/room/widgets/furniture/mannequin/views/preview/FurnitureMannequinPreviewView.tsx @@ -0,0 +1,17 @@ +import { FC } from 'react'; +import { NitroLayoutBase } from '../../../../../../../layout/base'; +import { AvatarImageView } from '../../../../../../shared/avatar-image/AvatarImageView'; +import { CurrencyIcon } from '../../../../../../shared/currency-icon/CurrencyIcon'; +import { FurnitureMannequinPreviewViewProps } from './FurnitureMannequinPreviewView.types'; + +export const FurnitureMannequinPreviewView: FC = props => +{ + const { figure = null, clubLevel = 0 } = props; + + return ( + + + { (clubLevel > 0) && } + + ); +} diff --git a/src/views/room/widgets/furniture/mannequin/views/preview/FurnitureMannequinPreviewView.types.ts b/src/views/room/widgets/furniture/mannequin/views/preview/FurnitureMannequinPreviewView.types.ts new file mode 100644 index 00000000..1a5ee3fe --- /dev/null +++ b/src/views/room/widgets/furniture/mannequin/views/preview/FurnitureMannequinPreviewView.types.ts @@ -0,0 +1,5 @@ +export interface FurnitureMannequinPreviewViewProps +{ + figure: string; + clubLevel: number; +} diff --git a/src/views/room/widgets/furniture/stickie/FurnitureStickieView.scss b/src/views/room/widgets/furniture/stickie/FurnitureStickieView.scss index fc0c09da..95c8aecd 100644 --- a/src/views/room/widgets/furniture/stickie/FurnitureStickieView.scss +++ b/src/views/room/widgets/furniture/stickie/FurnitureStickieView.scss @@ -5,6 +5,7 @@ top: 25px; left: 25px; padding: 1px; + pointer-events: all; .stickie-header { width: 183px; diff --git a/src/views/room/widgets/furniture/stickie/FurnitureStickieView.tsx b/src/views/room/widgets/furniture/stickie/FurnitureStickieView.tsx index 1c4fb312..3e4718cf 100644 --- a/src/views/room/widgets/furniture/stickie/FurnitureStickieView.tsx +++ b/src/views/room/widgets/furniture/stickie/FurnitureStickieView.tsx @@ -1,6 +1,6 @@ import { NitroEvent, RoomEngineTriggerWidgetEvent, RoomObjectVariable } from '@nitrots/nitro-renderer'; import { FC, useCallback, useState } from 'react'; -import { ColorUtils, GetRoomEngine, GetRoomSession, GetSessionDataManager, RoomWidgetRoomObjectUpdateEvent } from '../../../../../api'; +import { ColorUtils, GetRoomEngine, GetRoomSession, GetSessionDataManager, RoomWidgetUpdateRoomObjectEvent } from '../../../../../api'; import { CreateEventDispatcherHook } from '../../../../../hooks/events/event-dispatcher.base'; import { useRoomEngineEvent } from '../../../../../hooks/events/nitro/room/room-engine-event'; import { DraggableWindowPosition } from '../../../../../layout'; @@ -45,8 +45,8 @@ export const FurnitureStickieView: FC<{}> = props => setStickieData(new FurnitureStickieData(widgetEvent.objectId, widgetEvent.category, color, text, (GetRoomSession().isRoomOwner || GetSessionDataManager().isModerator), false)); return; } - case RoomWidgetRoomObjectUpdateEvent.FURNI_REMOVED: { - const widgetEvent = (event as RoomWidgetRoomObjectUpdateEvent); + case RoomWidgetUpdateRoomObjectEvent.FURNI_REMOVED: { + const widgetEvent = (event as RoomWidgetUpdateRoomObjectEvent); setStickieData(prevState => { @@ -60,7 +60,7 @@ export const FurnitureStickieView: FC<{}> = props => }, []); useRoomEngineEvent(RoomEngineTriggerWidgetEvent.REQUEST_STICKIE, onNitroEvent); - CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.FURNI_REMOVED, eventDispatcher, onNitroEvent); + CreateEventDispatcherHook(RoomWidgetUpdateRoomObjectEvent.FURNI_REMOVED, eventDispatcher, onNitroEvent); const processAction = useCallback((type: string, value: string = null) => { diff --git a/src/views/room/widgets/infostand/InfoStandWidgetView.tsx b/src/views/room/widgets/infostand/InfoStandWidgetView.tsx index 01190223..4f240121 100644 --- a/src/views/room/widgets/infostand/InfoStandWidgetView.tsx +++ b/src/views/room/widgets/infostand/InfoStandWidgetView.tsx @@ -1,5 +1,5 @@ import { FC, useCallback, useState } from 'react'; -import { RoomWidgetRoomObjectMessage, RoomWidgetRoomObjectUpdateEvent, RoomWidgetUpdateEvent, RoomWidgetUpdateInfostandEvent, RoomWidgetUpdateInfostandFurniEvent, RoomWidgetUpdateInfostandPetEvent, RoomWidgetUpdateInfostandRentableBotEvent, RoomWidgetUpdateInfostandUserEvent } from '../../../../api'; +import { RoomWidgetRoomObjectMessage, RoomWidgetUpdateEvent, RoomWidgetUpdateInfostandEvent, RoomWidgetUpdateInfostandFurniEvent, RoomWidgetUpdateInfostandPetEvent, RoomWidgetUpdateInfostandRentableBotEvent, RoomWidgetUpdateInfostandUserEvent, RoomWidgetUpdateRoomObjectEvent } from '../../../../api'; import { CreateEventDispatcherHook } from '../../../../hooks/events/event-dispatcher.base'; import { useRoomContext } from '../../context/RoomContext'; import { InfoStandWidgetBotView } from './views/bot/InfoStandWidgetBotView'; @@ -22,33 +22,33 @@ export const InfoStandWidgetView: FC<{}> = props => { switch(event.type) { - case RoomWidgetRoomObjectUpdateEvent.OBJECT_SELECTED: { - const roomObjectEvent = (event as RoomWidgetRoomObjectUpdateEvent); + case RoomWidgetUpdateRoomObjectEvent.OBJECT_SELECTED: { + const roomObjectEvent = (event as RoomWidgetUpdateRoomObjectEvent); widgetHandler.processWidgetMessage(new RoomWidgetRoomObjectMessage(RoomWidgetRoomObjectMessage.GET_OBJECT_INFO, roomObjectEvent.id, roomObjectEvent.category)); return; } - case RoomWidgetRoomObjectUpdateEvent.OBJECT_DESELECTED: { - const roomObjectEvent = (event as RoomWidgetRoomObjectUpdateEvent); + case RoomWidgetUpdateRoomObjectEvent.OBJECT_DESELECTED: { + const roomObjectEvent = (event as RoomWidgetUpdateRoomObjectEvent); closeInfostand(); return; } - case RoomWidgetRoomObjectUpdateEvent.FURNI_REMOVED: - case RoomWidgetRoomObjectUpdateEvent.USER_REMOVED: { - const roomObjectEvent = (event as RoomWidgetRoomObjectUpdateEvent); + case RoomWidgetUpdateRoomObjectEvent.FURNI_REMOVED: + case RoomWidgetUpdateRoomObjectEvent.USER_REMOVED: { + const roomObjectEvent = (event as RoomWidgetUpdateRoomObjectEvent); setInfoStandEvent(prevValue => { switch(event.type) { - case RoomWidgetRoomObjectUpdateEvent.FURNI_REMOVED: + case RoomWidgetUpdateRoomObjectEvent.FURNI_REMOVED: if(prevValue instanceof RoomWidgetUpdateInfostandFurniEvent) { if(prevValue.id === roomObjectEvent.id) return null; } break; - case RoomWidgetRoomObjectUpdateEvent.USER_REMOVED: + case RoomWidgetUpdateRoomObjectEvent.USER_REMOVED: if(prevValue instanceof RoomWidgetUpdateInfostandUserEvent || prevValue instanceof RoomWidgetUpdateInfostandRentableBotEvent) { if(prevValue.roomIndex === roomObjectEvent.id) return null; @@ -80,10 +80,10 @@ export const InfoStandWidgetView: FC<{}> = props => } }, [ widgetHandler, closeInfostand ]); - CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.OBJECT_SELECTED, eventDispatcher, onRoomWidgetUpdateEvent); - CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.OBJECT_DESELECTED, eventDispatcher, onRoomWidgetUpdateEvent); - CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.USER_REMOVED, eventDispatcher, onRoomWidgetUpdateEvent); - CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.FURNI_REMOVED, eventDispatcher, onRoomWidgetUpdateEvent); + CreateEventDispatcherHook(RoomWidgetUpdateRoomObjectEvent.OBJECT_SELECTED, eventDispatcher, onRoomWidgetUpdateEvent); + CreateEventDispatcherHook(RoomWidgetUpdateRoomObjectEvent.OBJECT_DESELECTED, eventDispatcher, onRoomWidgetUpdateEvent); + CreateEventDispatcherHook(RoomWidgetUpdateRoomObjectEvent.USER_REMOVED, eventDispatcher, onRoomWidgetUpdateEvent); + CreateEventDispatcherHook(RoomWidgetUpdateRoomObjectEvent.FURNI_REMOVED, eventDispatcher, onRoomWidgetUpdateEvent); CreateEventDispatcherHook(RoomWidgetUpdateInfostandFurniEvent.FURNI, eventDispatcher, onRoomWidgetUpdateEvent); CreateEventDispatcherHook(RoomWidgetUpdateInfostandUserEvent.OWN_USER, eventDispatcher, onRoomWidgetUpdateEvent); CreateEventDispatcherHook(RoomWidgetUpdateInfostandUserEvent.PEER, eventDispatcher, onRoomWidgetUpdateEvent);