Remove some useCallback

This commit is contained in:
Bill 2022-09-22 00:07:05 -04:00
parent dd9969baf7
commit a3212f8a16
35 changed files with 376 additions and 432 deletions

View File

@ -1,5 +1,5 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { FC, MouseEvent, useCallback, useMemo } from 'react';
import { FC, MouseEvent, useMemo } from 'react';
import { Base, Column, ColumnProps, Flex } from '..';
interface NitroCardHeaderViewProps extends ColumnProps
@ -22,11 +22,11 @@ export const NitroCardHeaderView: FC<NitroCardHeaderViewProps> = props =>
return newClassNames;
}, [ classNames ]);
const onMouseDown = useCallback((event: MouseEvent<HTMLDivElement>) =>
const onMouseDown = (event: MouseEvent<HTMLDivElement>) =>
{
event.stopPropagation();
event.nativeEvent.stopImmediatePropagation();
}, []);
}
return (
<Column center position="relative" classNames={ getClassNames } { ...rest }>

View File

@ -1,5 +1,5 @@
import { IGetImageListener, ImageResult, TextureUtils, Vector3d } from '@nitrots/nitro-renderer';
import { CSSProperties, FC, useCallback, useEffect, useMemo, useState } from 'react';
import { CSSProperties, FC, useEffect, useMemo, useState } from 'react';
import { BaseProps } from '..';
import { GetRoomEngine, ProductTypeEnum } from '../../api';
import { Base } from '../Base';
@ -41,7 +41,7 @@ export const LayoutFurniImageView: FC<LayoutFurniImageViewProps> = props =>
return newStyle;
}, [ imageElement, scale, style ]);
const buildImage = useCallback(() =>
useEffect(() =>
{
let imageResult: ImageResult = null;
@ -71,16 +71,11 @@ export const LayoutFurniImageView: FC<LayoutFurniImageViewProps> = props =>
if(imageResult)
{
const image = imageResult.getImage();
image.onload = () => setImageElement(image);
}
}, [ productType, productClassId, direction, extraData ]);
useEffect(() =>
{
buildImage();
}, [ buildImage ]);
if(!imageElement) return null;
return <Base classNames={ [ 'furni-image' ] } style={ getStyle } { ...rest } />;

View File

@ -1,5 +1,5 @@
import { NitroRectangle, NitroRenderTexture } from '@nitrots/nitro-renderer';
import { FC, useCallback, useRef } from 'react';
import { FC, useRef } from 'react';
import { GetRoomEngine, LocalizeText, PlaySound, SoundNames } from '../../api';
import { DraggableWindow } from '../draggable-window';
@ -15,20 +15,20 @@ export const LayoutMiniCameraView: FC<LayoutMiniCameraViewProps> = props =>
const { roomId = -1, textureReceiver = null, onClose = null } = props;
const elementRef = useRef<HTMLDivElement>();
const getCameraBounds = useCallback(() =>
const getCameraBounds = () =>
{
if(!elementRef || !elementRef.current) return null;
const frameBounds = elementRef.current.getBoundingClientRect();
return new NitroRectangle(Math.floor(frameBounds.x), Math.floor(frameBounds.y), Math.floor(frameBounds.width), Math.floor(frameBounds.height));
}, []);
}
const takePicture = useCallback(() =>
const takePicture = () =>
{
PlaySound(SoundNames.CAMERA_SHUTTER);
textureReceiver(GetRoomEngine().createTextureFromRoom(roomId, 1, getCameraBounds()));
}, [ roomId, getCameraBounds, textureReceiver ]);
}
return (
<DraggableWindow handleSelector=".nitro-room-thumbnail-camera">

View File

@ -1,5 +1,5 @@
import { ColorConverter, IRoomRenderingCanvas, RoomPreviewer, TextureUtils } from '@nitrots/nitro-renderer';
import { FC, MouseEvent, ReactNode, useCallback, useEffect, useRef, useState } from 'react';
import { FC, MouseEvent, ReactNode, useEffect, useRef, useState } from 'react';
import { GetNitroInstance } from '../../api';
export interface LayoutRoomPreviewerViewProps
@ -19,58 +19,51 @@ export const LayoutRoomPreviewerView: FC<LayoutRoomPreviewerViewProps> = props =
{
if(!roomPreviewer) return;
if(event.shiftKey)
{
roomPreviewer.changeRoomObjectDirection();
}
else
{
roomPreviewer.changeRoomObjectState();
}
if(event.shiftKey) roomPreviewer.changeRoomObjectDirection();
else roomPreviewer.changeRoomObjectState();
}
const update = useCallback((time: number) =>
{
if(!roomPreviewer || !renderingCanvas || !elementRef.current) return;
roomPreviewer.updatePreviewRoomView();
if(!renderingCanvas.canvasUpdated) return;
elementRef.current.style.backgroundImage = `url(${ TextureUtils.generateImageUrl(renderingCanvas.master) })`;
}, [ roomPreviewer, renderingCanvas, elementRef ]);
const setupPreviewer = useCallback(() =>
{
if(!elementRef.current || !roomPreviewer) return;
const computed = document.defaultView.getComputedStyle(elementRef.current, null);
let backgroundColor = computed.backgroundColor;
backgroundColor = ColorConverter.rgbStringToHex(backgroundColor);
backgroundColor = backgroundColor.replace('#', '0x');
roomPreviewer.backgroundColor = parseInt(backgroundColor, 16);
const width = elementRef.current.parentElement.clientWidth;
roomPreviewer.getRoomCanvas(width, height);
const canvas = roomPreviewer.getRenderingCanvas();
setRenderingCanvas(canvas);
canvas.canvasUpdated = true;
update(-1);
}, [ elementRef, height, roomPreviewer, update ]);
useEffect(() =>
{
if(!roomPreviewer) return;
if(!renderingCanvas) setupPreviewer();
const update = (time: number) =>
{
if(!roomPreviewer || !renderingCanvas || !elementRef.current) return;
roomPreviewer.updatePreviewRoomView();
if(!renderingCanvas.canvasUpdated) return;
elementRef.current.style.backgroundImage = `url(${ TextureUtils.generateImageUrl(renderingCanvas.master) })`;
}
if(!renderingCanvas)
{
if(elementRef.current && roomPreviewer)
{
const computed = document.defaultView.getComputedStyle(elementRef.current, null);
let backgroundColor = computed.backgroundColor;
backgroundColor = ColorConverter.rgbStringToHex(backgroundColor);
backgroundColor = backgroundColor.replace('#', '0x');
roomPreviewer.backgroundColor = parseInt(backgroundColor, 16);
const width = elementRef.current.parentElement.clientWidth;
roomPreviewer.getRoomCanvas(width, height);
const canvas = roomPreviewer.getRenderingCanvas();
setRenderingCanvas(canvas);
canvas.canvasUpdated = true;
update(-1);
}
}
GetNitroInstance().ticker.add(update);
@ -94,7 +87,7 @@ export const LayoutRoomPreviewerView: FC<LayoutRoomPreviewerViewProps> = props =
GetNitroInstance().ticker.remove(update);
}
}, [ renderingCanvas, roomPreviewer, elementRef, height, setupPreviewer, update ]);
}, [ renderingCanvas, roomPreviewer, elementRef, height ]);
return (
<div className="room-preview-container">

View File

@ -1,5 +1,5 @@
import { FriendlyTime } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useMemo, useState } from 'react';
import { FC, useEffect, useMemo, useState } from 'react';
import { Base, BaseProps } from '..';
interface FriendlyTimeViewProps extends BaseProps<HTMLDivElement>
@ -15,15 +15,6 @@ export const FriendlyTimeView: FC<FriendlyTimeViewProps> = props =>
const getStartSeconds = useMemo(() => (Math.round(new Date().getSeconds()) - seconds), [ seconds ]);
const getFriendlyTime = useCallback(() =>
{
const value = (Math.round(new Date().getSeconds()) - getStartSeconds);
if(isShort) return FriendlyTime.format(value);
return FriendlyTime.format(value);
}, [ getStartSeconds, isShort ]);
useEffect(() =>
{
const interval = setInterval(() => setUpdateId(prevValue => (prevValue + 1)), 10000);
@ -31,5 +22,7 @@ export const FriendlyTimeView: FC<FriendlyTimeViewProps> = props =>
return () => clearInterval(interval);
}, []);
return <Base { ...rest }>{ getFriendlyTime() }</Base>;
const value = (Math.round(new Date().getSeconds()) - getStartSeconds);
return <Base { ...rest }>{ isShort ? FriendlyTime.shortFormat(value) : FriendlyTime.format(value) }</Base>;
}

View File

@ -1,5 +1,5 @@
import { AvatarDirectionAngle } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useState } from 'react';
import { FC, useEffect, useState } from 'react';
import { FigureData } from '../../../api';
import { Base, Column, LayoutAvatarImageView } from '../../../common';
import { AvatarEditorIcon } from './AvatarEditorIcon';
@ -14,12 +14,7 @@ export const AvatarEditorFigurePreviewView: FC<AvatarEditorFigurePreviewViewProp
const { figureData = null } = props;
const [ updateId, setUpdateId ] = useState(-1);
const rerender = useCallback(() =>
{
setUpdateId(prevValue => (prevValue + 1));
}, []);
const rotateFigure = useCallback((direction: number) =>
const rotateFigure = (direction: number) =>
{
if(direction < AvatarDirectionAngle.MIN_DIRECTION)
{
@ -32,19 +27,19 @@ export const AvatarEditorFigurePreviewView: FC<AvatarEditorFigurePreviewViewProp
}
figureData.direction = direction;
}, [ figureData ]);
}
useEffect(() =>
{
if(!figureData) return;
figureData.notify = rerender;
figureData.notify = () => setUpdateId(prevValue => (prevValue + 1));
return () =>
{
figureData.notify = null;
}
}, [ figureData, rerender ] );
}, [ figureData ] );
return (
<Column className="figure-preview-container" overflow="hidden" position="relative">

View File

@ -1,5 +1,5 @@
import { ILinkEventTracker, RoomSessionEvent } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useState } from 'react';
import { FC, useEffect, useState } from 'react';
import { AddEventLinkTracker, RemoveLinkEventTracker } from '../../api';
import { useCamera, useRoomSessionManagerEvent } from '../../hooks';
import { CameraWidgetCaptureView } from './views/CameraWidgetCaptureView';
@ -43,11 +43,11 @@ export const CameraWidgetView: FC<{}> = props =>
}
}
const checkoutPictureUrl = useCallback((pictureUrl: string) =>
const checkoutPictureUrl = (pictureUrl: string) =>
{
setSavedPictureUrl(pictureUrl);
setMode(MODE_CHECKOUT);
}, []);
}
useRoomSessionManagerEvent<RoomSessionEvent>(RoomSessionEvent.ENDED, event => setMode(MODE_NONE));

View File

@ -1,6 +1,6 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { NitroRectangle, TextureUtils } from '@nitrots/nitro-renderer';
import { FC, useCallback, useRef } from 'react';
import { FC, useRef } from 'react';
import { CameraPicture, GetRoomEngine, GetRoomSession, LocalizeText, PlaySound, SoundNames } from '../../../api';
import { Column, DraggableWindow, Flex } from '../../../common';
import { useCamera, useNotification } from '../../../hooks';
@ -23,16 +23,16 @@ export const CameraWidgetCaptureView: FC<CameraWidgetCaptureViewProps> = props =
const selectedPicture = ((selectedPictureIndex > -1) ? cameraRoll[selectedPictureIndex] : null);
const getCameraBounds = useCallback(() =>
const getCameraBounds = () =>
{
if(!elementRef || !elementRef.current) return null;
const frameBounds = elementRef.current.getBoundingClientRect();
return new NitroRectangle(Math.floor(frameBounds.x), Math.floor(frameBounds.y), Math.floor(frameBounds.width), Math.floor(frameBounds.height));
}, []);
}
const takePicture = useCallback(() =>
const takePicture = () =>
{
if(selectedPictureIndex > -1)
{
@ -55,7 +55,7 @@ export const CameraWidgetCaptureView: FC<CameraWidgetCaptureViewProps> = props =
clone.push(new CameraPicture(texture, TextureUtils.generateImageUrl(texture)));
setCameraRoll(clone);
}, [ cameraRoll, selectedPictureIndex, getCameraBounds, setCameraRoll, setSelectedPictureIndex, simpleAlert ]);
}
return (
<DraggableWindow uniqueKey="nitro-camera-capture">

View File

@ -1,5 +1,5 @@
import { CampaignCalendarData, CampaignCalendarDataMessageEvent, CampaignCalendarDoorOpenedMessageEvent, ILinkEventTracker, OpenCampaignCalendarDoorAsStaffComposer, OpenCampaignCalendarDoorComposer } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useState } from 'react';
import { FC, useEffect, useState } from 'react';
import { AddEventLinkTracker, CalendarItem, RemoveLinkEventTracker, SendMessageComposer } from '../../api';
import { useMessageEvent } from '../../hooks';
import { CalendarView } from './CalendarView';
@ -11,11 +11,29 @@ export const CampaignView: FC<{}> = props =>
const [ receivedProducts, setReceivedProducts ] = useState<Map<number, CalendarItem>>(new Map());
const [ isCalendarOpen, setCalendarOpen ] = useState(false);
const openPackage = (id: number, asStaff = false) =>
{
if(!calendarData) return;
setLastOpenAttempt(id);
if(asStaff)
{
SendMessageComposer(new OpenCampaignCalendarDoorAsStaffComposer(calendarData.campaignName, id));
}
else
{
SendMessageComposer(new OpenCampaignCalendarDoorComposer(calendarData.campaignName, id));
}
}
useMessageEvent<CampaignCalendarDataMessageEvent>(CampaignCalendarDataMessageEvent, event =>
{
const parser = event.getParser();
if(!parser) return;
setCalendarData(parser.calendarData);
});
@ -49,28 +67,6 @@ export const CampaignView: FC<{}> = props =>
setLastOpenAttempt(-1);
});
const openPackage = useCallback((id: number, asStaff = false) =>
{
if(!calendarData) return;
setLastOpenAttempt(id);
if(asStaff)
{
SendMessageComposer(new OpenCampaignCalendarDoorAsStaffComposer(calendarData.campaignName, id));
}
else
{
SendMessageComposer(new OpenCampaignCalendarDoorComposer(calendarData.campaignName, id));
}
}, [ calendarData ]);
const onCalendarClose = useCallback(() =>
{
setCalendarOpen(false);
}, []);
useEffect(() =>
{
const linkTracker: ILinkEventTracker = {
@ -98,7 +94,7 @@ export const CampaignView: FC<{}> = props =>
return (
<>
{ (calendarData && isCalendarOpen) &&
<CalendarView onClose={ onCalendarClose } campaignName={ calendarData.campaignName } currentDay={ calendarData.currentDay } numDays={ calendarData.campaignDays } openedDays={ calendarData.openedDays } missedDays={ calendarData.missedDays } openPackage={ openPackage } receivedProducts={ receivedProducts } />
<CalendarView onClose={ () => setCalendarOpen(false) } campaignName={ calendarData.campaignName } currentDay={ calendarData.currentDay } numDays={ calendarData.campaignDays } openedDays={ calendarData.openedDays } missedDays={ calendarData.missedDays } openPackage={ openPackage } receivedProducts={ receivedProducts } />
}
</>
)

View File

@ -1,5 +1,5 @@
import { NitroToolbarAnimateIconEvent, TextureUtils, ToolbarIconEnum } from '@nitrots/nitro-renderer';
import { FC, useCallback, useRef } from 'react';
import { FC, useRef } from 'react';
import { GetRoomEngine } from '../../../../api';
import { LayoutRoomPreviewerView, LayoutRoomPreviewerViewProps } from '../../../../common';
import { CatalogPurchasedEvent } from '../../../../events';
@ -10,7 +10,7 @@ export const CatalogRoomPreviewerView: FC<LayoutRoomPreviewerViewProps> = props
const { roomPreviewer = null } = props;
const elementRef = useRef<HTMLDivElement>(null);
const animatePurchase = useCallback(() =>
useUiEvent(CatalogPurchasedEvent.PURCHASE_SUCCESS, event =>
{
if(!elementRef) return;
@ -27,19 +27,12 @@ export const CatalogRoomPreviewerView: FC<LayoutRoomPreviewerViewProps> = props
const x = (bounds.x + (bounds.width / 2));
const y = (bounds.y + (bounds.height / 2));
const event = new NitroToolbarAnimateIconEvent(image, x, y);
const animateEvent = new NitroToolbarAnimateIconEvent(image, x, y);
event.iconName = ToolbarIconEnum.INVENTORY;
animateEvent.iconName = ToolbarIconEnum.INVENTORY;
GetRoomEngine().events.dispatchEvent(event);
}, [ roomPreviewer ]);
const onCatalogPurchasedEvent = useCallback((event: CatalogPurchasedEvent) =>
{
animatePurchase();
}, [ animatePurchase ]);
useUiEvent(CatalogPurchasedEvent.PURCHASE_SUCCESS, onCatalogPurchasedEvent);
GetRoomEngine().events.dispatchEvent(animateEvent);
});
return (
<div ref={ elementRef }>

View File

@ -1,5 +1,5 @@
import { GetRoomAdPurchaseInfoComposer, GetUserEventCatsMessageComposer, PurchaseRoomAdMessageComposer, RoomAdPurchaseInfoEvent, RoomEntryData, UserEventCatsEvent } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useState } from 'react';
import { FC, useEffect, useState } from 'react';
import { LocalizeText, SendMessageComposer } from '../../../../../api';
import { Base, Button, Column, Text } from '../../../../../common';
import { useMessageEvent } from '../../../../../hooks';
@ -16,16 +16,7 @@ export const CatalogLayoutRoomAdsView: FC<CatalogLayoutProps> = props =>
const [ categoryId, setCategoryId ] = useState<number>(1);
const [ categories, setCategories ] = useState<INavigatorCategory[]>(null);
useMessageEvent<RoomAdPurchaseInfoEvent>(RoomAdPurchaseInfoEvent, event =>
{
const parser = event.getParser();
if(!parser) return;
setAvailableRooms(parser.rooms);
});
const purchaseAd = useCallback(() =>
const purchaseAd = () =>
{
const pageId = page.pageId;
const offerId = page.offers.length >= 1 ? page.offers[0].offerId : -1;
@ -35,7 +26,16 @@ export const CatalogLayoutRoomAdsView: FC<CatalogLayoutProps> = props =>
const catId = categoryId;
SendMessageComposer(new PurchaseRoomAdMessageComposer(pageId, offerId, flatId, name, extended, desc, catId))
}, [ categoryId, eventDesc, eventName, extended, page.offers, page.pageId, roomId ]);
}
useMessageEvent<RoomAdPurchaseInfoEvent>(RoomAdPurchaseInfoEvent, event =>
{
const parser = event.getParser();
if(!parser) return;
setAvailableRooms(parser.rooms);
});
useMessageEvent<UserEventCatsEvent>(UserEventCatsEvent, event =>
{

View File

@ -1,5 +1,5 @@
import { GroupInformationParser, GroupRemoveMemberComposer } from '@nitrots/nitro-renderer';
import { FC, useCallback } from 'react';
import { FC } from 'react';
import { CatalogPageName, CreateLinkEvent, GetGroupManager, GetGroupMembers, GetSessionDataManager, GroupMembershipType, GroupType, LocalizeText, SendMessageComposer, TryJoinGroup, TryVisitRoom } from '../../../api';
import { Button, Column, Flex, Grid, GridProps, LayoutBadgeImageView, Text } from '../../../common';
import { useNotification } from '../../../hooks';
@ -72,7 +72,7 @@ export const GroupInformationView: FC<GroupInformationViewProps> = props =>
joinGroup();
}
const handleAction = useCallback((action: string) =>
const handleAction = (action: string) =>
{
switch(action)
{
@ -95,7 +95,7 @@ export const GroupInformationView: FC<GroupInformationViewProps> = props =>
CreateLinkEvent('navigator/search/groups');
break;
}
}, [ groupInformation ]);
}
if(!groupInformation) return null;

View File

@ -1,5 +1,5 @@
import { GuideSessionFeedbackMessageComposer } from '@nitrots/nitro-renderer';
import { FC, useCallback } from 'react';
import { FC } from 'react';
import { LocalizeText, SendMessageComposer } from '../../../api';
import { Button, Column, Flex, Text } from '../../../common';
@ -12,10 +12,7 @@ export const GuideToolUserFeedbackView: FC<GuideToolUserFeedbackViewProps> = pro
{
const { userName = null } = props;
const giveFeedback = useCallback((recommend: boolean) =>
{
SendMessageComposer(new GuideSessionFeedbackMessageComposer(recommend));
}, []);
const giveFeedback = (recommend: boolean) => SendMessageComposer(new GuideSessionFeedbackMessageComposer(recommend));
return (
<Column>

View File

@ -1,5 +1,5 @@
import { ChangeUserNameMessageComposer, UserNameChangeMessageEvent } from '@nitrots/nitro-renderer';
import { FC, useCallback, useState } from 'react';
import { FC, useState } from 'react';
import { GetSessionDataManager, LocalizeText, SendMessageComposer } from '../../../../api';
import { useMessageEvent } from '../../../../hooks';
import { NameChangeLayoutViewProps } from './NameChangeView.types';
@ -8,6 +8,14 @@ export const NameChangeConfirmationView:FC<NameChangeLayoutViewProps> = props =>
{
const { username = '', onAction = null } = props;
const [ isConfirming, setIsConfirming ] = useState<boolean>(false);
const confirm = () =>
{
if(isConfirming) return;
setIsConfirming(true);
SendMessageComposer(new ChangeUserNameMessageComposer(username));
}
useMessageEvent<UserNameChangeMessageEvent>(UserNameChangeMessageEvent, event =>
{
@ -20,14 +28,6 @@ export const NameChangeConfirmationView:FC<NameChangeLayoutViewProps> = props =>
onAction('close');
});
const confirm = useCallback(() =>
{
if(isConfirming) return;
setIsConfirming(true);
SendMessageComposer(new ChangeUserNameMessageComposer(username));
}, [ isConfirming, username ]);
return (
<div className="d-flex flex-column gap-4 h-100">
<div className="bg-muted rounded p-2 text-center">{ LocalizeText('tutorial.name_change.info.confirm') }</div>

View File

@ -1,5 +1,5 @@
import { CheckUserNameMessageComposer, CheckUserNameResultMessageEvent } from '@nitrots/nitro-renderer';
import { FC, useCallback, useState } from 'react';
import { FC, useState } from 'react';
import { LocalizeText, SendMessageComposer } from '../../../../api';
import { useMessageEvent } from '../../../../hooks';
import { NameChangeLayoutViewProps } from './NameChangeView.types';
@ -14,12 +14,31 @@ const DISABLED: number = 6;
export const NameChangeInputView:FC<NameChangeLayoutViewProps> = props =>
{
const { onAction = null } = props;
const [ newUsername, setNewUsername ] = useState<string>('');
const [ canProceed, setCanProceed ] = useState<boolean>(false);
const [ isChecking, setIsChecking ] = useState<boolean>(false);
const [ errorCode, setErrorCode ] = useState<string>(null);
const [ suggestions, setSuggestions ] = useState<string[]>([]);
const check = () =>
{
if(newUsername === '') return;
setCanProceed(false);
setSuggestions([]);
setErrorCode(null);
setIsChecking(true);
SendMessageComposer(new CheckUserNameMessageComposer(newUsername));
}
const handleUsernameChange = (username: string) =>
{
setCanProceed(false);
setSuggestions([]);
setErrorCode(null);
setNewUsername(username);
}
useMessageEvent<CheckUserNameResultMessageEvent>(CheckUserNameResultMessageEvent, event =>
{
@ -52,45 +71,23 @@ export const NameChangeInputView:FC<NameChangeLayoutViewProps> = props =>
}
});
const check = useCallback(() =>
{
if(newUsername === '') return;
setCanProceed(false);
setSuggestions([]);
setErrorCode(null);
setIsChecking(true);
SendMessageComposer(new CheckUserNameMessageComposer(newUsername));
}, [ newUsername ]);
const handleUsernameChange = useCallback((username: string) =>
{
setCanProceed(false);
setSuggestions([]);
setErrorCode(null);
setNewUsername(username);
}, []);
return (
<div className="d-flex flex-column gap-3 h-100">
<div>{ LocalizeText('tutorial.name_change.info.select') }</div>
<div className="d-flex gap-2">
<input type="text" className="form-control form-control-sm" value={ newUsername } onChange={ (e) => handleUsernameChange(e.target.value) } />
<input type="text" className="form-control form-control-sm" value={ newUsername } onChange={ event => handleUsernameChange(event.target.value) } />
<button className="btn btn-primary" disabled={ newUsername === '' || isChecking } onClick={ check }>{ LocalizeText('tutorial.name_change.check') }</button>
</div>
{ !errorCode && !canProceed && <div className="bg-muted rounded p-2 text-center">{ LocalizeText('help.tutorial.name.info') }</div> }
{ errorCode && <div className="bg-danger rounded p-2 text-center text-white">{ LocalizeText(`help.tutorial.name.${ errorCode }`, [ 'name' ], [ newUsername ]) }</div> }
{ canProceed && <div className="bg-success rounded p-2 text-center text-white">{ LocalizeText('help.tutorial.name.available', [ 'name' ], [ newUsername ]) }</div> }
{ suggestions && <div className="d-flex flex-column gap-2">
{
suggestions.map((suggestion, i) =>
{
return (<div key={ i } className="col bg-muted rounded p-1 cursor-pointer" onClick={ () => handleUsernameChange(suggestion) }>{ suggestion }</div>);
})
}
</div> }
{ !errorCode && !canProceed &&
<div className="bg-muted rounded p-2 text-center">{ LocalizeText('help.tutorial.name.info') }</div> }
{ errorCode &&
<div className="bg-danger rounded p-2 text-center text-white">{ LocalizeText(`help.tutorial.name.${ errorCode }`, [ 'name' ], [ newUsername ]) }</div> }
{ canProceed &&
<div className="bg-success rounded p-2 text-center text-white">{ LocalizeText('help.tutorial.name.available', [ 'name' ], [ newUsername ]) }</div> }
{ suggestions &&
<div className="d-flex flex-column gap-2">
{ suggestions.map((suggestion, index) => <div key={ index } className="col bg-muted rounded p-1 cursor-pointer" onClick={ () => handleUsernameChange(suggestion) }>{ suggestion }</div>) }
</div> }
<div className="d-flex gap-2">
<button className="btn btn-success w-100" disabled={ !canProceed } onClick={ () => onAction('confirmation', newUsername) }>{ LocalizeText('tutorial.name_change.pick') }</button>
<button className="btn btn-primary w-100" onClick={ () => onAction('close') }>{ LocalizeText('cancel') }</button>

View File

@ -1,4 +1,4 @@
import { FC, useCallback, useMemo, useState } from 'react';
import { FC, useMemo, useState } from 'react';
import { LocalizeText } from '../../../../api';
import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../common';
import { HelpNameChangeEvent } from '../../../../events';
@ -17,13 +17,7 @@ export const NameChangeView:FC<{}> = props =>
const [ layout, setLayout ] = useState<string>(INIT);
const [ newUsername, setNewUsername ] = useState<string>('');
useUiEvent<HelpNameChangeEvent>(HelpNameChangeEvent.INIT, event =>
{
setLayout(INIT);
setIsVisible(true);
});
const onAction = useCallback((action: string, value?: string) =>
const onAction = (action: string, value?: string) =>
{
switch(action)
{
@ -39,7 +33,7 @@ export const NameChangeView:FC<{}> = props =>
setIsVisible(false);
break;
}
}, []);
}
const titleKey = useMemo(() =>
{
@ -50,6 +44,12 @@ export const NameChangeView:FC<{}> = props =>
case CONFIRMATION: return 'tutorial.name_change.title.confirm';
}
}, [ layout ]);
useUiEvent<HelpNameChangeEvent>(HelpNameChangeEvent.INIT, event =>
{
setLayout(INIT);
setIsVisible(true);
});
if(!isVisible) return null;

View File

@ -1,5 +1,5 @@
import { RoomSessionEvent } from '@nitrots/nitro-renderer';
import { FC, useCallback, useState } from 'react';
import { FC, useState } from 'react';
import { GetConfiguration, GetConfigurationManager } from '../../api';
import { LayoutAvatarImageView } from '../../common';
import { useRoomSessionManagerEvent, useSessionInfo } from '../../hooks';
@ -12,7 +12,9 @@ export const HotelView: FC<{}> = props =>
const [ isVisible, setIsVisible ] = useState(true);
const { userFigure = null } = useSessionInfo();
const onRoomSessionEvent = useCallback((event: RoomSessionEvent) =>
useRoomSessionManagerEvent<RoomSessionEvent>([
RoomSessionEvent.CREATED,
RoomSessionEvent.ENDED ], event =>
{
switch(event.type)
{
@ -23,10 +25,7 @@ export const HotelView: FC<{}> = props =>
setIsVisible(event.openLandingView);
return;
}
}, []);
useRoomSessionManagerEvent(RoomSessionEvent.CREATED, onRoomSessionEvent);
useRoomSessionManagerEvent(RoomSessionEvent.ENDED, onRoomSessionEvent);
});
if(!isVisible) return null;

View File

@ -1,4 +1,4 @@
import { FC, useCallback } from 'react';
import { FC } from 'react';
import { GetConfigurationManager, LocalizeText, OpenUrl } from '../../../../../api';
export interface WidgetContainerViewProps
@ -10,7 +10,7 @@ export const WidgetContainerView: FC<WidgetContainerViewProps> = props =>
{
const { conf = null } = props;
const getOption = useCallback((key: string) =>
const getOption = (key: string) =>
{
const option = conf[key];
@ -23,7 +23,7 @@ export const WidgetContainerView: FC<WidgetContainerViewProps> = props =>
}
return option;
}, [ conf ]);
}
return (
<div className="widgetcontainer widget d-flex flex-row overflow-hidden">

View File

@ -1,5 +1,5 @@
import { BannedUserData, BannedUsersFromRoomEvent, RoomBannedUsersComposer, RoomModerationSettings, RoomUnbanUserComposer } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useState } from 'react';
import { FC, useEffect, useState } from 'react';
import { IRoomData, LocalizeText, SendMessageComposer } from '../../../../api';
import { Button, Column, Flex, Grid, Text, UserProfileIconView } from '../../../../common';
import { useMessageEvent } from '../../../../hooks';
@ -16,16 +16,7 @@ export const NavigatorRoomSettingsModTabView: FC<NavigatorRoomSettingsTabViewPro
const [ selectedUserId, setSelectedUserId ] = useState<number>(-1);
const [ bannedUsers, setBannedUsers ] = useState<BannedUserData[]>([]);
useMessageEvent<BannedUsersFromRoomEvent>(BannedUsersFromRoomEvent, event =>
{
const parser = event.getParser();
if(!roomData || (roomData.roomId !== parser.roomId)) return;
setBannedUsers(parser.bannedUsers);
});
const unBanUser = useCallback((userId: number) =>
const unBanUser = (userId: number) =>
{
setBannedUsers(prevValue =>
{
@ -41,7 +32,16 @@ export const NavigatorRoomSettingsModTabView: FC<NavigatorRoomSettingsTabViewPro
SendMessageComposer(new RoomUnbanUserComposer(userId, roomData.roomId));
setSelectedUserId(-1);
}, [ roomData ]);
}
useMessageEvent<BannedUsersFromRoomEvent>(BannedUsersFromRoomEvent, event =>
{
const parser = event.getParser();
if(!roomData || (roomData.roomId !== parser.roomId)) return;
setBannedUsers(parser.bannedUsers);
});
useEffect(() =>
{

View File

@ -1,5 +1,5 @@
import { ILinkEventTracker, NitroLogger } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useRef, useState } from 'react';
import { FC, useEffect, useRef, useState } from 'react';
import { AddEventLinkTracker, GetConfiguration, OpenUrl, RemoveLinkEventTracker } from '../../api';
import { Base, NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../common';
@ -11,45 +11,45 @@ export const NitropediaView: FC<{}> = props =>
const [ header, setHeader ] = useState<string>('');
const [ dimensions, setDimensions ] = useState<{ width: number, height: number }>(null);
const elementRef = useRef<HTMLDivElement>(null);
const openPage = useCallback(async (link: string) =>
{
try
{
const response = await fetch(link);
if(!response) return;
const text = await response.text();
const splitData = text.split(NEW_LINE_REGEX);
const line = splitData.shift().split('|');
setHeader(line[0]);
setDimensions(prevValue =>
{
if(line[1] && (line[1].split(';').length === 2))
{
return {
width: parseInt(line[1].split(';')[0]),
height: parseInt(line[1].split(';')[1])
}
}
return null;
});
setContent(splitData.join(''));
}
catch (error)
{
NitroLogger.error(`Failed to fetch ${ link }`);
}
}, []);
useEffect(() =>
{
const openPage = async (link: string) =>
{
try
{
const response = await fetch(link);
if(!response) return;
const text = await response.text();
const splitData = text.split(NEW_LINE_REGEX);
const line = splitData.shift().split('|');
setHeader(line[0]);
setDimensions(prevValue =>
{
if(line[1] && (line[1].split(';').length === 2))
{
return {
width: parseInt(line[1].split(';')[0]),
height: parseInt(line[1].split(';')[1])
}
}
return null;
});
setContent(splitData.join(''));
}
catch (error)
{
NitroLogger.error(`Failed to fetch ${ link }`);
}
}
const linkTracker: ILinkEventTracker = {
linkReceived: (url: string) =>
{
@ -67,7 +67,7 @@ export const NitropediaView: FC<{}> = props =>
AddEventLinkTracker(linkTracker);
return () => RemoveLinkEventTracker(linkTracker);
}, [ openPage ]);
}, []);
useEffect(() =>
{

View File

@ -1,4 +1,4 @@
import { FC, useCallback, useState } from 'react';
import { FC, useState } from 'react';
import { LocalizeText, NotificationAlertItem, NotificationAlertType, OpenUrl } from '../../../../api';
import { Base, Button, Column, Flex, LayoutNotificationAlertView, LayoutNotificationAlertViewProps } from '../../../../common';
@ -10,17 +10,16 @@ interface NotificationDefaultAlertViewProps extends LayoutNotificationAlertViewP
export const NotificationDefaultAlertView: FC<NotificationDefaultAlertViewProps> = props =>
{
const { item = null, title = ((props.item && props.item.title) || ''), onClose = null, ...rest } = props;
const [ imageFailed, setImageFailed ] = useState<boolean>(false)
const visitUrl = useCallback(() =>
const visitUrl = () =>
{
OpenUrl(item.clickUrl);
onClose();
}, [ item, onClose ]);
}
const hasFrank = item.alertType === NotificationAlertType.DEFAULT;
const hasFrank = (item.alertType === NotificationAlertType.DEFAULT);
return (
<LayoutNotificationAlertView title={ title } onClose={ onClose } { ...rest } type={ hasFrank ? NotificationAlertType.DEFAULT : item.alertType }>

View File

@ -1,4 +1,4 @@
import { FC, useCallback, useEffect, useState } from 'react';
import { FC, useEffect, useState } from 'react';
import { LocalizeText, NotificationAlertItem, OpenUrl } from '../../../../api';
import { AutoGrid, Button, Column, Flex, LayoutNotificationAlertView, LayoutNotificationAlertViewProps } from '../../../../common';
@ -14,24 +14,25 @@ export const NotificationSeachAlertView: FC<NotificationDefaultAlertViewProps> =
const [ searchValue, setSearchValue ] = useState('');
const [ results, setResults ] = useState<string[]>([]);
const visitUrl = useCallback(() =>
const visitUrl = () =>
{
OpenUrl(item.clickUrl);
onClose();
}, [ item, onClose ]);
}
const updateSearchValue = (value: string) =>
{
let res = JSON.parse(item.messages[0]);
setResults(res.filter((val: string) => val.includes(value)));
setSearchValue(value);
}
useEffect(() =>
{
setResults(JSON.parse(item.messages[0]));
}, [ item ])
const updateSearchValue = useCallback((value: string) =>
{
let res = JSON.parse(item.messages[0]);
setResults(res.filter((val: string) => val.includes(value)));
setSearchValue(value);
},[ item ])
}, [ item ]);
const isAction = (item.clickUrl && item.clickUrl.startsWith('event:'));

View File

@ -1,5 +1,5 @@
import { FriendlyTime, HabboClubLevelEnum } from '@nitrots/nitro-renderer';
import { FC, useCallback, useMemo } from 'react';
import { FC, useMemo } from 'react';
import { CreateLinkEvent, GetConfiguration, LocalizeText } from '../../api';
import { Column, Flex, Grid, LayoutCurrencyIcon, Text } from '../../common';
import { usePurse } from '../../hooks';
@ -9,10 +9,11 @@ import { SeasonalView } from './views/SeasonalView';
export const PurseView: FC<{}> = props =>
{
const { purse = null, hcDisabled = false } = usePurse();
const displayedCurrencies = useMemo(() => GetConfiguration<number[]>('system.currency.types', []), []);
const currencyDisplayNumberShort = useMemo(() => GetConfiguration<boolean>('currency.display.number.short', false), []);
const getClubText = useMemo(() =>
const getClubText = (() =>
{
if(!purse) return null;
@ -24,9 +25,9 @@ export const PurseView: FC<{}> = props =>
else if((minutesUntilExpiration > -1) && (minutesUntilExpiration < (60 * 24))) return FriendlyTime.shortFormat(minutesUntilExpiration * 60);
else return FriendlyTime.shortFormat(totalDays * 86400);
}, [ purse ]);
})();
const getCurrencyElements = useCallback((offset: number, limit: number = -1, seasonal: boolean = false) =>
const getCurrencyElements = (offset: number, limit: number = -1, seasonal: boolean = false) =>
{
if(!purse || !purse.activityPoints || !purse.activityPoints.size) return null;
@ -56,7 +57,7 @@ export const PurseView: FC<{}> = props =>
}
return elements;
}, [ purse, displayedCurrencies, currencyDisplayNumberShort ]);
}
if(!purse) return null;

View File

@ -1,5 +1,5 @@
import { IFurnitureData, PetCustomPart, PetFigureData, RoomObjectCategory, RoomObjectVariable, RoomUserData } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useMemo, useState } from 'react';
import { FC, useEffect, useMemo, useState } from 'react';
import { FurniCategory, GetFurnitureDataForRoomObject, GetRoomEngine, LocalizeText, UseProductItem } from '../../../../api';
import { Base, Button, Column, Flex, LayoutPetImageView, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../../common';
import { useRoom } from '../../../../hooks';
@ -27,19 +27,19 @@ export const AvatarInfoUseProductConfirmView: FC<AvatarInfoUseProductConfirmView
const [ furniData, setFurniData ] = useState<IFurnitureData>(null);
const { roomSession = null } = useRoom();
const selectRoomObject = useCallback(() =>
const selectRoomObject = () =>
{
if(!petData) return;
GetRoomEngine().selectRoomObject(roomSession.roomId, petData.roomIndex, RoomObjectCategory.UNIT);
}, [ roomSession, petData ]);
}
const useProduct = useCallback(() =>
const useProduct = () =>
{
roomSession.usePetProduct(item.requestRoomObjectId, petData.webID);
onClose();
}, [ roomSession, item, petData, onClose ]);
}
const getPetImage = useMemo(() =>
{

View File

@ -1,5 +1,5 @@
import { RoomObjectCategory, RoomObjectType } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useState } from 'react';
import { FC, useEffect, useState } from 'react';
import { FurniCategory, GetFurnitureDataForRoomObject, LocalizeText, UseProductItem } from '../../../../api';
import { useRoom } from '../../../../hooks';
import { ContextMenuHeaderView } from '../context-menu/ContextMenuHeaderView';
@ -28,6 +28,26 @@ export const AvatarInfoUseProductView: FC<AvatarInfoUseProductViewProps> = props
const [ mode, setMode ] = useState(0);
const { roomSession = null } = useRoom();
const processAction = (name: string) =>
{
if(!name) return;
switch(name)
{
case 'use_product':
case 'use_product_shampoo':
case 'use_product_custom_part':
case 'use_product_custom_part_shampoo':
case 'use_product_saddle':
case 'replace_product_saddle':
case 'revive_monsterplant':
case 'rebreed_monsterplant':
case 'fertilize_monsterplant':
updateConfirmingProduct(item);
break;
}
}
useEffect(() =>
{
if(!item) return;
@ -65,26 +85,6 @@ export const AvatarInfoUseProductView: FC<AvatarInfoUseProductViewProps> = props
setMode(mode);
}, [ roomSession, item ]);
const processAction = useCallback((name: string) =>
{
if(!name) return;
switch(name)
{
case 'use_product':
case 'use_product_shampoo':
case 'use_product_custom_part':
case 'use_product_custom_part_shampoo':
case 'use_product_saddle':
case 'replace_product_saddle':
case 'revive_monsterplant':
case 'rebreed_monsterplant':
case 'fertilize_monsterplant':
updateConfirmingProduct(item);
break;
}
}, [ item, updateConfirmingProduct ]);
return (
<ContextMenuView objectId={ item.id } category={ RoomObjectCategory.UNIT } userType={ RoomObjectType.PET } onClose={ onClose } collapsable={ true }>

View File

@ -1,4 +1,4 @@
import { FC, useCallback, useEffect, useState } from 'react';
import { FC, useEffect, useState } from 'react';
import YouTube, { Options } from 'react-youtube';
import { YouTubePlayer } from 'youtube-player/dist/types';
import { LocalizeText, YoutubeVideoPlaybackStateEnum } from '../../../../api';
@ -10,7 +10,7 @@ export const FurnitureYoutubeDisplayView: FC<{}> = props =>
const [ player, setPlayer ] = useState<any>(null);
const { objectId = -1, videoId = null, videoStart = 0, videoEnd = 0, currentVideoState = null, selectedVideo = null, playlists = [], onClose = null, previous = null, next = null, pause = null, play = null, selectVideo = null } = useFurnitureYoutubeWidget();
const onStateChange = useCallback((event: { target: YouTubePlayer; data: number }) =>
const onStateChange = (event: { target: YouTubePlayer; data: number }) =>
{
setPlayer(event.target);
@ -30,7 +30,7 @@ export const FurnitureYoutubeDisplayView: FC<{}> = props =>
case 2:
if(currentVideoState !== 2) pause();
}
}, [ objectId, currentVideoState, play, pause ]);
}
useEffect(() =>
{

View File

@ -1,5 +1,5 @@
import { NitroRenderTexture } from '@nitrots/nitro-renderer';
import { FC, useCallback, useState } from 'react';
import { FC, useState } from 'react';
import { GetRoomEngine } from '../../../../api';
import { LayoutMiniCameraView } from '../../../../common';
import { RoomWidgetThumbnailEvent } from '../../../../events';
@ -10,7 +10,10 @@ export const RoomThumbnailWidgetView: FC<{}> = props =>
const [ isVisible, setIsVisible ] = useState(false);
const { roomSession = null } = useRoom();
const onNitroEvent = useCallback((event: RoomWidgetThumbnailEvent) =>
useUiEvent([
RoomWidgetThumbnailEvent.SHOW_THUMBNAIL,
RoomWidgetThumbnailEvent.HIDE_THUMBNAIL,
RoomWidgetThumbnailEvent.TOGGLE_THUMBNAIL ], event =>
{
switch(event.type)
{
@ -24,18 +27,14 @@ export const RoomThumbnailWidgetView: FC<{}> = props =>
setIsVisible(value => !value);
return;
}
}, []);
});
useUiEvent(RoomWidgetThumbnailEvent.SHOW_THUMBNAIL, onNitroEvent);
useUiEvent(RoomWidgetThumbnailEvent.HIDE_THUMBNAIL, onNitroEvent);
useUiEvent(RoomWidgetThumbnailEvent.TOGGLE_THUMBNAIL, onNitroEvent);
const receiveTexture = useCallback((texture: NitroRenderTexture) =>
const receiveTexture = (texture: NitroRenderTexture) =>
{
GetRoomEngine().saveTextureAsScreenshot(texture, true);
setIsVisible(false);
}, []);
}
if(!isVisible) return null;

View File

@ -1,5 +1,5 @@
import { Dispose, DropBounce, EaseOut, JumpBy, Motions, NitroToolbarAnimateIconEvent, PerkAllowancesMessageEvent, PerkEnum, Queue, Wait } from '@nitrots/nitro-renderer';
import { FC, useCallback, useState } from 'react';
import { FC, useState } from 'react';
import { CreateLinkEvent, GetSessionDataManager, MessengerIconState, OpenMessengerChat, VisitDesktop } from '../../api';
import { Base, Flex, LayoutAvatarImageView, LayoutItemCountView, TransitionAnimation, TransitionAnimationTypes } from '../../common';
import { useAchievements, useFriends, useInventoryUnseenTracker, useMessageEvent, useMessenger, useRoomEngineEvent, useSessionInfo } from '../../hooks';
@ -8,7 +8,6 @@ import { ToolbarMeView } from './ToolbarMeView';
export const ToolbarView: FC<{ isInRoom: boolean }> = props =>
{
const { isInRoom } = props;
const [ isMeExpanded, setMeExpanded ] = useState(false);
const [ useGuideTool, setUseGuideTool ] = useState(false);
const { userFigure = null } = useSessionInfo();
@ -25,42 +24,42 @@ export const ToolbarView: FC<{ isInRoom: boolean }> = props =>
setUseGuideTool(parser.isAllowed(PerkEnum.USE_GUIDE_TOOL));
});
const animationIconToToolbar = useCallback((iconName: string, image: HTMLImageElement, x: number, y: number) =>
{
const target = (document.body.getElementsByClassName(iconName)[0] as HTMLElement);
if(!target) return;
image.className = 'toolbar-icon-animation';
image.style.visibility = 'visible';
image.style.left = (x + 'px');
image.style.top = (y + 'px');
document.body.append(image);
const targetBounds = target.getBoundingClientRect();
const imageBounds = image.getBoundingClientRect();
const left = (imageBounds.x - targetBounds.x);
const top = (imageBounds.y - targetBounds.y);
const squared = Math.sqrt(((left * left) + (top * top)));
const wait = (500 - Math.abs(((((1 / squared) * 100) * 500) * 0.5)));
const height = 20;
const motionName = (`ToolbarBouncing[${ iconName }]`);
if(!Motions.getMotionByTag(motionName))
{
Motions.runMotion(new Queue(new Wait((wait + 8)), new DropBounce(target, 400, 12))).tag = motionName;
}
const motion = new Queue(new EaseOut(new JumpBy(image, wait, ((targetBounds.x - imageBounds.x) + height), (targetBounds.y - imageBounds.y), 100, 1), 1), new Dispose(image));
Motions.runMotion(motion);
}, []);
useRoomEngineEvent<NitroToolbarAnimateIconEvent>(NitroToolbarAnimateIconEvent.ANIMATE_ICON, event =>
{
const animationIconToToolbar = (iconName: string, image: HTMLImageElement, x: number, y: number) =>
{
const target = (document.body.getElementsByClassName(iconName)[0] as HTMLElement);
if(!target) return;
image.className = 'toolbar-icon-animation';
image.style.visibility = 'visible';
image.style.left = (x + 'px');
image.style.top = (y + 'px');
document.body.append(image);
const targetBounds = target.getBoundingClientRect();
const imageBounds = image.getBoundingClientRect();
const left = (imageBounds.x - targetBounds.x);
const top = (imageBounds.y - targetBounds.y);
const squared = Math.sqrt(((left * left) + (top * top)));
const wait = (500 - Math.abs(((((1 / squared) * 100) * 500) * 0.5)));
const height = 20;
const motionName = (`ToolbarBouncing[${ iconName }]`);
if(!Motions.getMotionByTag(motionName))
{
Motions.runMotion(new Queue(new Wait((wait + 8)), new DropBounce(target, 400, 12))).tag = motionName;
}
const motion = new Queue(new EaseOut(new JumpBy(image, wait, ((targetBounds.x - imageBounds.x) + height), (targetBounds.y - imageBounds.y), 100, 1), 1), new Dispose(image));
Motions.runMotion(motion);
}
animationIconToToolbar('icon-inventory', event.image, event.x, event.y);
});

View File

@ -1,5 +1,5 @@
import { RelationshipStatusInfoEvent, RelationshipStatusInfoMessageParser, RoomEngineObjectEvent, RoomObjectCategory, RoomObjectType, UserCurrentBadgesComposer, UserCurrentBadgesEvent, UserProfileEvent, UserProfileParser, UserRelationshipsComposer } from '@nitrots/nitro-renderer';
import { FC, useCallback, useState } from 'react';
import { FC, useState } from 'react';
import { CreateLinkEvent, GetRoomSession, GetSessionDataManager, GetUserProfile, LocalizeText, SendMessageComposer } from '../../api';
import { Column, Flex, Grid, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../common';
import { useMessageEvent, useRoomEngineEvent } from '../../hooks';
@ -21,12 +21,12 @@ export const UserProfileView: FC<{}> = props =>
setUserRelationships(null);
}
const onLeaveGroup = useCallback(() =>
const onLeaveGroup = () =>
{
if(!userProfile || (userProfile.id !== GetSessionDataManager().userId)) return;
GetUserProfile(userProfile.id);
}, [ userProfile ]);
}
useMessageEvent<UserCurrentBadgesEvent>(UserCurrentBadgesEvent, event =>
{

View File

@ -1,6 +1,6 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { ILinkEventTracker, NitroSettingsEvent, UserSettingsCameraFollowComposer, UserSettingsEvent, UserSettingsOldChatComposer, UserSettingsRoomInvitesComposer, UserSettingsSoundComposer } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useState } from 'react';
import { FC, useEffect, useState } from 'react';
import { AddEventLinkTracker, DispatchMainEvent, DispatchUiEvent, LocalizeText, RemoveLinkEventTracker, SendMessageComposer } from '../../api';
import { Column, Flex, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../common';
import { useCatalogPlaceMultipleItems, useCatalogSkipPurchaseConfirmation, useMessageEvent } from '../../hooks';
@ -12,7 +12,7 @@ export const UserSettingsView: FC<{}> = props =>
const [ catalogPlaceMultipleObjects, setCatalogPlaceMultipleObjects ] = useCatalogPlaceMultipleItems();
const [ catalogSkipPurchaseConfirmation, setCatalogSkipPurchaseConfirmation ] = useCatalogSkipPurchaseConfirmation();
const processAction = useCallback((type: string, value?: boolean | number | string) =>
const processAction = (type: string, value?: boolean | number | string) =>
{
let doUpdate = true;
@ -56,9 +56,9 @@ export const UserSettingsView: FC<{}> = props =>
if(doUpdate) setUserSettings(clone);
DispatchMainEvent(clone)
}, [ userSettings ]);
}
const saveRangeSlider = useCallback((type: string) =>
const saveRangeSlider = (type: string) =>
{
switch(type)
{
@ -66,7 +66,7 @@ export const UserSettingsView: FC<{}> = props =>
SendMessageComposer(new UserSettingsSoundComposer(Math.round(userSettings.volumeSystem), Math.round(userSettings.volumeFurni), Math.round(userSettings.volumeTrax)));
break;
}
}, [ userSettings ]);
}
useMessageEvent<UserSettingsEvent>(UserSettingsEvent, event =>
{

View File

@ -1,5 +1,5 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { FC, useCallback, useEffect, useState } from 'react';
import { FC, useEffect, useState } from 'react';
import ReactSlider from 'react-slider';
import { LocalizeText, WiredFurniType } from '../../../../api';
import { Button, Column, Flex, Text } from '../../../../common';
@ -16,12 +16,9 @@ export const WiredActionGiveRewardView: FC<{}> = props =>
const [ rewards, setRewards ] = useState<{ isBadge: boolean, itemCode: string, probability: number }[]>([]);
const { trigger = null, setIntParams = null, setStringParam = null } = useWired();
const addReward = useCallback(() =>
{
setRewards(rewards => [ ...rewards, { isBadge: false, itemCode: '', probability: null } ]);
}, [ setRewards ]);
const addReward = () => setRewards(rewards => [ ...rewards, { isBadge: false, itemCode: '', probability: null } ]);
const removeReward = useCallback((index: number) =>
const removeReward = (index: number) =>
{
setRewards(prevValue =>
{
@ -31,9 +28,9 @@ export const WiredActionGiveRewardView: FC<{}> = props =>
return newValues;
});
}, [ setRewards ]);
}
const updateReward = useCallback((index: number, isBadge: boolean, itemCode: string, probability: number) =>
const updateReward = (index: number, isBadge: boolean, itemCode: string, probability: number) =>
{
const rewardsClone = Array.from(rewards);
const reward = rewardsClone[index];
@ -45,9 +42,9 @@ export const WiredActionGiveRewardView: FC<{}> = props =>
reward.probability = probability;
setRewards(rewardsClone);
}, [ rewards, setRewards ]);
}
const save = useCallback(() =>
const save = () =>
{
let stringRewards = [];
@ -64,7 +61,7 @@ export const WiredActionGiveRewardView: FC<{}> = props =>
setStringParam(stringRewards.join(';'));
setIntParams([ rewardTime, uniqueRewards ? 1 : 0, rewardsLimit, limitationInterval ]);
}
}, [ rewardTime, uniqueRewards, rewardsLimit, limitationInterval, rewards, setIntParams, setStringParam ]);
}
useEffect(() =>
{

View File

@ -1,28 +1,25 @@
import { UnseenItemsEvent, UnseenResetCategoryComposer, UnseenResetItemsComposer } from '@nitrots/nitro-renderer';
import { useCallback, useMemo, useState } from 'react';
import { useState } from 'react';
import { useBetween } from 'use-between';
import { SendMessageComposer } from '../../api';
import { useMessageEvent } from '../events';
const sendResetCategoryMessage = (category: number) => SendMessageComposer(new UnseenResetCategoryComposer(category));
const sendResetItemsMessage = (category: number, itemIds: number[]) => SendMessageComposer(new UnseenResetItemsComposer(category, ...itemIds));
const useInventoryUnseenTrackerState = () =>
{
const [ unseenItems, setUnseenItems ] = useState<Map<number, number[]>>(new Map());
const getCount = useCallback((category: number) => (unseenItems.get(category)?.length || 0), [ unseenItems ]);
const getCount = (category: number) => (unseenItems.get(category)?.length || 0);
const getFullCount = useMemo(() =>
const getFullCount = (() =>
{
let count = 0;
for(const key of unseenItems.keys()) count += getCount(key);
return count;
}, [ unseenItems, getCount ]);
})();
const resetCategory = useCallback((category: number) =>
const resetCategory = (category: number) =>
{
let didReset = true;
@ -39,15 +36,15 @@ const useInventoryUnseenTrackerState = () =>
newValue.delete(category);
sendResetCategoryMessage(category);
SendMessageComposer(new UnseenResetCategoryComposer(category));
return newValue;
});
return didReset;
}, []);
}
const resetItems = useCallback((category: number, itemIds: number[]) =>
const resetItems = (category: number, itemIds: number[]) =>
{
let didReset = true;
@ -65,24 +62,24 @@ const useInventoryUnseenTrackerState = () =>
if(existing) for(const itemId of itemIds) existing.splice(existing.indexOf(itemId), 1);
sendResetItemsMessage(category, itemIds);
SendMessageComposer(new UnseenResetItemsComposer(category, ...itemIds))
return newValue;
});
return didReset;
}, []);
}
const isUnseen = useCallback((category: number, itemId: number) =>
const isUnseen = (category: number, itemId: number) =>
{
if(!unseenItems.has(category)) return false;
const items = unseenItems.get(category);
return (items.indexOf(itemId) >= 0);
}, [ unseenItems ]);
}
const removeUnseen = useCallback((category: number, itemId: number) =>
const removeUnseen = (category: number, itemId: number) =>
{
setUnseenItems(prevValue =>
{
@ -96,7 +93,7 @@ const useInventoryUnseenTrackerState = () =>
return newValue;
});
}, []);
}
useMessageEvent<UnseenItemsEvent>(UnseenItemsEvent, event =>
{

View File

@ -1,5 +1,5 @@
import { ContextMenuEnum, GroupFurniContextMenuInfoMessageEvent, GroupFurniContextMenuInfoMessageParser, RoomEngineTriggerWidgetEvent, RoomObjectCategory } from '@nitrots/nitro-renderer';
import { useCallback, useState } from 'react';
import { useState } from 'react';
import { GetRoomEngine, IsOwnerOfFurniture, TryJoinGroup, TryVisitRoom } from '../../../../api';
import { useMessageEvent, useRoomEngineEvent } from '../../../events';
import { useRoom } from '../../useRoom';
@ -19,13 +19,13 @@ const useFurnitureContextMenuWidgetState = () =>
const [ isGroupMember, setIsGroupMember ] = useState(false);
const { roomSession = null } = useRoom();
const onClose = useCallback(() =>
const onClose = () =>
{
setObjectId(-1);
setGroupData(null);
setIsGroupMember(false);
setMode(null);
}, []);
}
const closeConfirm = () =>
{

View File

@ -1,5 +1,5 @@
import { FurnitureExchangeComposer, RoomEngineTriggerWidgetEvent, RoomObjectVariable } from '@nitrots/nitro-renderer';
import { useCallback, useState } from 'react';
import { useState } from 'react';
import { GetRoomEngine, GetRoomSession, IsOwnerOfFurniture } from '../../../../api';
import { useRoomEngineEvent } from '../../../events';
import { useFurniRemovedEvent } from '../../engine';
@ -10,12 +10,12 @@ const useFurnitureExchangeWidgetState = () =>
const [ category, setCategory ] = useState(-1);
const [ value, setValue ] = useState(0);
const onClose = useCallback(() =>
const onClose = () =>
{
setObjectId(-1);
setCategory(-1);
setValue(0);
}, []);
}
const redeem = () =>
{

View File

@ -1,5 +1,5 @@
import { AvatarAction, IQuestion, RoomSessionWordQuizEvent } from '@nitrots/nitro-renderer';
import { useCallback, useEffect, useState } from 'react';
import { useEffect, useState } from 'react';
import { GetRoomEngine, VoteValue } from '../../../api';
import { useRoomSessionManagerEvent } from '../../events';
import { useRoom } from '../useRoom';
@ -34,29 +34,6 @@ const useWordQuizWidgetState = () =>
setAnswerSent(true);
}
const checkSignFade = useCallback(() =>
{
setUserAnswers(prevValue =>
{
const keysToRemove: number[] = [];
prevValue.forEach((value, key) =>
{
value.secondsLeft--;
if(value.secondsLeft <= 0) keysToRemove.push(key);
});
if(keysToRemove.length === 0) return prevValue;
const copy = new Map(prevValue);
keysToRemove.forEach(key => copy.delete(key));
return copy;
});
}, []);
useRoomSessionManagerEvent<RoomSessionWordQuizEvent>(RoomSessionWordQuizEvent.ANSWERED, event =>
{
const userData = roomSession.userDataManager.getUserData(event.userId);
@ -79,14 +56,7 @@ const useWordQuizWidgetState = () =>
return prevValue;
});
if(event.value === '0')
{
GetRoomEngine().updateRoomObjectUserGesture(roomSession.roomId, userData.roomIndex, AvatarAction.getGestureId(AvatarAction.GESTURE_SAD));
}
else
{
GetRoomEngine().updateRoomObjectUserGesture(roomSession.roomId, userData.roomIndex, AvatarAction.getGestureId(AvatarAction.GESTURE_SMILE));
}
GetRoomEngine().updateRoomObjectUserGesture(roomSession.roomId, userData.roomIndex, AvatarAction.getGestureId((event.value === '0') ? AvatarAction.GESTURE_SAD : AvatarAction.GESTURE_SMILE));
});
useRoomSessionManagerEvent<RoomSessionWordQuizEvent>(RoomSessionWordQuizEvent.FINISHED, event =>
@ -132,10 +102,33 @@ const useWordQuizWidgetState = () =>
useEffect(() =>
{
const checkSignFade = () =>
{
setUserAnswers(prevValue =>
{
const keysToRemove: number[] = [];
prevValue.forEach((value, key) =>
{
value.secondsLeft--;
if(value.secondsLeft <= 0) keysToRemove.push(key);
});
if(keysToRemove.length === 0) return prevValue;
const copy = new Map(prevValue);
keysToRemove.forEach(key => copy.delete(key));
return copy;
});
}
const interval = setInterval(() => checkSignFade(), 1000);
return () => clearInterval(interval);
}, [ checkSignFade ]);
}, []);
useEffect(() =>
{