Merge branch '@update/react-18' into @update/friends

This commit is contained in:
Bill 2022-04-02 01:44:08 -04:00
commit 6f865f05ec
240 changed files with 3517 additions and 3697 deletions

View File

@ -1,86 +0,0 @@
module.exports = {
'extends': [
'react-app',
'react-app/jest'
],
'rules': {
'linebreak-style': [
'off'
],
'quotes': [
'error',
'single'
],
'brace-style': [
'error',
'allman',
{
'allowSingleLine': true
}
],
'object-curly-spacing': [
'error',
'always'
],
'keyword-spacing': [
'error',
{
'overrides': {
'if': {
'after': false
},
'for': {
'after': false
},
'while': {
'after': false
},
'switch': {
'after': false
}
}
}
],
'@typescript-eslint/no-explicit-any': [
'off'
],
'@typescript-eslint/ban-ts-comment': [
'off'
],
'@typescript-eslint/no-empty-function': [
'error',
{
'allow': [
'functions',
'arrowFunctions',
'generatorFunctions',
'methods',
'generatorMethods',
'constructors'
]
}
],
'@typescript-eslint/no-unused-vars': [
'off'
],
'@typescript-eslint/ban-types': [
'error',
{
'types': {
'String': true,
'Boolean': true,
'Number': true,
'Symbol': true,
'{}': false,
'Object': false,
'object': false,
'Function': false
},
'extendDefaults': true
}
],
'no-switch-case-fall-through': [
'off'
]
}
}

55
.eslintrc.json Normal file
View File

@ -0,0 +1,55 @@
{
"settings": {
"react": {
"pragma": "React",
"version": "18.0.0"
}
},
"env": {
"browser": true,
"es2021": true
},
"extends": [
"plugin:react/recommended",
"plugin:react/jsx-runtime",
"plugin:react-hooks/recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": "latest",
"sourceType": "module"
},
"plugins": [
"react",
"@typescript-eslint"
],
"rules": {
"linebreak-style": [ "off" ],
"quotes": [ "error", "single" ],
"@typescript-eslint/indent": [ "error", 4, { "SwitchCase": 1 } ],
"array-bracket-spacing": [ "error", "always" ],
"brace-style": [ "error", "allman" ],
"react/prop-types": [ "off" ],
"object-curly-spacing": [ "error", "always" ],
"@typescript-eslint/ban-types": [
"error",
{
"types": {
"String": true,
"Boolean": true,
"Number": true,
"Symbol": true,
"{}": false,
"Object": false,
"object": false,
"Function": false
},
"extendDefaults": true
}
],
"no-switch-case-fall-through": [ "off" ]
}
}

View File

@ -1 +0,0 @@
*.scss

View File

@ -14,5 +14,7 @@
"files.insertFinalNewline": true,
"files.trimFinalNewlines": true,
"editor.wordWrap": "on",
"emmet.showExpandedAbbreviation": "never"
"emmet.showExpandedAbbreviation": "never",
"eslint.validate": [ "javascript", "javascriptreact", "html", "typescriptreact" ],
"eslint.workingDirectories": [ "./src" ]
}

View File

@ -7,7 +7,8 @@
"build": "cross-env SKIP_PREFLIGHT_CHECK=true GENERATE_SOURCEMAP=false IMAGE_INLINE_SIZE_LIMIT=100000 craco build",
"build:prod": "npx browserslist@latest --update-db && yarn build",
"test": "craco test",
"eject": "react-scripts eject"
"eject": "react-scripts eject",
"eslint": "eslint src --ext .ts,.tsx"
},
"dependencies": {
"@craco/craco": "^6.3.0",
@ -20,11 +21,11 @@
"cross-env": "^7.0.3",
"emoji-toolkit": "^6.6.0",
"node-sass": "^6.0.1",
"react": "^17.0.2",
"react": "^18.0.0",
"react-bootstrap": "^2.2.2",
"react-dom": "^17.0.2",
"react-dom": "^18.0.0",
"react-scripts": "4.0.3",
"react-slider": "^1.3.1",
"react-slider": "^2.0.0",
"react-transition-group": "^4.4.2",
"react-virtualized": "^9.22.3",
"react-youtube": "^7.13.1",
@ -41,7 +42,13 @@
"@types/react-slider": "^1.3.1",
"@types/react-transition-group": "^4.4.2",
"@types/react-virtualized": "^9.21.13",
"@typescript-eslint/eslint-plugin": "^4.29.1",
"@typescript-eslint/eslint-plugin": "^5.17.0",
"@typescript-eslint/parser": "^5.17.0",
"eslint": "^8.12.0",
"eslint-plugin-import": "^2.25.4",
"eslint-plugin-jsx-a11y": "^6.5.1",
"eslint-plugin-react": "^7.29.4",
"eslint-plugin-react-hooks": "^4.4.0",
"react-error-overlay": "6.0.9"
}
}

View File

@ -14,8 +14,8 @@ export const App: FC<{}> = props =>
{
const [ isReady, setIsReady ] = useState(false);
const [ isError, setIsError ] = useState(false);
const [message, setMessage] = useState('Getting Ready');
const [percent, setPercent] = useState(0);
const [ message, setMessage ] = useState('Getting Ready');
const [ percent, setPercent ] = useState(0);
//@ts-ignore
if(!NitroConfig) throw new Error('NitroConfig is not defined!');

View File

@ -6,5 +6,6 @@ export class MessengerSettings
public userFriendLimit: number = 0,
public normalFriendLimit: number = 0,
public extendedFriendLimit: number = 0,
public categories: FriendCategoryData[] = []) {}
public categories: FriendCategoryData[] = [])
{}
}

View File

@ -10,5 +10,6 @@ export class TradeUserData
public itemCount: number = 0,
public creditsCount: number = 0,
public accepts: boolean = false,
public canTrade: boolean = false) {}
public canTrade: boolean = false)
{}
}

View File

@ -3,7 +3,6 @@ export interface IUnseenItemTracker
dispose(): void;
resetCategory(category: number): boolean;
resetItems(category: number, itemIds: number[]): boolean;
resetCategoryIfEmpty(category: number): boolean;
isUnseen(category: number, itemId: number): boolean;
removeUnseen(category: number, itemId: number): boolean;
getIds(category: number): number[];

View File

@ -43,7 +43,7 @@ export class FurnitureInternalLinkHandler extends RoomWidgetHandler
public get eventTypes(): string[]
{
return [RoomEngineTriggerWidgetEvent.REQUEST_INTERNAL_LINK];
return [ RoomEngineTriggerWidgetEvent.REQUEST_INTERNAL_LINK ];
}
public get messageTypes(): string[]

View File

@ -49,7 +49,7 @@ export class FurnitureRoomLinkHandler extends RoomWidgetHandler
public get eventTypes(): string[]
{
return [RoomEngineTriggerWidgetEvent.REQUEST_ROOM_LINK];
return [ RoomEngineTriggerWidgetEvent.REQUEST_ROOM_LINK ];
}
public get messageTypes(): string[]

View File

@ -63,11 +63,11 @@ export class PollWidgetHandler extends RoomWidgetHandler
public get eventTypes(): string[]
{
return [RoomSessionPollEvent.OFFER, RoomSessionPollEvent.ERROR, RoomSessionPollEvent.CONTENT];
return [ RoomSessionPollEvent.OFFER, RoomSessionPollEvent.ERROR, RoomSessionPollEvent.CONTENT ];
}
public get messageTypes(): string[]
{
return [RoomWidgetPollMessage.ANSWER, RoomWidgetPollMessage.REJECT, RoomWidgetPollMessage.START];
return [ RoomWidgetPollMessage.ANSWER, RoomWidgetPollMessage.REJECT, RoomWidgetPollMessage.START ];
}
}

View File

@ -101,7 +101,7 @@ export class RoomWidgetChatHandler extends RoomWidgetHandler implements IAvatarI
text = LocalizeText('widget.chatbubble.pettreat', [ 'petname' ], [ username ]);
break;
case RoomSessionChatEvent.CHAT_TYPE_HAND_ITEM_RECEIVED:
text = LocalizeText('widget.chatbubble.handitem', [ 'username', 'handitem' ], [ username, LocalizeText(('handitem' + chatEvent.extraParam))]);
text = LocalizeText('widget.chatbubble.handitem', [ 'username', 'handitem' ], [ username, LocalizeText(('handitem' + chatEvent.extraParam)) ]);
break;
case RoomSessionChatEvent.CHAT_TYPE_MUTE_REMAINING: {
const hours = ((chatEvent.extraParam > 0) ? Math.floor((chatEvent.extraParam / 3600)) : 0).toString();

View File

@ -64,7 +64,7 @@ export class WordQuizWidgetHandler extends RoomWidgetHandler
public get eventTypes(): string[]
{
return [RoomSessionWordQuizEvent.ANSWERED, RoomSessionWordQuizEvent.FINISHED, RoomSessionWordQuizEvent.QUESTION];
return [ RoomSessionWordQuizEvent.ANSWERED, RoomSessionWordQuizEvent.FINISHED, RoomSessionWordQuizEvent.QUESTION ];
}
public get messageTypes(): string[]

View File

@ -4,7 +4,7 @@ export class RoomWidgetDanceMessage extends RoomWidgetMessage
{
public static DANCE: string = 'RWDM_MESSAGE_DANCE';
public static NORMAL_STYLE: number = 0;
public static CLUB_STYLE: number[] = [2, 3, 4];
public static CLUB_STYLE: number[] = [ 2, 3, 4 ];
private _style: number = 0;

View File

@ -157,7 +157,7 @@ export class NotificationUtilities
public static handleHotelClosedMessage(open: number, minute: number, thrownOut: boolean): void
{
this.simpleAlert( LocalizeText(('opening.hours.' + (thrownOut ? 'disconnected' : 'closed')), [ 'h', 'm'], [ this.getTimeZeroPadded(open), this.getTimeZeroPadded(minute) ]), NotificationAlertType.DEFAULT, null, null, LocalizeText('opening.hours.title'));
this.simpleAlert( LocalizeText(('opening.hours.' + (thrownOut ? 'disconnected' : 'closed')), [ 'h', 'm' ], [ this.getTimeZeroPadded(open), this.getTimeZeroPadded(minute) ]), NotificationAlertType.DEFAULT, null, null, LocalizeText('opening.hours.title'));
}
public static handleHotelMaintenanceMessage(minutesUntilMaintenance: number, duration: number): void

View File

@ -26,9 +26,9 @@ allowedColours.set('pink', 'pink');
function encodeHTML(str: string)
{
return str.replace(/([\u00A0-\u9999<>&])(.|$)/g, function(full, char, next)
{
{
if(char !== '&' || next !== '#')
{
{
if(/[\u00A0-\u9999<>&]/.test(next))
next = '&#' + next.charCodeAt(0) + ';';

View File

@ -2,7 +2,6 @@ import { MouseEventType, TouchEventType } from '@nitrots/nitro-renderer';
import { CSSProperties, FC, Key, MouseEvent as ReactMouseEvent, TouchEvent as ReactTouchEvent, useCallback, useEffect, useRef, useState } from 'react';
import { createPortal } from 'react-dom';
import { Base } from '..';
import { BatchUpdates } from '../../hooks';
import { DraggableWindowPosition } from './DraggableWindowPosition';
const CURRENT_WINDOWS: HTMLElement[] = [];
@ -134,12 +133,9 @@ export const DraggableWindow: FC<DraggableWindowProps> = props =>
offsetX = (document.body.offsetWidth - elementRef.current.offsetWidth) - elementRef.current.offsetLeft;
}
BatchUpdates(() =>
{
setDelta({ x: 0, y: 0 });
setOffset({ x: offsetX, y: offsetY });
setIsDragging(false);
});
if(uniqueKey !== null) POS_MEMORY.set(uniqueKey, { x: offsetX, y: offsetY });
}, [ dragHandler, delta, offset, uniqueKey ]);
@ -201,11 +197,8 @@ export const DraggableWindow: FC<DraggableWindowProps> = props =>
}
}
BatchUpdates(() =>
{
setDelta({ x: 0, y: 0 });
setOffset({ x: offsetX, y: offsetY });
});
return () =>
{
@ -213,7 +206,7 @@ export const DraggableWindow: FC<DraggableWindowProps> = props =>
if(index >= 0) CURRENT_WINDOWS.splice(index, 1);
}
}, [ handleSelector, windowPosition, uniqueKey, disableDrag, bringToTop ]);
}, [ handleSelector, windowPosition, uniqueKey, disableDrag, offsetLeft, offsetTop, bringToTop ]);
useEffect(() =>
{

View File

@ -67,7 +67,8 @@ export const LayoutAvatarImageView: FC<LayoutAvatarImageViewProps> = props =>
setRandomValue(Math.random());
},
dispose: () => {},
dispose: () =>
{},
disposed: false
}, null);

View File

@ -31,7 +31,7 @@ export const LayoutGiftTagView: FC<LayoutGiftTagViewProps> = props =>
{ editable && (onChange !== null) &&
<textarea className="gift-message h-100" maxLength={ 140 } value={ message } onChange={ (e) => onChange(e.target.value) } placeholder={ LocalizeText('catalog.gift_wrapping_new.message_hint') }></textarea> }
{ userName &&
<Text italics textEnd className="pe-1">{ LocalizeText('catalog.gift_wrapping_new.message_from', ['name'], [userName]) }</Text> }
<Text italics textEnd className="pe-1">{ LocalizeText('catalog.gift_wrapping_new.message_from', [ 'name' ], [ userName ]) }</Text> }
</Column>
</Flex>
</Flex>

View File

@ -15,7 +15,7 @@ export const LayoutNotificationAlertView: FC<LayoutNotificationAlertViewProps> =
const getClassNames = useMemo(() =>
{
const newClassNames: string[] = ['nitro-alert'];
const newClassNames: string[] = [ 'nitro-alert' ];
newClassNames.push('nitro-alert-' + type);

View File

@ -8,15 +8,11 @@ interface LayoutLimitedEditionStyledNumberViewProps
export const LayoutLimitedEditionStyledNumberView: FC<LayoutLimitedEditionStyledNumberViewProps> = props =>
{
const { value = 0 } = props;
const numbers = value.toString().split('');
return (
<>
{ numbers.map((number, index) =>
{
return <i key={ index } className={ 'limited-edition-number n-' + number } />;
})}
{ numbers.map((number, index) => <i key={ index } className={ 'limited-edition-number n-' + number } />) }
</>
);
}

View File

@ -3,7 +3,7 @@ import { FC, useCallback, useEffect, useMemo, useState } from 'react';
import { AchievementCategory, AddEventLinkTracker, CloneObject, GetAchievementCategoryImageUrl, GetAchievementIsIgnored, LocalizeText, RemoveLinkEventTracker, SendMessageComposer } from '../../api';
import { Base, Column, LayoutImage, LayoutProgressBar, NitroCardContentView, NitroCardHeaderView, NitroCardSubHeaderView, NitroCardView, Text } from '../../common';
import { AchievementsUIUnseenCountEvent } from '../../events';
import { BatchUpdates, DispatchUiEvent, UseMessageEventHook } from '../../hooks';
import { DispatchUiEvent, UseMessageEventHook } from '../../hooks';
import { AchievementCategoryView } from './views/AchievementCategoryView';
import { AchievementsCategoryListView } from './views/category-list/AchievementsCategoryListView';
@ -92,11 +92,8 @@ export const AchievementsView: FC<{}> = props =>
existing.achievements.push(achievement);
}
BatchUpdates(() =>
{
setAchievementCategories(categories);
setIsInitalized(true);
});
}, []);
UseMessageEventHook(AchievementsEvent, onAchievementsEvent);

View File

@ -5,7 +5,7 @@ import { FigureData } from './FigureData';
export class AvatarEditorGridPartItem implements IAvatarImageListener
{
private static ALPHA_FILTER: NitroAlphaFilter = new NitroAlphaFilter(0.2);
private static THUMB_DIRECTIONS: number[] = [2, 6, 0, 4, 3, 1];
private static THUMB_DIRECTIONS: number[] = [ 2, 6, 0, 4, 3, 1 ];
private static DRAW_ORDER: string[] = [
AvatarFigurePartType.LEFT_HAND_ITEM,
AvatarFigurePartType.LEFT_HAND,

View File

@ -4,5 +4,6 @@ export class CameraPicture
{
constructor(
public texture: NitroTexture,
public imageUrl: string) {}
public imageUrl: string)
{}
}

View File

@ -2,5 +2,6 @@ export class CameraPictureThumbnail
{
constructor(
public effectName: string,
public thumbnailUrl: string) {}
public thumbnailUrl: string)
{}
}

View File

@ -3,7 +3,7 @@ import { FC, useCallback, useEffect, useMemo, useState } from 'react';
import { GetConfiguration, GetRoomEngine, LocalizeText, SendMessageComposer } from '../../../../api';
import { Button, Column, Flex, LayoutCurrencyIcon, LayoutImage, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../../common';
import { InventoryEvent } from '../../../../events';
import { BatchUpdates, DispatchUiEvent, UseMessageEventHook } from '../../../../hooks';
import { DispatchUiEvent, UseMessageEventHook } from '../../../../hooks';
export interface CameraWidgetCheckoutViewProps
{
@ -26,12 +26,9 @@ export const CameraWidgetCheckoutView: FC<CameraWidgetCheckoutViewProps> = props
const publishDisabled = useMemo(() => GetConfiguration<boolean>('camera.publish.disabled', false), []);
const onCameraPurchaseOKMessageEvent = useCallback((event: CameraPurchaseOKMessageEvent) =>
{
BatchUpdates(() =>
{
setPicturesBought(value => (value + 1));
setIsWaiting(false);
});
}, []);
UseMessageEventHook(CameraPurchaseOKMessageEvent, onCameraPurchaseOKMessageEvent);
@ -40,13 +37,10 @@ export const CameraWidgetCheckoutView: FC<CameraWidgetCheckoutViewProps> = props
{
const parser = event.getParser();
BatchUpdates(() =>
{
setPublishUrl(parser.extraDataId);
setPublishCooldown(parser.secondsToWait);
setWasPicturePublished(parser.ok);
setIsWaiting(false);
});
}, []);
UseMessageEventHook(CameraPublishStatusMessageEvent, onCameraPublishStatusMessageEvent);

View File

@ -104,7 +104,7 @@ export const CalendarView: FC<CalendarViewProps> = props =>
<Column size={ 10 }>
<Flex justifyContent="between" alignItems="center" gap={ 1 }>
<Column gap={ 1 }>
<Text fontSize={ 3 }>{ LocalizeText('campaign.calendar.heading.day', ['number'], [(selectedDay + 1).toString()]) }</Text>
<Text fontSize={ 3 }>{ LocalizeText('campaign.calendar.heading.day', [ 'number' ], [ (selectedDay + 1).toString() ]) }</Text>
<Text>{ dayMessage(selectedDay) }</Text>
</Column>
<div>
@ -121,7 +121,7 @@ export const CalendarView: FC<CalendarViewProps> = props =>
</Flex>
<Column center fullWidth>
<Grid fit columnCount={ TOTAL_SHOWN_ITEMS } gap={ 1 }>
{ [...Array(TOTAL_SHOWN_ITEMS)].map((e, i) =>
{ [ ...Array(TOTAL_SHOWN_ITEMS) ].map((e, i) =>
{
const day = (index + i);

View File

@ -1,7 +1,7 @@
import { CampaignCalendarData, CampaignCalendarDataMessageEvent, CampaignCalendarDoorOpenedMessageEvent, OpenCampaignCalendarDoorAsStaffComposer, OpenCampaignCalendarDoorComposer } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useState } from 'react';
import { AddEventLinkTracker, CalendarItem, RemoveLinkEventTracker, SendMessageComposer } from '../../api';
import { BatchUpdates, UseMessageEventHook } from '../../hooks';
import { UseMessageEventHook } from '../../hooks';
import { CalendarView } from './CalendarView';
export const CampaignView: FC<{}> = props =>
@ -30,8 +30,6 @@ export const CampaignView: FC<{}> = props =>
const lastAttempt = lastOpenAttempt;
if(parser.doorOpened)
{
BatchUpdates(() =>
{
setCalendarData(prev =>
{
@ -48,11 +46,10 @@ export const CampaignView: FC<{}> = props =>
return copy;
});
});
}
setLastOpenAttempt(-1);
}, [lastOpenAttempt]);
}, [ lastOpenAttempt ]);
UseMessageEventHook(CampaignCalendarDoorOpenedMessageEvent, onCampaignCalendarDoorOpenedMessageEvent);
@ -71,7 +68,7 @@ export const CampaignView: FC<{}> = props =>
{
SendMessageComposer(new OpenCampaignCalendarDoorComposer(calendarData.campaignName, id));
}
}, [calendarData]);
}, [ calendarData ]);
const onCalendarClose = useCallback(() =>
{
@ -101,7 +98,7 @@ export const CampaignView: FC<{}> = props =>
{
RemoveLinkEventTracker(linkTracker);
}
}, [onLinkReceived]);
}, [ onLinkReceived ]);
return (
<>

View File

@ -3,7 +3,7 @@ import { GuildMembershipsMessageEvent } from '@nitrots/nitro-renderer/src/nitro/
import { FC, useCallback } from 'react';
import { GetFurnitureData, GetProductDataForLocalization, LocalizeText, NotificationAlertType, NotificationUtilities, ProductTypeEnum } from '../../api';
import { CatalogGiftReceiverNotFoundEvent, CatalogNameResultEvent, CatalogPurchasedEvent, CatalogPurchaseFailureEvent, CatalogPurchaseNotAllowedEvent, CatalogPurchaseSoldOutEvent } from '../../events';
import { BatchUpdates, DispatchUiEvent, UseMessageEventHook } from '../../hooks';
import { DispatchUiEvent, UseMessageEventHook } from '../../hooks';
import { useCatalogContext } from './CatalogContext';
import { CatalogNode } from './common/CatalogNode';
import { CatalogPetPalette } from './common/CatalogPetPalette';
@ -43,11 +43,8 @@ export const CatalogMessageHandler: FC<{}> = props =>
return catalogNode;
}
BatchUpdates(() =>
{
setRootNode(getCatalogNode(parser.root, 0, null));
setOffersToNodes(offers);
});
}, [ setRootNode, setOffersToNodes ]);
const onCatalogPageMessageEvent = useCallback((event: CatalogPageMessageEvent) =>
@ -77,8 +74,6 @@ export const CatalogMessageHandler: FC<{}> = props =>
if((currentType === CatalogType.NORMAL) || ((purchasableOffer.pricingModel !== Offer.PRICING_MODEL_BUNDLE) && (purchasableOffer.pricingModel !== Offer.PRICING_MODEL_MULTI))) purchasableOffers.push(purchasableOffer);
}
BatchUpdates(() =>
{
if(parser.frontPageItems && parser.frontPageItems.length) setFrontPageItems(parser.frontPageItems);
setIsBusy(false);
@ -87,7 +82,6 @@ export const CatalogMessageHandler: FC<{}> = props =>
{
showCatalogPage(parser.pageId, parser.layoutCode, new PageLocalization(parser.localization.images.concat(), parser.localization.texts.concat()), purchasableOffers, parser.offerId, parser.acceptSeasonCurrencyAsCredits);
}
});
}, [ currentType, pageId, setFrontPageItems, setIsBusy, showCatalogPage ]);
const onPurchaseOKMessageEvent = useCallback((event: PurchaseOKMessageEvent) =>

View File

@ -3,7 +3,7 @@ import { FC, useCallback, useEffect, useState } from 'react';
import { AddEventLinkTracker, GetRoomEngine, LocalizeText, NotificationAlertType, NotificationUtilities, PlaySound, RemoveLinkEventTracker, SendMessageComposer, SoundNames } from '../../api';
import { Column, Grid, NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../common';
import { CatalogPurchasedEvent } from '../../events';
import { BatchUpdates, UseMessageEventHook, UseUiEvent } from '../../hooks';
import { UseMessageEventHook, UseUiEvent } from '../../hooks';
import { CatalogContextProvider } from './CatalogContext';
import { CatalogMessageHandler } from './CatalogMessageHandler';
import { CatalogPage } from './common/CatalogPage';
@ -43,8 +43,6 @@ export const CatalogView: FC<{}> = props =>
const [ catalogOptions, setCatalogOptions ] = useState<ICatalogOptions>({});
const resetState = useCallback(() =>
{
BatchUpdates(() =>
{
setPageId(-1);
setPreviousPageId(-1);
@ -56,7 +54,6 @@ export const CatalogView: FC<{}> = props =>
setSearchResult(null);
setFrontPageItems([]);
setIsVisible(false);
});
}, []);
const onCatalogPublishedMessageEvent = useCallback((event: CatalogPublishedMessageEvent) =>
@ -119,11 +116,8 @@ export const CatalogView: FC<{}> = props =>
{
if(pageId < 0) return;
BatchUpdates(() =>
{
setIsBusy(true);
setPageId(pageId);
});
if(pageId > -1) SendMessageComposer(new GetCatalogPageComposer(pageId, offerId, currentType));
}, [ currentType ]);
@ -132,8 +126,6 @@ export const CatalogView: FC<{}> = props =>
{
const catalogPage = (new CatalogPage(pageId, layoutCode, localization, offers, acceptSeasonCurrencyAsCredits) as ICatalogPage);
BatchUpdates(() =>
{
setCurrentPage(catalogPage);
setPreviousPageId(prevValue => ((pageId !== -1) ? pageId : prevValue));
setNavigationHidden(false);
@ -149,7 +141,6 @@ export const CatalogView: FC<{}> = props =>
break;
}
}
});
}, []);
const activateNode = useCallback((targetNode: ICatalogNode, offerId: number = -1) =>
@ -213,8 +204,6 @@ export const CatalogView: FC<{}> = props =>
}, [ setActiveNodes, loadCatalogPage ]);
const openPageById = useCallback((id: number) =>
{
BatchUpdates(() =>
{
setSearchResult(null);
@ -230,12 +219,9 @@ export const CatalogView: FC<{}> = props =>
if(node) activateNode(node);
}
});
}, [ isVisible, rootNode, getNodeById, activateNode ]);
const openPageByName = useCallback((name: string) =>
{
BatchUpdates(() =>
{
setSearchResult(null);
@ -251,12 +237,9 @@ export const CatalogView: FC<{}> = props =>
if(node) activateNode(node);
}
});
}, [ isVisible, rootNode, getNodeByName, activateNode ]);
const openPageByOfferId = useCallback((offerId: number) =>
{
BatchUpdates(() =>
{
setSearchResult(null);
@ -274,7 +257,6 @@ export const CatalogView: FC<{}> = props =>
activateNode(nodes[0], offerId);
}
});
}, [ isVisible, getNodesByOfferId, activateNode ]);
const onCatalogPurchasedEvent = useCallback((event: CatalogPurchasedEvent) =>
@ -415,7 +397,10 @@ export const CatalogView: FC<{}> = props =>
<CatalogMessageHandler />
{ isVisible &&
<NitroCardView uniqueKey="catalog" className="nitro-catalog">
<NitroCardHeaderView headerText={ LocalizeText('catalog.title') } onCloseClick={ event => { setIsVisible(false); } } />
<NitroCardHeaderView headerText={ LocalizeText('catalog.title') } onCloseClick={ event =>
{
setIsVisible(false);
} } />
<NitroCardTabsView>
{ rootNode && (rootNode.children.length > 0) && rootNode.children.map(child =>
{

View File

@ -5,5 +5,6 @@ export class CatalogPetPalette
constructor(
public readonly breed: string,
public readonly palettes: SellablePetPaletteData[]
) {}
)
{}
}

View File

@ -85,21 +85,21 @@ export function GetPetAvailableColors(petIndex: number, palettes: SellablePetPal
switch(petIndex)
{
case 0:
return [[16743226], [16750435], [16764339], [0xF59500], [16498012], [16704690], [0xEDD400], [16115545], [16513201], [8694111], [11585939], [14413767], [6664599], [9553845], [12971486], [8358322], [10002885], [13292268], [10780600], [12623573], [14403561], [12418717], [14327229], [15517403], [14515069], [15764368], [16366271], [0xABABAB], [0xD4D4D4], [0xFFFFFF], [14256481], [14656129], [15848130], [14005087], [14337152], [15918540], [15118118], [15531929], [9764857], [11258085]];
return [ [ 16743226 ], [ 16750435 ], [ 16764339 ], [ 0xF59500 ], [ 16498012 ], [ 16704690 ], [ 0xEDD400 ], [ 16115545 ], [ 16513201 ], [ 8694111 ], [ 11585939 ], [ 14413767 ], [ 6664599 ], [ 9553845 ], [ 12971486 ], [ 8358322 ], [ 10002885 ], [ 13292268 ], [ 10780600 ], [ 12623573 ], [ 14403561 ], [ 12418717 ], [ 14327229 ], [ 15517403 ], [ 14515069 ], [ 15764368 ], [ 16366271 ], [ 0xABABAB ], [ 0xD4D4D4 ], [ 0xFFFFFF ], [ 14256481 ], [ 14656129 ], [ 15848130 ], [ 14005087 ], [ 14337152 ], [ 15918540 ], [ 15118118 ], [ 15531929 ], [ 9764857 ], [ 11258085 ] ];
case 1:
return [[16743226], [16750435], [16764339], [0xF59500], [16498012], [16704690], [0xEDD400], [16115545], [16513201], [8694111], [11585939], [14413767], [6664599], [9553845], [12971486], [8358322], [10002885], [13292268], [10780600], [12623573], [14403561], [12418717], [14327229], [15517403], [14515069], [15764368], [16366271], [0xABABAB], [0xD4D4D4], [0xFFFFFF], [14256481], [14656129], [15848130], [14005087], [14337152], [15918540], [15118118], [15531929], [9764857], [11258085]];
return [ [ 16743226 ], [ 16750435 ], [ 16764339 ], [ 0xF59500 ], [ 16498012 ], [ 16704690 ], [ 0xEDD400 ], [ 16115545 ], [ 16513201 ], [ 8694111 ], [ 11585939 ], [ 14413767 ], [ 6664599 ], [ 9553845 ], [ 12971486 ], [ 8358322 ], [ 10002885 ], [ 13292268 ], [ 10780600 ], [ 12623573 ], [ 14403561 ], [ 12418717 ], [ 14327229 ], [ 15517403 ], [ 14515069 ], [ 15764368 ], [ 16366271 ], [ 0xABABAB ], [ 0xD4D4D4 ], [ 0xFFFFFF ], [ 14256481 ], [ 14656129 ], [ 15848130 ], [ 14005087 ], [ 14337152 ], [ 15918540 ], [ 15118118 ], [ 15531929 ], [ 9764857 ], [ 11258085 ] ];
case 2:
return [[16579283], [15378351], [8830016], [15257125], [9340985], [8949607], [6198292], [8703620], [9889626], [8972045], [12161285], [13162269], [8620113], [12616503], [8628101], [0xD2FF00], [9764857]];
return [ [ 16579283 ], [ 15378351 ], [ 8830016 ], [ 15257125 ], [ 9340985 ], [ 8949607 ], [ 6198292 ], [ 8703620 ], [ 9889626 ], [ 8972045 ], [ 12161285 ], [ 13162269 ], [ 8620113 ], [ 12616503 ], [ 8628101 ], [ 0xD2FF00 ], [ 9764857 ] ];
case 3:
return [[0xFFFFFF], [0xEEEEEE], [0xDDDDDD]];
return [ [ 0xFFFFFF ], [ 0xEEEEEE ], [ 0xDDDDDD ] ];
case 4:
return [[0xFFFFFF], [16053490], [15464440], [16248792], [15396319], [15007487]];
return [ [ 0xFFFFFF ], [ 16053490 ], [ 15464440 ], [ 16248792 ], [ 15396319 ], [ 15007487 ] ];
case 5:
return [[0xFFFFFF], [0xEEEEEE], [0xDDDDDD]];
return [ [ 0xFFFFFF ], [ 0xEEEEEE ], [ 0xDDDDDD ] ];
case 6:
return [[0xFFFFFF], [0xEEEEEE], [0xDDDDDD], [16767177], [16770205], [16751331]];
return [ [ 0xFFFFFF ], [ 0xEEEEEE ], [ 0xDDDDDD ], [ 16767177 ], [ 16770205 ], [ 16751331 ] ];
case 7:
return [[0xCCCCCC], [0xAEAEAE], [16751331], [10149119], [16763290], [16743786]];
return [ [ 0xCCCCCC ], [ 0xAEAEAE ], [ 16751331 ], [ 10149119 ], [ 16763290 ], [ 16743786 ] ];
default: {
const colors: number[][] = [];

View File

@ -6,6 +6,6 @@ export class SearchResult
constructor(
public readonly searchValue: string,
public readonly offers: IPurchasableOffer[],
public readonly filteredNodes: ICatalogNode[]
) {}
public readonly filteredNodes: ICatalogNode[])
{}
}

View File

@ -8,7 +8,8 @@ export class SubscriptionInfo
public readonly clubPeriods: number = 0,
public readonly isVip: boolean = false,
public readonly pastDays: number = 0,
public readonly pastVipDays: number = 0) {}
public readonly pastVipDays: number = 0)
{}
public get lastUpdated(): number
{

View File

@ -5,7 +5,7 @@ import { FC, useCallback, useEffect, useMemo, useState } from 'react';
import { GetSessionDataManager, LocalizeText, ProductTypeEnum, SendMessageComposer } from '../../../../api';
import { Base, Button, ButtonGroup, Column, Flex, FormGroup, LayoutCurrencyIcon, LayoutFurniImageView, LayoutGiftTagView, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../../common';
import { CatalogEvent, CatalogInitGiftEvent, CatalogPurchasedEvent } from '../../../../events';
import { BatchUpdates, UseUiEvent } from '../../../../hooks';
import { UseUiEvent } from '../../../../hooks';
import { useCatalogContext } from '../../CatalogContext';
export const CatalogGiftView: FC<{}> = props =>
@ -28,8 +28,6 @@ export const CatalogGiftView: FC<{}> = props =>
const { giftConfiguration = null } = catalogOptions;
const close = useCallback(() =>
{
BatchUpdates(() =>
{
setIsVisible(false);
setPageId(0);
@ -42,7 +40,6 @@ export const CatalogGiftView: FC<{}> = props =>
setSelectedRibbonIndex(0);
if(colors.length) setSelectedColorId(colors[0].id);
});
}, [ colors ]);
const onCatalogEvent = useCallback((event: CatalogEvent) =>
@ -55,15 +52,12 @@ export const CatalogGiftView: FC<{}> = props =>
case CatalogEvent.INIT_GIFT:
const castedEvent = (event as CatalogInitGiftEvent);
BatchUpdates(() =>
{
close();
setPageId(castedEvent.pageId);
setOfferId(castedEvent.offerId);
setExtraData(castedEvent.extraData);
setIsVisible(true);
});
return;
case CatalogEvent.GIFT_RECEIVER_NOT_FOUND:
setReceiverNotFound(true);
@ -144,8 +138,6 @@ export const CatalogGiftView: FC<{}> = props =>
if(giftData.colors && giftData.colors.length > 0) newColors.push({ id: colorId, color: `#${giftData.colors[0].toString(16)}` });
}
BatchUpdates(() =>
{
setMaxBoxIndex(giftConfiguration.boxTypes.length - 1);
setMaxRibbonIndex(giftConfiguration.ribbonTypes.length - 1);
@ -154,7 +146,6 @@ export const CatalogGiftView: FC<{}> = props =>
setSelectedColorId(newColors[0].id);
setColors(newColors);
}
});
}, [ giftConfiguration ]);
if(!giftConfiguration || !giftConfiguration.isEnabled || !isVisible) return null;
@ -196,7 +187,7 @@ export const CatalogGiftView: FC<{}> = props =>
<Column gap={ 1 }>
<Text fontWeight="bold">{ LocalizeText(boxName) }</Text>
<Flex alignItems="center" gap={ 1 }>
{ LocalizeText(priceText, ['price'], [giftConfiguration.price.toString()]) }
{ LocalizeText(priceText, [ 'price' ], [ giftConfiguration.price.toString() ]) }
<LayoutCurrencyIcon type={ -1 } />
</Flex>
</Column>

View File

@ -3,7 +3,7 @@ import { RedeemVoucherMessageComposer, VoucherRedeemErrorMessageEvent, VoucherRe
import { FC, useCallback, useState } from 'react';
import { LocalizeText, NotificationUtilities, SendMessageComposer } from '../../../../../api';
import { Button, Flex } from '../../../../../common';
import { BatchUpdates, UseMessageEventHook } from '../../../../../hooks';
import { UseMessageEventHook } from '../../../../../hooks';
export interface CatalogRedeemVoucherViewProps
{
@ -35,11 +35,8 @@ export const CatalogRedeemVoucherView: FC<CatalogRedeemVoucherViewProps> = props
NotificationUtilities.simpleAlert(message, null, null, null, LocalizeText('catalog.alert.voucherredeem.ok.title'));
BatchUpdates(() =>
{
setIsWaiting(false);
setVoucher('');
});
}, []);
UseMessageEventHook(VoucherRedeemOkMessageEvent, onVoucherRedeemOkMessageEvent);

View File

@ -4,7 +4,6 @@ import { FC, useCallback, useEffect, useState } from 'react';
import { GetSessionDataManager, LocalizeText } from '../../../../../api';
import { Button } from '../../../../../common/Button';
import { Flex } from '../../../../../common/Flex';
import { BatchUpdates } from '../../../../../hooks';
import { useCatalogContext } from '../../../CatalogContext';
import { CatalogPage } from '../../../common/CatalogPage';
import { CatalogType } from '../../../common/CatalogType';
@ -23,8 +22,6 @@ export const CatalogSearchView: FC<{}> = props =>
const { currentType = null, rootNode = null, setActiveNodes = null, offersToNodes = null, searchResult = null, setSearchResult = null, setCurrentPage = null } = useCatalogContext();
const updateSearchValue = (value: string) =>
{
BatchUpdates(() =>
{
if(!value || !value.length)
{
@ -37,7 +34,6 @@ export const CatalogSearchView: FC<{}> = props =>
setSearchValue(value);
setNeedsProcessing(true);
}
});
}
const processSearch = useCallback((search: string) =>
@ -96,11 +92,8 @@ export const CatalogSearchView: FC<{}> = props =>
FilterCatalogNode(search, foundFurniLines, rootNode, nodes);
BatchUpdates(() =>
{
setCurrentPage((new CatalogPage(-1, 'default_3x3', new PageLocalization([], []), offers, false, 1) as ICatalogPage));
setSearchResult(new SearchResult(search, offers, nodes.filter(node => (node.isVisible))));
});
}, [ offersToNodes, currentType, rootNode, setCurrentPage, setSearchResult ]);
useEffect(() =>

View File

@ -44,8 +44,8 @@ export const CatalogLayoutMarketplaceItemView: FC<MarketplaceItemViewProps> = pr
text = hours + ' ' + LocalizeText('catalog.marketplace.offer.hours') + ' ' + text;
}
return LocalizeText('catalog.marketplace.offer.time_left', ['time'], [text] );
}, [offerData]);
return LocalizeText('catalog.marketplace.offer.time_left', [ 'time' ], [ text ] );
}, [ offerData ]);
return (
<LayoutGridItem shrink center={ false } column={ false } alignItems="center" className="p-1">
@ -59,8 +59,8 @@ export const CatalogLayoutMarketplaceItemView: FC<MarketplaceItemViewProps> = pr
</> }
{ (type === PUBLIC_OFFER) &&
<>
<Text>{ LocalizeText('catalog.marketplace.offer.price_public_item', ['price', 'average'], [offerData.price.toString(), offerData.averagePrice.toString() ]) }</Text>
<Text>{ LocalizeText('catalog.marketplace.offer_count', ['count'], [offerData.offerCount.toString()]) }</Text>
<Text>{ LocalizeText('catalog.marketplace.offer.price_public_item', [ 'price', 'average' ], [ offerData.price.toString(), offerData.averagePrice.toString() ]) }</Text>
<Text>{ LocalizeText('catalog.marketplace.offer_count', [ 'count' ], [ offerData.offerCount.toString() ]) }</Text>
</> }
</Column>
<Column gap={ 1 }>

View File

@ -1,8 +1,8 @@
import { CancelMarketplaceOfferMessageComposer, GetMarketplaceOwnOffersMessageComposer, MarketplaceCancelOfferResultEvent, MarketplaceOwnOffersEvent, RedeemMarketplaceOfferCreditsMessageComposer } from '@nitrots/nitro-renderer';
import { FC, useCallback, useMemo, useState } from 'react';
import { FC, useCallback, useEffect, useMemo, useState } from 'react';
import { LocalizeText, NotificationAlertType, NotificationUtilities, SendMessageComposer } from '../../../../../../api';
import { Button, Column, Text } from '../../../../../../common';
import { BatchUpdates, UseMessageEventHook, UseMountEffect } from '../../../../../../hooks';
import { UseMessageEventHook } from '../../../../../../hooks';
import { CatalogLayoutProps } from '../CatalogLayout.types';
import { CatalogLayoutMarketplaceItemView, OWN_OFFER } from './CatalogLayoutMarketplaceItemView';
import { MarketplaceOfferData } from './common/MarketplaceOfferData';
@ -28,11 +28,8 @@ export const CatalogLayoutMarketplaceOwnItemsView: FC<CatalogLayoutProps> = prop
return newOffer;
});
BatchUpdates(() =>
{
setCreditsWaiting(parser.creditsWaiting);
setOffers(offers);
});
}, []);
UseMessageEventHook(MarketplaceOwnOffersEvent, onMarketPlaceOwnOffersEvent);
@ -77,10 +74,10 @@ export const CatalogLayoutMarketplaceOwnItemsView: FC<CatalogLayoutProps> = prop
SendMessageComposer(new CancelMarketplaceOfferMessageComposer(offerData.offerId));
};
UseMountEffect(() =>
useEffect(() =>
{
SendMessageComposer(new GetMarketplaceOwnOffersMessageComposer());
});
}, []);
return (
<Column overflow="hidden">
@ -91,7 +88,7 @@ export const CatalogLayoutMarketplaceOwnItemsView: FC<CatalogLayoutProps> = prop
{ (creditsWaiting > 0) &&
<Column center gap={ 1 } className="bg-muted rounded p-2">
<Text>
{ LocalizeText('catalog.marketplace.redeem.get_credits', ['count', 'credits'], [ soldOffers.length.toString(), creditsWaiting.toString() ]) }
{ LocalizeText('catalog.marketplace.redeem.get_credits', [ 'count', 'credits' ], [ soldOffers.length.toString(), creditsWaiting.toString() ]) }
</Text>
<Button className="mt-1" onClick={ redeemSoldOffers }>
{ LocalizeText('catalog.marketplace.offer.redeem') }

View File

@ -2,7 +2,7 @@ import { BuyMarketplaceOfferMessageComposer, GetMarketplaceOffersMessageComposer
import { FC, useCallback, useMemo, useState } from 'react';
import { LocalizeText, NotificationAlertType, NotificationUtilities, SendMessageComposer } from '../../../../../../api';
import { Button, ButtonGroup, Column, Text } from '../../../../../../common';
import { BatchUpdates, UseMessageEventHook } from '../../../../../../hooks';
import { UseMessageEventHook } from '../../../../../../hooks';
import { GetCurrencyAmount } from '../../../../../purse/common/CurrencyHelper';
import { CatalogLayoutProps } from '../CatalogLayout.types';
import { CatalogLayoutMarketplaceItemView, PUBLIC_OFFER } from './CatalogLayoutMarketplaceItemView';
@ -11,9 +11,9 @@ import { IMarketplaceSearchOptions } from './common/IMarketplaceSearchOptions';
import { MarketplaceOfferData } from './common/MarketplaceOfferData';
import { MarketplaceSearchType } from './common/MarketplaceSearchType';
const SORT_TYPES_VALUE = [1, 2];
const SORT_TYPES_ACTIVITY = [3, 4, 5, 6];
const SORT_TYPES_ADVANCED = [1, 2, 3, 4, 5, 6];
const SORT_TYPES_VALUE = [ 1, 2 ];
const SORT_TYPES_ACTIVITY = [ 3, 4, 5, 6 ];
const SORT_TYPES_ADVANCED = [ 1, 2, 3, 4, 5, 6 ];
export interface CatalogLayoutMarketplacePublicItemsViewProps extends CatalogLayoutProps
{
@ -44,7 +44,7 @@ export const CatalogLayoutMarketplacePublicItemsView: FC<CatalogLayoutMarketplac
return SORT_TYPES_ADVANCED;
}
return [];
}, [searchType]);
}, [ searchType ]);
const purchaseItem = useCallback((offerData: MarketplaceOfferData) =>
{
@ -75,12 +75,8 @@ export const CatalogLayoutMarketplacePublicItemsView: FC<CatalogLayoutMarketplac
latestOffers.set(entry.offerId, offerEntry);
});
BatchUpdates(() =>
{
setTotalItemsFound(parser.totalItemsFound);
setOffers(latestOffers);
});
}, []);
const onMarketplaceBuyOfferResultEvent = useCallback( (event: MarketplaceBuyOfferResultEvent) =>
@ -124,7 +120,7 @@ export const CatalogLayoutMarketplacePublicItemsView: FC<CatalogLayoutMarketplac
});
NotificationUtilities.confirm(LocalizeText('catalog.marketplace.confirm_higher_header') +
'\n' + LocalizeText('catalog.marketplace.confirm_price', ['price'], [parser.newPrice.toString()]), () =>
'\n' + LocalizeText('catalog.marketplace.confirm_price', [ 'price' ], [ parser.newPrice.toString() ]), () =>
{
SendMessageComposer(new BuyMarketplaceOfferMessageComposer(parser.offerId));
},
@ -134,7 +130,7 @@ export const CatalogLayoutMarketplacePublicItemsView: FC<CatalogLayoutMarketplac
NotificationUtilities.simpleAlert(LocalizeText('catalog.alert.notenough.credits.description'), NotificationAlertType.DEFAULT, null, null, LocalizeText('catalog.alert.notenough.title'));
break;
}
}, [lastSearch, requestOffers]);
}, [ lastSearch, requestOffers ]);
UseMessageEventHook(MarketPlaceOffersEvent, onMarketPlaceOffersEvent);
UseMessageEventHook(MarketplaceBuyOfferResultEvent, onMarketplaceBuyOfferResultEvent);

View File

@ -46,7 +46,7 @@ export const SearchFormView: FC<SearchFormViewProps> = props =>
setSortType(sortType);
if(searchType === MarketplaceSearchType.BY_ACTIVITY || MarketplaceSearchType.BY_VALUE === searchType) onSearch({ minPrice: -1, maxPrice: -1, query: '', type: sortType });
}, [onSearch, searchType, sortTypes]);
}, [ onSearch, searchType, sortTypes ]);
return (
<Column gap={ 1 }>

View File

@ -64,7 +64,10 @@ export const MarketplacePostOfferView : FC<{}> = props =>
SendMessageComposer(new MakeOfferMessageComposer(askingPrice, item.isWallItem ? 2 : 1, item.id));
setItem(null);
},
() => { setItem(null) }, null, null, LocalizeText('inventory.marketplace.confirm_offer.title'));
() =>
{
setItem(null)
}, null, null, LocalizeText('inventory.marketplace.confirm_offer.title'));
}
return (
@ -82,7 +85,7 @@ export const MarketplacePostOfferView : FC<{}> = props =>
</Column>
<Column overflow="auto">
<Text italics>
{ LocalizeText('inventory.marketplace.make_offer.expiration_info', ['time'], [marketplaceConfiguration.offerTime.toString()]) }
{ LocalizeText('inventory.marketplace.make_offer.expiration_info', [ 'time' ], [ marketplaceConfiguration.offerTime.toString() ]) }
</Text>
<div className="input-group has-validation">
<input className="form-control form-control-sm" type="number" min={ 0 } value={ askingPrice } onChange={ event => setAskingPrice(parseInt(event.target.value)) } placeholder={ LocalizeText('inventory.marketplace.make_offer.price_request') } />

View File

@ -4,7 +4,7 @@ import { FC, useCallback, useEffect, useMemo, useState } from 'react';
import { LocalizeText, SendMessageComposer } from '../../../../../../api';
import { AutoGrid, Base, Button, Column, Flex, Grid, LayoutGridItem, LayoutPetImageView, Text } from '../../../../../../common';
import { CatalogNameResultEvent, CatalogPurchaseFailureEvent, CatalogWidgetEvent } from '../../../../../../events';
import { BatchUpdates, DispatchUiEvent, UseUiEvent } from '../../../../../../hooks';
import { DispatchUiEvent, UseUiEvent } from '../../../../../../hooks';
import { useCatalogContext } from '../../../../CatalogContext';
import { GetPetAvailableColors, GetPetIndexFromLocalization } from '../../../../common/CatalogUtilities';
import { CatalogAddOnBadgeWidgetView } from '../../widgets/CatalogAddOnBadgeWidgetView';
@ -122,12 +122,9 @@ export const CatalogLayoutPetView: FC<CatalogLayoutProps> = props =>
const offer = page.offers[0];
BatchUpdates(() =>
{
setCurrentOffer(offer);
setPetIndex(GetPetIndexFromLocalization(offer.localizationId));
setColorsShowing(false);
});
}, [ page, setCurrentOffer ]);
useEffect(() =>
@ -153,21 +150,15 @@ export const CatalogLayoutPetView: FC<CatalogLayoutProps> = props =>
palettes.push(palette);
}
BatchUpdates(() =>
{
setSelectedPaletteIndex((palettes.length ? 0 : -1));
setSellablePalettes(palettes);
});
return;
}
}
BatchUpdates(() =>
{
setSelectedPaletteIndex(-1);
setSellablePalettes([]);
});
SendMessageComposer(new GetSellablePetPalettesComposer(productData.type));
}, [ currentOffer, petPalettes ]);
@ -178,11 +169,8 @@ export const CatalogLayoutPetView: FC<CatalogLayoutProps> = props =>
const colors = GetPetAvailableColors(petIndex, sellablePalettes);
BatchUpdates(() =>
{
setSelectedColorIndex((colors.length ? 0 : -1));
setSellableColors(colors);
});
}, [ petIndex, sellablePalettes ]);
useEffect(() =>

View File

@ -21,7 +21,7 @@ export const VipGiftItem : FC<VipGiftItemViewProps> = props =>
const productData = offer.products[0];
return ProductImageUtility.getProductImageUrl(productData.productType, productData.furniClassId, productData.extraParam);
}, [offer]);
}, [ offer ]);
const getItemTitle = useCallback(() =>
{
@ -32,7 +32,7 @@ export const VipGiftItem : FC<VipGiftItemViewProps> = props =>
const localizationKey = ProductImageUtility.getProductCategory(productData.productType, productData.furniClassId) === 2 ? 'wallItem.name.' + productData.furniClassId : 'roomItem.name.' + productData.furniClassId;
return LocalizeText(localizationKey);
}, [offer]);
}, [ offer ]);
const getItemDesc = useCallback( () =>
{
@ -43,7 +43,7 @@ export const VipGiftItem : FC<VipGiftItemViewProps> = props =>
const localizationKey = ProductImageUtility.getProductCategory(productData.productType, productData.furniClassId) === 2 ? 'wallItem.desc.' + productData.furniClassId : 'roomItem.desc.' + productData.furniClassId ;
return LocalizeText(localizationKey);
}, [offer]);
}, [ offer ]);
return (
<LayoutGridItem center={ false } column={ false } alignItems="center" className="p-1">

View File

@ -14,9 +14,10 @@ interface CatalogBadgeSelectorWidgetViewProps extends AutoGridProps
export const CatalogBadgeSelectorWidgetView: FC<CatalogBadgeSelectorWidgetViewProps> = props =>
{
const { columnCount = 5, ...rest } = props;
const [ isVisible, setIsVisible ] = useState(false);
const [ currentBadgeCode, setCurrentBadgeCode ] = useState<string>(null);
const { currentOffer = null, setPurchaseOptions = null } = useCatalogContext();
const { badgeCodes = [] } = useInventoryBadges();
const { badgeCodes = [], activate = null, deactivate = null } = useInventoryBadges();
const previewStuffData = useMemo(() =>
{
@ -45,6 +46,22 @@ export const CatalogBadgeSelectorWidgetView: FC<CatalogBadgeSelectorWidgetViewPr
});
}, [ currentOffer, previewStuffData, setPurchaseOptions ]);
useEffect(() =>
{
if(!isVisible) return;
const id = activate();
return () => deactivate(id);
}, [ isVisible, activate, deactivate ]);
useEffect(() =>
{
setIsVisible(true);
return () => setIsVisible(false);
}, []);
return (
<AutoGrid columnCount={ columnCount } { ...rest }>
{ badgeCodes && (badgeCodes.length > 0) && badgeCodes.map((badgeCode, index) =>

View File

@ -1,7 +1,6 @@
import { FC, useEffect, useState } from 'react';
import { LocalizeText, ProductTypeEnum } from '../../../../../api';
import { AutoGrid, AutoGridProps, Button, ButtonGroup } from '../../../../../common';
import { BatchUpdates } from '../../../../../hooks';
import { useCatalogContext } from '../../../CatalogContext';
import { IPurchasableOffer } from '../../../common/IPurchasableOffer';
import { Offer } from '../../../common/Offer';
@ -52,12 +51,9 @@ export const CatalogSpacesWidgetView: FC<CatalogSpacesWidgetViewProps> = props =
}
}
BatchUpdates(() =>
{
setGroupedOffers(groupedOffers);
setSelectedGroupIndex(0);
setSelectedOfferForGroup([ groupedOffers[0][0], groupedOffers[1][0], groupedOffers[2][0] ]);
});
}, [ currentPage ]);
useEffect(() =>

View File

@ -15,7 +15,7 @@ export const ChatHistoryMessageHandler: FC<{}> = props =>
{
const { chatHistoryState = null, roomHistoryState = null } = useChatHistoryContext();
const [needsRoomInsert, setNeedsRoomInsert ] = useState(false);
const [ needsRoomInsert, setNeedsRoomInsert ] = useState(false);
const addChatEntry = useCallback((entry: IChatEntry) =>
{
@ -32,7 +32,7 @@ export const ChatHistoryMessageHandler: FC<{}> = props =>
//dispatchUiEvent(new ChatHistoryEvent(ChatHistoryEvent.CHAT_HISTORY_CHANGED));
}, [chatHistoryState]);
}, [ chatHistoryState ]);
const addRoomHistoryEntry = useCallback((entry: IRoomHistoryEntry) =>
{
@ -45,7 +45,7 @@ export const ChatHistoryMessageHandler: FC<{}> = props =>
}
roomHistoryState.notify();
}, [roomHistoryState]);
}, [ roomHistoryState ]);
const onChatEvent = useCallback((event: RoomSessionChatEvent) =>
{
@ -62,7 +62,7 @@ export const ChatHistoryMessageHandler: FC<{}> = props =>
const entry: IChatEntry = { id: -1, entityId: userData.webID, name: userData.name, look: userData.figure, entityType: userData.type, message: event.message, timestamp: timeString, type: ChatEntryType.TYPE_CHAT, roomId: roomSession.roomId };
addChatEntry(entry);
}, [addChatEntry]);
}, [ addChatEntry ]);
UseRoomSessionManagerEvent(RoomSessionChatEvent.CHAT_EVENT, onChatEvent);
@ -104,7 +104,7 @@ export const ChatHistoryMessageHandler: FC<{}> = props =>
setNeedsRoomInsert(false);
}
}, [addChatEntry, addRoomHistoryEntry, needsRoomInsert]);
}, [ addChatEntry, addRoomHistoryEntry, needsRoomInsert ]);
UseMessageEventHook(GetGuestRoomResultEvent, onGetGuestRoomResultEvent);

View File

@ -3,7 +3,6 @@ import { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { AutoSizer, CellMeasurer, CellMeasurerCache, List, ListRowProps, ListRowRenderer, Size } from 'react-virtualized';
import { AddEventLinkTracker, LocalizeText, RemoveLinkEventTracker } from '../../api';
import { Flex, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../common';
import { BatchUpdates } from '../../hooks';
import { ChatHistoryContextProvider } from './ChatHistoryContext';
import { ChatHistoryMessageHandler } from './ChatHistoryMessageHandler';
import { ChatEntryType } from './common/ChatEntryType';
@ -91,11 +90,8 @@ export const ChatHistoryView: FC<{}> = props =>
chatState.notifier = () => setChatHistoryUpdateId(prevValue => (prevValue + 1));
roomState.notifier = () => setRoomHistoryUpdateId(prevValue => (prevValue + 1));
BatchUpdates(() =>
{
setChatHistoryState(chatState);
setRoomHistoryState(roomState);
});
return () =>
{

View File

@ -20,7 +20,7 @@ export const FloorplanEditorView: FC<{}> = props =>
const [ originalFloorplanSettings, setOriginalFloorplanSettings ] = useState<IFloorplanSettings>({
tilemap: '',
reservedTiles: [],
entryPoint: [0, 0],
entryPoint: [ 0, 0 ],
entryPointDir: 2,
wallHeight: -1,
thicknessWall: 1,

View File

@ -151,7 +151,7 @@ export class FloorplanEditor extends PixiApplicationProxy
{
if(this._isHolding)
{
const [realX, realY] = getTileFromScreenPosition(tileStartX, tileStartY);
const [ realX, realY ] = getTileFromScreenPosition(tileStartX, tileStartY);
if(isClick)
{
@ -246,7 +246,7 @@ export class FloorplanEditor extends PixiApplicationProxy
if(tile.isBlocked) assetName = FloorplanEditor.TILE_BLOCKED;
//if((tile.height === 'x') || tile.height === 'X') continue;
const [positionX, positionY] = getScreenPositionForTile(x, y);
const [ positionX, positionY ] = getScreenPositionForTile(x, y);
this._tilemapRenderer.tile(this._assetCollection.getTexture(`floor_editor_${ assetName }`), positionX, positionY);
}

View File

@ -7,7 +7,7 @@ export const getScreenPositionForTile = (x: number, y: number): [number , number
positionX = positionX + 1024; // center the map in the canvas
return [positionX, positionY];
return [ positionX, positionY ];
}
export const getTileFromScreenPosition = (x: number, y: number): [number, number] =>
@ -17,7 +17,7 @@ export const getTileFromScreenPosition = (x: number, y: number): [number, number
const realX = ((translatedX /(TILE_SIZE / 2)) + (y / (TILE_SIZE / 4))) / 2;
const realY = ((y /(TILE_SIZE / 4)) - (translatedX / (TILE_SIZE / 2))) / 2;
return [realX, realY];
return [ realX, realY ];
}
export const convertNumbersForSaving = (value: number): number =>

View File

@ -2,7 +2,7 @@ import { HabboSearchComposer, HabboSearchResultData, HabboSearchResultEvent } fr
import { FC, useCallback, useEffect, useState } from 'react';
import { LocalizeText, OpenMessengerChat, SendMessageComposer } from '../../../../api';
import { Base, Column, Flex, NitroCardAccordionItemView, NitroCardAccordionSetView, NitroCardAccordionSetViewProps, Text, UserProfileIconView } from '../../../../common';
import { BatchUpdates, useFriends, UseMessageEventHook } from '../../../../hooks';
import { useFriends, UseMessageEventHook } from '../../../../hooks';
interface FriendsSearchViewProps extends NitroCardAccordionSetViewProps
{
@ -21,11 +21,8 @@ export const FriendsSearchView: FC<FriendsSearchViewProps> = props =>
{
const parser = event.getParser();
BatchUpdates(() =>
{
setFriendResults(parser.friends);
setOtherResults(parser.others);
});
}, []);
UseMessageEventHook(HabboSearchResultEvent, onHabboSearchResultEvent);

View File

@ -35,7 +35,7 @@ export const FriendsListView: FC<{}> = props =>
}
return LocalizeText('friendlist.removefriendconfirm.userlist', [ 'user_names' ], [ userNames.join(', ') ]);
}, [offlineFriends, onlineFriends, selectedFriendsIds]);
}, [ offlineFriends, onlineFriends, selectedFriendsIds ]);
const selectFriend = useCallback((userId: number) =>
{

View File

@ -0,0 +1,84 @@
import { FC, useMemo } from 'react';
import { GetSessionDataManager, LocalizeText } from '../../../../api';
import { Base, Flex, LayoutAvatarImageView } from '../../../../common';
import { GroupType } from '../../common/GroupType';
import { MessengerThread } from '../../common/MessengerThread';
import { MessengerThreadChat } from '../../common/MessengerThreadChat';
import { MessengerThreadChatGroup } from '../../common/MessengerThreadChatGroup';
import { getGroupChatData } from '../../common/Utils';
interface FriendsMessengerThreadGroupProps
{
thread: MessengerThread;
group: MessengerThreadChatGroup;
}
export const FriendsMessengerThreadGroup: FC<FriendsMessengerThreadGroupProps> = props =>
{
const { thread = null, group = null } = props;
const isOwnChat = useMemo(() =>
{
if(!thread || !group) return false;
if(group.type === GroupType.PRIVATE_CHAT && (group.userId === GetSessionDataManager().userId)) return true;
if( (group.type === GroupType.GROUP_CHAT) && (group.chats.length && getGroupChatData(group.chats[0].extraData).userId === GetSessionDataManager().userId)) return true;
return false;
}, [ group, thread ]);
if(!thread || !group) return null;
if(!group.userId)
{
return (
<>
{ group.chats.map((chat, index) =>
{
return (
<div key={ index } className="d-flex gap-2 w-100 justify-content-start">
<Base className="w-100 text-break">
{ chat.type === MessengerThreadChat.SECURITY_NOTIFICATION &&
<Base className="bg-light rounded mb-2 d-flex gap-2 px-2 py-1 small text-muted align-items-center">
<Base className="nitro-friends-spritesheet icon-warning flex-shrink-0" />
<Base>{ chat.message }</Base>
</Base> }
{ chat.type === MessengerThreadChat.ROOM_INVITE &&
<Base className="bg-light rounded mb-2 d-flex gap-2 px-2 py-1 small text-black align-items-center">
<Base className="messenger-notification-icon flex-shrink-0" />
<Base>{(LocalizeText('messenger.invitation') + ' ') }{ chat.message }</Base>
</Base> }
</Base>
</div>
);
}) }
</>
);
}
return (
<Flex className={ 'w-100 justify-content-' + (isOwnChat ? 'end' : 'start') } gap={ 2 }>
<Base className="message-avatar flex-shrink-0">
{ (group.type === GroupType.PRIVATE_CHAT && !isOwnChat) &&
<LayoutAvatarImageView figure={ thread.participant.figure } direction={ 2 } />
}
{ (group.type === GroupType.GROUP_CHAT && !isOwnChat) &&
<LayoutAvatarImageView figure={ getGroupChatData(group.chats[0].extraData).figure } direction={ 2} />
}
</Base>
<Base className={ 'bg-light text-black border-radius mb-2 rounded py-1 px-2 messages-group-' + (isOwnChat ? 'right' : 'left') }>
<Base className='fw-bold'>
{ (isOwnChat) && GetSessionDataManager().userName }
{ (!isOwnChat) && ((group.type === GroupType.GROUP_CHAT) ? getGroupChatData(group.chats[0].extraData).username : thread.participant.name)
}
</Base>
{ group.chats.map((chat, index) =><Base key={ index } className="text-break">{ chat.message }</Base>) }
</Base>
{ (isOwnChat) &&
<Base className="message-avatar flex-shrink-0">
<LayoutAvatarImageView figure={ GetSessionDataManager().figure } direction={ 4 } />
</Base> }
</Flex>
);
}

View File

@ -3,7 +3,7 @@ import { FollowFriendMessageComposer, ILinkEventTracker } from '@nitrots/nitro-r
import { FC, KeyboardEvent, useEffect, useRef, useState } from 'react';
import { AddEventLinkTracker, GetUserProfile, LocalizeText, RemoveLinkEventTracker, SendMessageComposer } from '../../../../api';
import { Base, Button, ButtonGroup, Column, Flex, Grid, LayoutAvatarImageView, LayoutBadgeImageView, LayoutGridItem, LayoutItemCountView, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../../common';
import { BatchUpdates, useMessenger } from '../../../../hooks';
import { useMessenger } from '../../../../hooks';
import { FriendsMessengerThreadView } from './FriendsMessengerThreadView';
export const FriendsMessengerView: FC<{}> = props =>
@ -54,11 +54,8 @@ export const FriendsMessengerView: FC<{}> = props =>
if(!thread) return;
BatchUpdates(() =>
{
setActiveThread(thread);
setIsVisible(true);
});
}
}
},

View File

@ -2,7 +2,7 @@ import { GroupBuyComposer, GroupBuyDataComposer, GroupBuyDataEvent } from '@nitr
import { FC, useCallback, useEffect, useState } from 'react';
import { HasHabboClub, LocalizeText, SendMessageComposer } from '../../../api';
import { Base, Button, Column, Flex, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../common';
import { BatchUpdates, UseMessageEventHook } from '../../../hooks';
import { UseMessageEventHook } from '../../../hooks';
import { IGroupData } from '../common/IGroupData';
import { GroupTabBadgeView } from './tabs/GroupTabBadgeView';
import { GroupTabColorsView } from './tabs/GroupTabColorsView';
@ -94,18 +94,13 @@ export const GroupCreatorView: FC<GroupCreatorViewProps> = props =>
parser.availableRooms.forEach((name, id) => rooms.push({ id, name }));
BatchUpdates(() =>
{
setAvailableRooms(rooms);
setPurchaseCost(parser.groupCost);
});
}, []);
UseMessageEventHook(GroupBuyDataEvent, onGroupBuyDataEvent);
useEffect(() =>
{
BatchUpdates(() =>
{
setCurrentTab(1);
@ -119,7 +114,6 @@ export const GroupCreatorView: FC<GroupCreatorViewProps> = props =>
groupColors: null,
groupBadgeParts: null
});
});
SendMessageComposer(new GroupBuyDataComposer());
}, [ setGroupData ]);

View File

@ -126,7 +126,7 @@ export const GroupInformationView: FC<GroupInformationViewProps> = props =>
<i className="icon icon-group-decorate" title={ LocalizeText('group.memberscandecorate') } /> }
</Flex>
</Flex>
<Text small>{ LocalizeText('group.created', ['date', 'owner'], [groupInformation.createdAt, groupInformation.ownerName]) }</Text>
<Text small>{ LocalizeText('group.created', [ 'date', 'owner' ], [ groupInformation.createdAt, groupInformation.ownerName ]) }</Text>
</Column>
<Text small overflow="auto" className="group-description">{ groupInformation.description }</Text>
</Column>

View File

@ -3,7 +3,7 @@ import { GroupAdminGiveComposer, GroupAdminTakeComposer, GroupConfirmMemberRemov
import { FC, useCallback, useEffect, useState } from 'react';
import { AddEventLinkTracker, GetSessionDataManager, GetUserProfile, LocalizeText, NotificationUtilities, RemoveLinkEventTracker, SendMessageComposer } from '../../../api';
import { Base, Button, Column, Flex, Grid, LayoutAvatarImageView, LayoutBadgeImageView, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../common';
import { BatchUpdates, UseMessageEventHook } from '../../../hooks';
import { UseMessageEventHook } from '../../../hooks';
export const GroupMembersView: FC<{}> = props =>
{
@ -76,12 +76,9 @@ export const GroupMembersView: FC<{}> = props =>
{
const parser = event.getParser();
BatchUpdates(() =>
{
setMembersData(parser);
setLevelId(parser.level);
setTotalPages(Math.ceil(parser.totalMembersCount / parser.pageSize));
});
}, []);
UseMessageEventHook(GroupMembersEvent, onGroupMembersEvent);
@ -111,11 +108,8 @@ export const GroupMembersView: FC<{}> = props =>
const groupId = (parseInt(parts[1]) || -1);
const levelId = (parseInt(parts[2]) || 3);
BatchUpdates(() =>
{
setGroupId(groupId);
setLevelId(levelId);
});
}, []);
useEffect(() =>
@ -146,21 +140,18 @@ export const GroupMembersView: FC<{}> = props =>
{
if(groupId === -1) return;
BatchUpdates(() =>
{
setLevelId(-1);
setMembersData(null);
setTotalPages(0);
setSearchQuery('');
setRemovingMemberName(null);
})
}, [ groupId ]);
if((groupId === -1) || !membersData) return null;
return (
<NitroCardView className="nitro-group-members" theme="primary-slim">
<NitroCardHeaderView headerText={ LocalizeText('group.members.title', ['groupName'], [ membersData ? membersData.groupTitle : '' ]) } onCloseClick={ event => setGroupId(-1) } />
<NitroCardHeaderView headerText={ LocalizeText('group.members.title', [ 'groupName' ], [ membersData ? membersData.groupTitle : '' ]) } onCloseClick={ event => setGroupId(-1) } />
<NitroCardContentView overflow="hidden">
<Flex gap={ 2 }>
<Flex center className="group-badge">
@ -211,7 +202,7 @@ export const GroupMembersView: FC<{}> = props =>
<FontAwesomeIcon icon="chevron-left" />
</Button>
<Text small>
{ LocalizeText('group.members.pageinfo', ['amount', 'page', 'totalPages'], [membersData.totalMembersCount.toString(), (membersData.pageIndex + 1).toString(), totalPages.toString()]) }
{ LocalizeText('group.members.pageinfo', [ 'amount', 'page', 'totalPages' ], [ membersData.totalMembersCount.toString(), (membersData.pageIndex + 1).toString(), totalPages.toString() ]) }
</Text>
<Button disabled={ (membersData.pageIndex === (totalPages - 1)) } onClick={ event => setPageId(prevValue => (prevValue + 1)) }>
<FontAwesomeIcon icon="chevron-right" />

View File

@ -2,7 +2,6 @@ import { GroupDeleteComposer, GroupSaveInformationComposer } from '@nitrots/nitr
import { Dispatch, FC, SetStateAction, useCallback, useEffect, useState } from 'react';
import { CreateLinkEvent, LocalizeText, NotificationUtilities, SendMessageComposer } from '../../../../api';
import { Base, Button, Column, Flex, Text } from '../../../../common';
import { BatchUpdates } from '../../../../hooks';
import { IGroupData } from '../../common/IGroupData';
interface GroupTabIdentityViewProps
@ -64,13 +63,10 @@ export const GroupTabIdentityView: FC<GroupTabIdentityViewProps> = props =>
}, [ groupData, groupName, groupDescription, groupHomeroomId, setGroupData ]);
useEffect(() =>
{
BatchUpdates(() =>
{
setGroupName(groupData.groupName || '');
setGroupDescription(groupData.groupDescription || '');
setGroupHomeroomId(groupData.groupHomeroomId);
});
}, [ groupData ]);
useEffect(() =>

View File

@ -3,7 +3,6 @@ import { Dispatch, FC, SetStateAction, useCallback, useEffect, useState } from '
import { SendMessageComposer } from '../../../../api';
import { LocalizeText } from '../../../../api/utils/LocalizeText';
import { Column, Flex, HorizontalRule, Text } from '../../../../common';
import { BatchUpdates } from '../../../../hooks';
import { IGroupData } from '../../common/IGroupData';
const STATES: string[] = [ 'regular', 'exclusive', 'private' ];
@ -48,12 +47,9 @@ export const GroupTabSettingsView: FC<GroupTabSettingsViewProps> = props =>
}, [ groupData, groupState, groupDecorate, setGroupData ]);
useEffect(() =>
{
BatchUpdates(() =>
{
setGroupState(groupData.groupState);
setGroupDecorate(groupData.groupCanMembersDecorate);
});
}, [ groupData ]);
useEffect(() =>

View File

@ -55,7 +55,7 @@ export const GuideToolView: FC<{}> = props =>
setNoCloseButton(true);
break;
case GuideSessionState.GUIDE_ONGOING:
setHeaderText(LocalizeText('guide.help.request.guide.ongoing.title', ['name'], [replacement]));
setHeaderText(LocalizeText('guide.help.request.guide.ongoing.title', [ 'name' ], [ replacement ]));
setNoCloseButton(true);
break;
case GuideSessionState.USER_CREATE:
@ -67,7 +67,7 @@ export const GuideToolView: FC<{}> = props =>
setNoCloseButton(true);
break;
case GuideSessionState.USER_ONGOING:
setHeaderText(LocalizeText('guide.help.request.user.ongoing.title', ['name'], [replacement]));
setHeaderText(LocalizeText('guide.help.request.user.ongoing.title', [ 'name' ], [ replacement ]));
setNoCloseButton(true);
break;
case GuideSessionState.USER_FEEDBACK:
@ -183,7 +183,7 @@ export const GuideToolView: FC<{}> = props =>
{
const parser = event.getParser();
const messageGroups = [...ongoingMessageGroups];
const messageGroups = [ ...ongoingMessageGroups ];
let lastGroup = messageGroups[messageGroups.length - 1];
@ -203,7 +203,7 @@ export const GuideToolView: FC<{}> = props =>
{
const parser = event.getParser();
const messageGroups = [...ongoingMessageGroups];
const messageGroups = [ ...ongoingMessageGroups ];
let lastGroup = messageGroups[messageGroups.length - 1];
@ -217,7 +217,7 @@ export const GuideToolView: FC<{}> = props =>
lastGroup.addChat(new GuideToolMessage(parser.roomName, parser.roomId));
setOngoingMessageGroups(messageGroups);
}, [isOnDuty, ongoingMessageGroups, ongoingUserId]);
}, [ isOnDuty, ongoingMessageGroups, ongoingUserId ]);
UseMessageEventHook(GuideSessionInvitedToGuideRoomMessageEvent, onGuideSessionInvitedToGuideRoomMessageEvent);
@ -299,7 +299,7 @@ export const GuideToolView: FC<{}> = props =>
case 'toggle_duty':
if(!isHandlingBullyReports && !isHandlingGuideRequests && !isHandlingHelpRequests)
{
DispatchUiEvent(new NotificationAlertEvent([LocalizeText('guide.help.guide.tool.noqueueselected.message')], null, null, null, LocalizeText('guide.help.guide.tool.noqueueselected.caption'), null));
DispatchUiEvent(new NotificationAlertEvent([ LocalizeText('guide.help.guide.tool.noqueueselected.message') ], null, null, null, LocalizeText('guide.help.guide.tool.noqueueselected.caption'), null));
return;
}
@ -315,7 +315,7 @@ export const GuideToolView: FC<{}> = props =>
window.open(url);
return;
}
}, [isHandlingBullyReports, isHandlingGuideRequests, isHandlingHelpRequests]);
}, [ isHandlingBullyReports, isHandlingGuideRequests, isHandlingHelpRequests ]);
if(!isVisible) return null;

View File

@ -85,7 +85,7 @@ export const GuideToolOngoingView: FC<GuideToolOngoingViewProps> = props =>
{ messageGroups.map((group, index) =>
{
return (
<Flex fullWidth justifyContent={ isOwnChat(group.userId) ? 'end' : 'start' } gap={ 2 }>
<Flex key={ index } fullWidth justifyContent={ isOwnChat(group.userId) ? 'end' : 'start' } gap={ 2 }>
<Base shrink className="message-avatar">
{ (!isOwnChat(group.userId)) &&
<LayoutAvatarImageView figure={ userFigure } direction={ 2 } /> }

View File

@ -90,7 +90,7 @@ export const HcCenterView: FC<{}> = props =>
setIsVisible(!isVisible);
break;
}
}, [isVisible]);
}, [ isVisible ]);
UseUiEvent(HcCenterEvent.TOGGLE_HC_CENTER, onHcCenterEvent);
@ -169,7 +169,7 @@ export const HcCenterView: FC<{}> = props =>
AddEventLinkTracker(linkTracker);
return () => RemoveLinkEventTracker(linkTracker);
}, [ linkReceived]);
}, [ linkReceived ]);
useEffect(() =>
{
@ -201,13 +201,16 @@ export const HcCenterView: FC<{}> = props =>
<Popover id="popover-basic">
<Popover.Body className="text-black py-2 px-3">
<h5>{LocalizeText('hccenter.breakdown.title')}</h5>
<div>{LocalizeText('hccenter.breakdown.creditsspent', ['credits'], [kickbackData.totalCreditsSpent.toString()])}</div>
<div>{LocalizeText('hccenter.breakdown.paydayfactor.percent', ['percent'], [(kickbackData.kickbackPercentage * 100).toString()])}</div>
<div>{LocalizeText('hccenter.breakdown.streakbonus', ['credits'], [kickbackData.creditRewardForStreakBonus.toString()])}</div>
<div>{LocalizeText('hccenter.breakdown.creditsspent', [ 'credits' ], [ kickbackData.totalCreditsSpent.toString() ])}</div>
<div>{LocalizeText('hccenter.breakdown.paydayfactor.percent', [ 'percent' ], [ (kickbackData.kickbackPercentage * 100).toString() ])}</div>
<div>{LocalizeText('hccenter.breakdown.streakbonus', [ 'credits' ], [ kickbackData.creditRewardForStreakBonus.toString() ])}</div>
<hr className="w-100 text-black my-1" />
<div>{LocalizeText('hccenter.breakdown.total', ['credits', 'actual'], [getHcPaydayAmount(),
((((kickbackData.kickbackPercentage * kickbackData.totalCreditsSpent) + kickbackData.creditRewardForStreakBonus) * 100) / 100).toString()])}</div>
<div className="btn btn-link text-primary p-0" onClick={() => { CreateLinkEvent('habbopages/' + GetConfiguration('hc.center')['payday.habbopage']) }}>{
<div>{LocalizeText('hccenter.breakdown.total', [ 'credits', 'actual' ], [ getHcPaydayAmount(),
((((kickbackData.kickbackPercentage * kickbackData.totalCreditsSpent) + kickbackData.creditRewardForStreakBonus) * 100) / 100).toString() ])}</div>
<div className="btn btn-link text-primary p-0" onClick={() =>
{
CreateLinkEvent('habbopages/' + GetConfiguration('hc.center')['payday.habbopage'])
}}>{
LocalizeText('hccenter.special.infolink')}
</div>
</Popover.Body>
@ -221,7 +224,10 @@ export const HcCenterView: FC<{}> = props =>
<Column gap={ 1 }>
<div className="hc-logo" />
<Flex>
<Button variant="success" onClick={ event => { CreateLinkEvent('catalog/open/' + GetConfiguration('catalog.links')['hc.buy_hc']) } }>
<Button variant="success" onClick={ event =>
{
CreateLinkEvent('catalog/open/' + GetConfiguration('catalog.links')['hc.buy_hc'])
} }>
{ LocalizeText((clubStatus === ClubStatus.ACTIVE) ? 'hccenter.btn.extend' : 'hccenter.btn.buy') }
</Button>
</Flex>
@ -243,7 +249,10 @@ export const HcCenterView: FC<{}> = props =>
<Column className="rounded-start bg-primary p-2 payday-special mb-1">
<h4 className="mb-1">{LocalizeText('hccenter.special.title')}</h4>
<div>{LocalizeText('hccenter.special.info')}</div>
<div className="btn btn-link text-white p-0 mt-auto align-self-baseline" onClick={() => { CreateLinkEvent('habbopages/' + GetConfiguration('hc.center')['payday.habbopage']) }}>{LocalizeText('hccenter.special.infolink')}</div>
<div className="btn btn-link text-white p-0 mt-auto align-self-baseline" onClick={() =>
{
CreateLinkEvent('habbopages/' + GetConfiguration('hc.center')['payday.habbopage'])
}}>{LocalizeText('hccenter.special.infolink')}</div>
</Column>
<div className="payday flex-shrink-0 p-2">
<h5 className="mb-2 ms-2">{LocalizeText('hccenter.special.time.title')}</h5>
@ -271,16 +280,22 @@ export const HcCenterView: FC<{}> = props =>
<div className="rounded bg-success p-2 d-flex flex-row mb-0">
<div>
<h4 className="mb-1">{LocalizeText('hccenter.gift.title')}</h4>
<div dangerouslySetInnerHTML={{ __html: unclaimedGifts > 0 ? LocalizeText('hccenter.unclaimedgifts', ['unclaimedgifts'], [unclaimedGifts.toString()]) : LocalizeText('hccenter.gift.info') }}></div>
<div dangerouslySetInnerHTML={{ __html: unclaimedGifts > 0 ? LocalizeText('hccenter.unclaimedgifts', [ 'unclaimedgifts' ], [ unclaimedGifts.toString() ]) : LocalizeText('hccenter.gift.info') }}></div>
</div>
<button className="btn btn-primary btn-lg align-self-center ms-auto" onClick={() => { CreateLinkEvent('catalog/open/' + GetConfiguration('catalog.links')['hc.hc_gifts']) }}>{LocalizeText(clubStatus === ClubStatus.ACTIVE ? 'hccenter.btn.gifts.redeem' : 'hccenter.btn.gifts.view')}</button>
<button className="btn btn-primary btn-lg align-self-center ms-auto" onClick={() =>
{
CreateLinkEvent('catalog/open/' + GetConfiguration('catalog.links')['hc.hc_gifts'])
}}>{LocalizeText(clubStatus === ClubStatus.ACTIVE ? 'hccenter.btn.gifts.redeem' : 'hccenter.btn.gifts.view')}</button>
</div>
}
{GetConfiguration('hc.center')['benefits.info'] &&
<div className="benefits text-black py-2">
<h5 className="mb-1 text-primary">{LocalizeText('hccenter.general.title')}</h5>
<div className="mb-2" dangerouslySetInnerHTML={{ __html: LocalizeText('hccenter.general.info') }} />
<button className="btn btn-link p-0 text-primary" onClick={() => { CreateLinkEvent('habbopages/' + GetConfiguration('hc.center')['benefits.habbopage']) }}>{LocalizeText('hccenter.general.infolink')}</button>
<button className="btn btn-link p-0 text-primary" onClick={() =>
{
CreateLinkEvent('habbopages/' + GetConfiguration('hc.center')['benefits.habbopage'])
}}>{LocalizeText('hccenter.general.infolink')}</button>
</div>
}
</NitroCardContentView>

View File

@ -2,7 +2,7 @@
export class BadgeResolver
{
public static default_badge: string = 'HC1';
public static badges: string[] = ['ACH_VipHC1', 'ACH_VipHC2', 'ACH_VipHC3', 'ACH_VipHC4', 'ACH_VipHC5', 'HC1', 'HC2', 'HC3', 'HC4', 'HC5'];
public static badges: string[] = [ 'ACH_VipHC1', 'ACH_VipHC2', 'ACH_VipHC3', 'ACH_VipHC4', 'ACH_VipHC5', 'HC1', 'HC2', 'HC3', 'HC4', 'HC5' ];
public static getClubBadge(k: string[]): string

View File

@ -104,7 +104,7 @@ export const HelpView: FC<{}> = props =>
}
return null;
}, [helpReportState.currentStep]);
}, [ helpReportState.currentStep ]);
return (
<HelpContextProvider value={ { helpReportState, setHelpReportState } }>

View File

@ -15,7 +15,7 @@ export const HelpIndexView: FC<{}> = props =>
const reportState = Object.assign({}, helpReportState );
reportState.currentStep = 1;
setHelpReportState(reportState);
},[helpReportState, setHelpReportState]);
},[ helpReportState, setHelpReportState ]);
const onRequestMySanctionStatusClick = useCallback(() =>
{

View File

@ -39,11 +39,11 @@ export const SanctionSatusView:FC<{}> = props =>
if(length > 24)
{
localizationName = (localizationName + '.days');
return LocalizeText(localizationName, ['days'], [(length / 24).toString()]);
return LocalizeText(localizationName, [ 'days' ], [ (length / 24).toString() ]);
}
}
return LocalizeText(localizationName, ['hours'], [length.toString()]);
return LocalizeText(localizationName, [ 'hours' ], [ length.toString() ]);
}, []);
if(!sanctionInfo) return null;

View File

@ -9,7 +9,7 @@ export const NameChangeInitView:FC<NameChangeLayoutViewProps> = props =>
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.main') }</div>
<div className="fw-bold d-flex align-items-center justify-content-center h-100 w-100">{ LocalizeText('tutorial.name_change.current', ['name'], [GetSessionDataManager().userName]) }</div>
<div className="fw-bold d-flex align-items-center justify-content-center h-100 w-100">{ LocalizeText('tutorial.name_change.current', [ 'name' ], [ GetSessionDataManager().userName ]) }</div>
<div className="d-flex gap-2">
<button className="btn btn-success w-100" onClick={ () => onAction('start') }>{ LocalizeText('tutorial.name_change.change') }</button>
<button className="btn btn-primary w-100" onClick={ () => onAction('confirmation', GetSessionDataManager().userName) }>{ LocalizeText('tutorial.name_change.keep') }</button>

View File

@ -83,8 +83,8 @@ export const NameChangeInputView:FC<NameChangeLayoutViewProps> = props =>
<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> }
{ 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) =>

View File

@ -51,7 +51,7 @@ export const NameChangeView:FC<{}> = props =>
case INPUT: return 'tutorial.name_change.title.select';
case CONFIRMATION: return 'tutorial.name_change.title.confirm';
}
}, [layout]);
}, [ layout ]);
if(!isVisible) return null;

View File

@ -2,11 +2,11 @@ import { FigureUpdateEvent, RoomSessionEvent, UserInfoDataParser, UserInfoEvent
import { FC, useCallback, useState } from 'react';
import { GetConfiguration, GetConfigurationManager } from '../../api';
import { LayoutAvatarImageView } from '../../common';
import { BatchUpdates, UseMessageEventHook, UseRoomSessionManagerEvent } from '../../hooks';
import { UseMessageEventHook, UseRoomSessionManagerEvent } from '../../hooks';
import { WidgetSlotView } from './views/widgets/WidgetSlotView';
export const HotelView: FC<{}> = props =>
{
const [isVisible, setIsVisible] = useState(true);
const [ isVisible, setIsVisible ] = useState(true);
const widgetSlotCount = 7;
const [ userFigure, setUserFigure ] = useState<string>(null);
const [ userInfo, setUserInfo ] = useState<UserInfoDataParser>(null);
@ -16,11 +16,8 @@ export const HotelView: FC<{}> = props =>
{
const parser = event.getParser();
BatchUpdates(() =>
{
setUserInfo(parser.userInfo);
setUserFigure(parser.userInfo.figure);
});
}, []);
UseMessageEventHook(UserInfoEvent, onUserInfoEvent);

View File

@ -8,8 +8,8 @@ export interface PromoArticleWidgetViewProps
export const PromoArticleWidgetView: FC<PromoArticleWidgetViewProps> = props =>
{
const [articles, setArticles] = useState<PromoArticleData[]>(null);
const [index, setIndex] = useState(0);
const [ articles, setArticles ] = useState<PromoArticleData[]>(null);
const [ index, setIndex ] = useState(0);
const handleSelect = (selectedIndex) =>
{

View File

@ -4,11 +4,11 @@ import { AddEventLinkTracker, GetLocalization, GetRoomEngine, LocalizeText, Remo
import { isObjectMoverRequested, setObjectMoverRequested } from '../../api/inventory/InventoryUtilities';
import { NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../common';
import { useInventoryTrade, useInventoryUnseenTracker, UseMessageEventHook, UseRoomEngineEvent, UseRoomSessionManagerEvent } from '../../hooks';
import { InventoryBadgeView } from './views/InventoryBadgeView';
import { InventoryBotView } from './views/InventoryBotView';
import { InventoryFurnitureView } from './views/InventoryFurnitureView';
import { InventoryPetView } from './views/InventoryPetView';
import { InventoryTradeView } from './views/InventoryTradeView';
import { InventoryBadgeView } from './views/badge/InventoryBadgeView';
import { InventoryBotView } from './views/bot/InventoryBotView';
import { InventoryFurnitureView } from './views/furniture/InventoryFurnitureView';
import { InventoryTradeView } from './views/furniture/InventoryTradeView';
import { InventoryPetView } from './views/pet/InventoryPetView';
const TAB_FURNITURE: string = 'inventory.furni';
const TAB_BOTS: string = 'inventory.bots';
@ -130,10 +130,8 @@ export const InventoryView: FC<{}> = props =>
<NitroCardTabsView>
{ TABS.map((name, index) =>
{
const unseenCount = getCount(UNSEEN_CATEGORIES[index]);
return (
<NitroCardTabsItemView key={ index } isActive={ (currentTab === name) } onClick={ event => setCurrentTab(name) } count={ unseenCount }>
<NitroCardTabsItemView key={ index } isActive={ (currentTab === name) } onClick={ event => setCurrentTab(name) } count={ getCount(UNSEEN_CATEGORIES[index]) }>
{ LocalizeText(name) }
</NitroCardTabsItemView>
);

View File

@ -0,0 +1,19 @@
import { FC } from 'react';
import { UnseenItemCategory } from '../../../../api';
import { LayoutBadgeImageView, LayoutGridItem } from '../../../../common';
import { useInventoryBadges, useInventoryUnseenTracker } from '../../../../hooks';
export const InventoryBadgeItemView: FC<{ badgeCode: string }> = props =>
{
const { badgeCode = null, children = null, ...rest } = props;
const { selectedBadgeCode = null, setSelectedBadgeCode = null, getBadgeId = null } = useInventoryBadges();
const { isUnseen = null } = useInventoryUnseenTracker();
const unseen = isUnseen(UnseenItemCategory.BADGE, getBadgeId(badgeCode));
return (
<LayoutGridItem itemActive={ (selectedBadgeCode === badgeCode) } itemUnseen={ unseen } onMouseDown={ event => setSelectedBadgeCode(badgeCode) } { ...rest }>
<LayoutBadgeImageView badgeCode={ badgeCode } />
{ children }
</LayoutGridItem>
);
}

View File

@ -1,47 +1,37 @@
import { FC, useEffect } from 'react';
import { LocalizeBadgeName, LocalizeText, UnseenItemCategory } from '../../../api';
import { AutoGrid, Button, Column, Flex, Grid, LayoutBadgeImageView, LayoutGridItem, Text } from '../../../common';
import { useInventoryBadges, useInventoryUnseenTracker } from '../../../hooks';
import { FC, useEffect, useState } from 'react';
import { LocalizeBadgeName, LocalizeText, UnseenItemCategory } from '../../../../api';
import { AutoGrid, Button, Column, Flex, Grid, LayoutBadgeImageView, Text } from '../../../../common';
import { useInventoryBadges, useInventoryUnseenTracker } from '../../../../hooks';
import { InventoryBadgeItemView } from './InventoryBadgeItemView';
export const InventoryBadgeView: FC<{}> = props =>
{
const { badgeCodes = [], activeBadgeCodes = [], selectedBadgeCode = null, isWearingBadge = null, canWearBadges = null, toggleBadge = null, selectBadge = null, getBadgeId = null } = useInventoryBadges();
const [ isVisible, setIsVisible ] = useState(false);
const { badgeCodes = [], activeBadgeCodes = [], selectedBadgeCode = null, isWearingBadge = null, canWearBadges = null, toggleBadge = null, getBadgeId = null, activate = null, deactivate = null } = useInventoryBadges();
const { getCount = null, resetCategory = null, isUnseen = null, removeUnseen = null } = useInventoryUnseenTracker();
useEffect(() =>
{
if(!badgeCodes || !badgeCodes.length) return;
if(!selectedBadgeCode || !isUnseen(UnseenItemCategory.BADGE, getBadgeId(selectedBadgeCode))) return;
return () =>
removeUnseen(UnseenItemCategory.BADGE, getBadgeId(selectedBadgeCode));
}, [ selectedBadgeCode, isUnseen, removeUnseen, getBadgeId ]);
useEffect(() =>
{
const count = getCount(UnseenItemCategory.BADGE);
if(!isVisible) return;
if(!count) return;
const id = activate();
resetCategory(UnseenItemCategory.BADGE);
}
}, [ badgeCodes, getCount, resetCategory ]);
return () => deactivate(id);
}, [ isVisible, activate, deactivate ]);
const InventoryBadgeItemView: FC<{ badgeCode: string }> = props =>
useEffect(() =>
{
const { badgeCode = null, children = null, ...rest } = props;
const badgeId = getBadgeId(badgeCode);
const unseen = isUnseen(UnseenItemCategory.BADGE, badgeId);
setIsVisible(true);
const select = () =>
{
selectBadge(badgeCode);
if(unseen) removeUnseen(UnseenItemCategory.BADGE, badgeId);
}
return (
<LayoutGridItem itemActive={ (selectedBadgeCode === badgeCode) } itemUnseen={ unseen } onMouseDown={ select } { ...rest }>
<LayoutBadgeImageView badgeCode={ badgeCode } />
{ children }
</LayoutGridItem>
);
}
return () => setIsVisible(false);
}, []);
return (
<Grid>

View File

@ -0,0 +1,40 @@
import { MouseEventType } from '@nitrots/nitro-renderer';
import { FC, MouseEvent, useState } from 'react';
import { attemptBotPlacement, IBotItem, UnseenItemCategory } from '../../../../api';
import { LayoutAvatarImageView, LayoutGridItem } from '../../../../common';
import { useInventoryBots, useInventoryUnseenTracker } from '../../../../hooks';
export const InventoryBotItemView: FC<{ botItem: IBotItem }> = props =>
{
const { botItem = null, children = null, ...rest } = props;
const [ isMouseDown, setMouseDown ] = useState(false);
const { selectedBot = null, setSelectedBot = null } = useInventoryBots();
const { isUnseen = null } = useInventoryUnseenTracker();
const unseen = isUnseen(UnseenItemCategory.BOT, botItem.botData.id);
const onMouseEvent = (event: MouseEvent) =>
{
switch(event.type)
{
case MouseEventType.MOUSE_DOWN:
setSelectedBot(botItem);
setMouseDown(true);
return;
case MouseEventType.MOUSE_UP:
setMouseDown(false);
return;
case MouseEventType.ROLL_OUT:
if(!isMouseDown || (selectedBot !== botItem)) return;
attemptBotPlacement(botItem);
return;
}
}
return (
<LayoutGridItem itemActive={ (selectedBot === botItem) } itemUnseen={ unseen } onMouseDown={ onMouseEvent } onMouseUp={ onMouseEvent } onMouseOut={ onMouseEvent } { ...rest }>
<LayoutAvatarImageView figure={ botItem.botData.figure } direction={ 3 } headOnly={ true } />
{ children }
</LayoutGridItem>
);
}

View File

@ -1,9 +1,10 @@
import { IRoomSession, MouseEventType, RoomObjectVariable, RoomPreviewer } from '@nitrots/nitro-renderer';
import { FC, MouseEvent, useEffect, useState } from 'react';
import { attemptBotPlacement, GetRoomEngine, IBotItem, LocalizeText, UnseenItemCategory } from '../../../api';
import { AutoGrid, Button, Column, Grid, LayoutAvatarImageView, LayoutGridItem, LayoutRoomPreviewerView, Text } from '../../../common';
import { useInventoryBots, useInventoryUnseenTracker } from '../../../hooks';
import { InventoryCategoryEmptyView } from './InventoryCategoryEmptyView';
import { IRoomSession, RoomObjectVariable, RoomPreviewer } from '@nitrots/nitro-renderer';
import { FC, useEffect, useState } from 'react';
import { attemptBotPlacement, GetRoomEngine, LocalizeText, UnseenItemCategory } from '../../../../api';
import { AutoGrid, Button, Column, Grid, LayoutRoomPreviewerView, Text } from '../../../../common';
import { useInventoryBots, useInventoryUnseenTracker } from '../../../../hooks';
import { InventoryCategoryEmptyView } from '../InventoryCategoryEmptyView';
import { InventoryBotItemView } from './InventoryBotItemView';
interface InventoryBotViewProps
{
@ -14,22 +15,9 @@ interface InventoryBotViewProps
export const InventoryBotView: FC<InventoryBotViewProps> = props =>
{
const { roomSession = null, roomPreviewer = null } = props;
const { botItems = [], selectedBot = null, selectBot = null } = useInventoryBots();
const { getCount = null, resetCategory = null, isUnseen = null, removeUnseen = null } = useInventoryUnseenTracker();
useEffect(() =>
{
if(!botItems || !botItems.length) return;
return () =>
{
const count = getCount(UnseenItemCategory.BOT);
if(!count) return;
resetCategory(UnseenItemCategory.BOT);
}
}, [ botItems, getCount, resetCategory ]);
const [ isVisible, setIsVisible ] = useState(false);
const { botItems = [], selectedBot = null, activate = null, deactivate = null } = useInventoryBots();
const { isUnseen = null, removeUnseen = null } = useInventoryUnseenTracker();
useEffect(() =>
{
@ -53,44 +41,31 @@ export const InventoryBotView: FC<InventoryBotViewProps> = props =>
roomPreviewer.addAvatarIntoRoom(botData.figure, 0);
}, [ roomPreviewer, selectedBot ]);
useEffect(() =>
{
if(!selectedBot || !isUnseen(UnseenItemCategory.BOT, selectedBot.botData.id)) return;
removeUnseen(UnseenItemCategory.BOT, selectedBot.botData.id);
}, [ selectedBot, isUnseen, removeUnseen ]);
useEffect(() =>
{
if(!isVisible) return;
const id = activate();
return () => deactivate(id);
}, [ isVisible, activate, deactivate ]);
useEffect(() =>
{
setIsVisible(true);
return () => setIsVisible(false);
}, []);
if(!botItems || !botItems.length) return <InventoryCategoryEmptyView title={ LocalizeText('inventory.empty.bots.title') } desc={ LocalizeText('inventory.empty.bots.desc') } />;
const InventoryBotItemView: FC<{ botItem: IBotItem }> = props =>
{
const { botItem = null } = props;
const [ isMouseDown, setMouseDown ] = useState(false);
const isActive = (botItem === selectedBot);
const unseen = isUnseen(UnseenItemCategory.BOT, botItem.botData.id);
const onMouseEvent = (event: MouseEvent) =>
{
switch(event.type)
{
case MouseEventType.MOUSE_DOWN:
selectBot(botItem);
if(unseen) removeUnseen(UnseenItemCategory.BOT, botItem.botData.id);
setMouseDown(true);
return;
case MouseEventType.MOUSE_UP:
setMouseDown(false);
return;
case MouseEventType.ROLL_OUT:
if(!isMouseDown || !isActive) return;
attemptBotPlacement(botItem);
return;
}
}
return (
<LayoutGridItem itemActive={ isActive } itemUnseen={ unseen } onMouseDown={ onMouseEvent } onMouseUp={ onMouseEvent } onMouseOut={ onMouseEvent }>
<LayoutAvatarImageView figure={ botItem.botData.figure } direction={ 3 } headOnly={ true } />
</LayoutGridItem>
);
}
return (
<Grid>
<Column size={ 7 } overflow="hidden">

View File

@ -0,0 +1,35 @@
import { MouseEventType } from '@nitrots/nitro-renderer';
import { FC, MouseEvent, useState } from 'react';
import { attemptItemPlacement, GroupItem } from '../../../../api';
import { LayoutGridItem } from '../../../../common';
import { useInventoryFurni } from '../../../../hooks';
export const InventoryFurnitureItemView: FC<{ groupItem: GroupItem }> = props =>
{
const { groupItem = null, ...rest } = props;
const [ isMouseDown, setMouseDown ] = useState(false);
const { selectedItem = null, setSelectedItem = null } = useInventoryFurni();
const onMouseEvent = (event: MouseEvent) =>
{
switch(event.type)
{
case MouseEventType.MOUSE_DOWN:
setSelectedItem(groupItem);
setMouseDown(true);
return;
case MouseEventType.MOUSE_UP:
setMouseDown(false);
return;
case MouseEventType.ROLL_OUT:
if(!isMouseDown || !(groupItem === selectedItem)) return;
attemptItemPlacement(groupItem);
return;
}
}
const count = groupItem.getUnlockedCount();
return <LayoutGridItem className={ !count ? 'opacity-0-5 ' : '' } itemImage={ groupItem.iconUrl } itemCount={ groupItem.getUnlockedCount() } itemActive={ (groupItem === selectedItem) } itemUniqueNumber={ groupItem.stuffData.uniqueNumber } itemUnseen={ groupItem.hasUnseenItems } onMouseDown={ onMouseEvent } onMouseUp={ onMouseEvent } onMouseOut={ onMouseEvent } { ...rest } />;
}

View File

@ -1,7 +1,7 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Dispatch, FC, SetStateAction, useEffect, useState } from 'react';
import { GroupItem, LocalizeText } from '../../../api';
import { Button, Flex } from '../../../common';
import { GroupItem, LocalizeText } from '../../../../api';
import { Button, Flex } from '../../../../common';
export interface InventoryFurnitureSearchViewProps
{

View File

@ -1,10 +1,11 @@
import { IRoomSession, MouseEventType, RoomObjectVariable, RoomPreviewer, Vector3d } from '@nitrots/nitro-renderer';
import { FC, MouseEvent, useEffect, useState } from 'react';
import { attemptItemPlacement, FurniCategory, GetRoomEngine, GetSessionDataManager, GroupItem, LocalizeText, UnseenItemCategory } from '../../../api';
import { AutoGrid, Button, Column, Grid, LayoutGridItem, LayoutLimitedEditionCompactPlateView, LayoutRarityLevelView, LayoutRoomPreviewerView, Text } from '../../../common';
import { useInventoryFurni, useInventoryUnseenTracker } from '../../../hooks';
import { attemptPlaceMarketplaceOffer } from '../../../hooks/inventory/common';
import { InventoryCategoryEmptyView } from './InventoryCategoryEmptyView';
import { IRoomSession, RoomObjectVariable, RoomPreviewer, Vector3d } from '@nitrots/nitro-renderer';
import { FC, useEffect, useState } from 'react';
import { attemptItemPlacement, FurniCategory, GetRoomEngine, GetSessionDataManager, GroupItem, LocalizeText, UnseenItemCategory } from '../../../../api';
import { AutoGrid, Button, Column, Grid, LayoutLimitedEditionCompactPlateView, LayoutRarityLevelView, LayoutRoomPreviewerView, Text } from '../../../../common';
import { useInventoryFurni, useInventoryUnseenTracker } from '../../../../hooks';
import { attemptPlaceMarketplaceOffer } from '../../../../hooks/inventory/common';
import { InventoryCategoryEmptyView } from '../InventoryCategoryEmptyView';
import { InventoryFurnitureItemView } from './InventoryFurnitureItemView';
import { InventoryFurnitureSearchView } from './InventoryFurnitureSearchView';
interface InventoryFurnitureViewProps
@ -16,9 +17,10 @@ interface InventoryFurnitureViewProps
export const InventoryFurnitureView: FC<InventoryFurnitureViewProps> = props =>
{
const { roomSession = null, roomPreviewer = null } = props;
const [ isVisible, setIsVisible ] = useState(false);
const [ filteredGroupItems, setFilteredGroupItems ] = useState<GroupItem[]>([]);
const { groupItems = [], selectedItem = null, selectItem = null, activate = null, deactivate = null } = useInventoryFurni();
const { getCount = null, resetCategory = null } = useInventoryUnseenTracker();
const { groupItems = [], selectedItem = null, activate = null, deactivate = null } = useInventoryFurni();
const { resetItems = null } = useInventoryUnseenTracker();
useEffect(() =>
{
@ -72,65 +74,30 @@ export const InventoryFurnitureView: FC<InventoryFurnitureViewProps> = props =>
useEffect(() =>
{
if(!groupItems || !groupItems.length) return;
if(!selectedItem || !selectedItem.hasUnseenItems) return;
return () =>
{
const count = getCount(UnseenItemCategory.FURNI);
resetItems(UnseenItemCategory.FURNI, selectedItem.items.map(item => item.id));
if(!count) return;
resetCategory(UnseenItemCategory.FURNI);
for(const groupItem of groupItems) groupItem.hasUnseenItems = false;
}
}, [ groupItems, getCount, resetCategory ]);
selectedItem.hasUnseenItems = false;
}, [ selectedItem, resetItems ]);
useEffect(() =>
{
if(!isVisible) return;
const id = activate();
return () => deactivate(id);
}, [ activate, deactivate ]);
if(!groupItems || !groupItems.length) return <InventoryCategoryEmptyView title={ LocalizeText('inventory.empty.title') } desc={ LocalizeText('inventory.empty.desc') } />;
const InventoryFurnitureItemView: FC<{ groupItem: GroupItem }> = props =>
{
const { groupItem = null } = props;
const [ isMouseDown, setMouseDown ] = useState(false);
const isActive = (groupItem === selectedItem);
const onMouseEvent = (event: MouseEvent) =>
{
switch(event.type)
{
case MouseEventType.MOUSE_DOWN:
selectItem(groupItem);
setMouseDown(true);
return;
case MouseEventType.MOUSE_UP:
setMouseDown(false);
return;
case MouseEventType.ROLL_OUT:
if(!isMouseDown || !isActive) return;
attemptItemPlacement(groupItem);
return;
}
}
}, [ isVisible, activate, deactivate ]);
useEffect(() =>
{
if(!isActive) return;
setIsVisible(true);
groupItem.hasUnseenItems = false;
}, [ isActive, groupItem ]);
return () => setIsVisible(false);
}, []);
const count = groupItem.getUnlockedCount();
return <LayoutGridItem className={ !count ? 'opacity-0-5 ' : '' } itemImage={ groupItem.iconUrl } itemCount={ count } itemActive={ isActive } itemUniqueNumber={ groupItem.stuffData.uniqueNumber } itemUnseen={ groupItem.hasUnseenItems } onMouseDown={ onMouseEvent } onMouseUp={ onMouseEvent } onMouseOut={ onMouseEvent } />;
}
if(!groupItems || !groupItems.length) return <InventoryCategoryEmptyView title={ LocalizeText('inventory.empty.title') } desc={ LocalizeText('inventory.empty.desc') } />;
return (
<Grid>

View File

@ -1,10 +1,10 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { IObjectData, TradingListAddItemComposer, TradingListAddItemsComposer } from '@nitrots/nitro-renderer';
import { FC, useEffect, useState } from 'react';
import { FurniCategory, GroupItem, IFurnitureItem, LocalizeText, NotificationAlertType, NotificationUtilities, SendMessageComposer, TradeState } from '../../../api';
import { AutoGrid, Base, Button, Column, Flex, Grid, LayoutGridItem, Text } from '../../../common';
import { useInventoryTrade } from '../../../hooks';
import { getGuildFurniType } from '../../../hooks/inventory/common/TradingUtilities';
import { FurniCategory, GroupItem, IFurnitureItem, LocalizeText, NotificationAlertType, NotificationUtilities, SendMessageComposer, TradeState } from '../../../../api';
import { AutoGrid, Base, Button, Column, Flex, Grid, LayoutGridItem, Text } from '../../../../common';
import { useInventoryTrade } from '../../../../hooks';
import { getGuildFurniType } from '../../../../hooks/inventory/common/TradingUtilities';
import { InventoryFurnitureSearchView } from './InventoryFurnitureSearchView';
interface InventoryTradeViewProps

View File

@ -0,0 +1,40 @@
import { MouseEventType } from '@nitrots/nitro-renderer';
import { FC, MouseEvent, useState } from 'react';
import { attemptPetPlacement, IPetItem, UnseenItemCategory } from '../../../../api';
import { LayoutGridItem, LayoutPetImageView } from '../../../../common';
import { useInventoryPets, useInventoryUnseenTracker } from '../../../../hooks';
export const InventoryPetItemView: FC<{ petItem: IPetItem }> = props =>
{
const { petItem = null, children = null, ...rest } = props;
const [ isMouseDown, setMouseDown ] = useState(false);
const { selectedPet = null, setSelectedPet = null } = useInventoryPets();
const { isUnseen } = useInventoryUnseenTracker();
const unseen = isUnseen(UnseenItemCategory.PET, petItem.petData.id);
const onMouseEvent = (event: MouseEvent) =>
{
switch(event.type)
{
case MouseEventType.MOUSE_DOWN:
setSelectedPet(petItem);
setMouseDown(true);
return;
case MouseEventType.MOUSE_UP:
setMouseDown(false);
return;
case MouseEventType.ROLL_OUT:
if(!isMouseDown || !(petItem === selectedPet)) return;
attemptPetPlacement(petItem);
return;
}
}
return (
<LayoutGridItem itemActive={ (petItem === selectedPet) } itemUnseen={ unseen } onMouseDown={ onMouseEvent } onMouseUp={ onMouseEvent } onMouseOut={ onMouseEvent } { ...rest }>
<LayoutPetImageView figure={ petItem.petData.figureData.figuredata } direction={ 3 } headOnly={ true } />
{ children }
</LayoutGridItem>
);
}

View File

@ -1,9 +1,10 @@
import { IRoomSession, MouseEventType, RoomObjectVariable, RoomPreviewer } from '@nitrots/nitro-renderer';
import { FC, MouseEvent, useEffect, useState } from 'react';
import { attemptPetPlacement, GetRoomEngine, IPetItem, LocalizeText, UnseenItemCategory } from '../../../api';
import { AutoGrid, Button, Column, Grid, LayoutGridItem, LayoutPetImageView, LayoutRoomPreviewerView, Text } from '../../../common';
import { useInventoryPets, useInventoryUnseenTracker } from '../../../hooks';
import { InventoryCategoryEmptyView } from './InventoryCategoryEmptyView';
import { IRoomSession, RoomObjectVariable, RoomPreviewer } from '@nitrots/nitro-renderer';
import { FC, useEffect, useState } from 'react';
import { attemptPetPlacement, GetRoomEngine, LocalizeText, UnseenItemCategory } from '../../../../api';
import { AutoGrid, Button, Column, Grid, LayoutRoomPreviewerView, Text } from '../../../../common';
import { useInventoryPets, useInventoryUnseenTracker } from '../../../../hooks';
import { InventoryCategoryEmptyView } from '../InventoryCategoryEmptyView';
import { InventoryPetItemView } from './InventoryPetItemView';
interface InventoryPetViewProps
{
@ -14,22 +15,9 @@ interface InventoryPetViewProps
export const InventoryPetView: FC<InventoryPetViewProps> = props =>
{
const { roomSession = null, roomPreviewer = null } = props;
const { petItems = null, selectedPet = null, selectPet = null } = useInventoryPets();
const { getCount = null, resetCategory = null, isUnseen = null, removeUnseen = null } = useInventoryUnseenTracker();
useEffect(() =>
{
if(!petItems || !petItems.length) return;
return () =>
{
const count = getCount(UnseenItemCategory.PET);
if(!count) return;
resetCategory(UnseenItemCategory.PET);
}
}, [ petItems, getCount, resetCategory ]);
const [ isVisible, setIsVisible ] = useState(false);
const { petItems = null, selectedPet = null, activate = null, deactivate = null } = useInventoryPets();
const { isUnseen = null, removeUnseen = null } = useInventoryUnseenTracker();
useEffect(() =>
{
@ -52,44 +40,31 @@ export const InventoryPetView: FC<InventoryPetViewProps> = props =>
roomPreviewer.addPetIntoRoom(petData.figureString);
}, [ roomPreviewer, selectedPet ]);
useEffect(() =>
{
if(!selectedPet || !isUnseen(UnseenItemCategory.PET, selectedPet.petData.id)) return;
removeUnseen(UnseenItemCategory.PET, selectedPet.petData.id);
}, [ selectedPet, isUnseen, removeUnseen ]);
useEffect(() =>
{
if(!isVisible) return;
const id = activate();
return () => deactivate(id);
}, [ isVisible, activate, deactivate ]);
useEffect(() =>
{
setIsVisible(true);
return () => setIsVisible(false);
}, []);
if(!petItems || !petItems.length) return <InventoryCategoryEmptyView title={ LocalizeText('inventory.empty.pets.title') } desc={ LocalizeText('inventory.empty.pets.desc') } />;
const InventoryPetItemView: FC<{ petItem: IPetItem }> = props =>
{
const { petItem = null } = props;
const [ isMouseDown, setMouseDown ] = useState(false);
const isActive = (petItem === selectedPet);
const unseen = isUnseen(UnseenItemCategory.PET, petItem.petData.id);
const onMouseEvent = (event: MouseEvent) =>
{
switch(event.type)
{
case MouseEventType.MOUSE_DOWN:
selectPet(petItem);
if(unseen) removeUnseen(UnseenItemCategory.PET, petItem.petData.id);
setMouseDown(true);
return;
case MouseEventType.MOUSE_UP:
setMouseDown(false);
return;
case MouseEventType.ROLL_OUT:
if(!isMouseDown || !isActive) return;
attemptPetPlacement(petItem);
return;
}
}
return (
<LayoutGridItem itemActive={ isActive } itemUnseen={ unseen } onMouseDown={ onMouseEvent } onMouseUp={ onMouseEvent } onMouseOut={ onMouseEvent }>
<LayoutPetImageView figure={ petItem.petData.figureData.figuredata } direction={ 3 } headOnly={ true } />
</LayoutGridItem>
);
}
return (
<Grid>
<Column size={ 7 } overflow="hidden">

View File

@ -90,7 +90,7 @@ export const MainView: FC<{}> = props =>
{
RemoveLinkEventTracker(linkTracker);
}
}, [onLinkReceived]);
}, [ onLinkReceived ]);
return (
<Base fit>

View File

@ -34,7 +34,7 @@ export const ModToolsMessageHandler: FC<{}> = props =>
}
});
}, [dispatchModToolsState]);
}, [ dispatchModToolsState ]);
const onIssueInfoMessageEvent = useCallback((event: IssueInfoMessageEvent) =>
{
@ -62,7 +62,7 @@ export const ModToolsMessageHandler: FC<{}> = props =>
}
});
}, [dispatchModToolsState, tickets]);
}, [ dispatchModToolsState, tickets ]);
const onModeratorToolPreferencesEvent = useCallback((event: ModeratorToolPreferencesEvent) =>
{
@ -100,7 +100,7 @@ export const ModToolsMessageHandler: FC<{}> = props =>
tickets: newTickets
}
});
}, [dispatchModToolsState, tickets]);
}, [ dispatchModToolsState, tickets ]);
const onModeratorActionResultMessageEvent = useCallback((event: ModeratorActionResultMessageEvent) =>
{
@ -135,7 +135,7 @@ export const ModToolsMessageHandler: FC<{}> = props =>
SetCfhCategories(categories);
}, [dispatchModToolsState]);
}, [ dispatchModToolsState ]);
const onCfhSanctionMessageEvent = useCallback((event: CfhSanctionMessageEvent) =>
{
@ -195,7 +195,7 @@ export const ModToolsMessageHandler: FC<{}> = props =>
dispatchModToolsState({
type: ModToolsActions.SET_OPEN_ROOMS,
payload: {
openRooms: [...rooms, castedEvent.roomId]
openRooms: [ ...rooms, castedEvent.roomId ]
}
});
return;
@ -210,7 +210,7 @@ export const ModToolsMessageHandler: FC<{}> = props =>
dispatchModToolsState({
type: ModToolsActions.SET_OPEN_ROOM_CHATLOGS,
payload: {
openRoomChatlogs: [...chatlogs, castedEvent.roomId]
openRoomChatlogs: [ ...chatlogs, castedEvent.roomId ]
}
});
return;
@ -225,7 +225,7 @@ export const ModToolsMessageHandler: FC<{}> = props =>
dispatchModToolsState({
type: ModToolsActions.SET_OPEN_USERINFO,
payload: {
openUserInfo: [...userInfo, castedEvent.userId]
openUserInfo: [ ...userInfo, castedEvent.userId ]
}
});
return;
@ -240,13 +240,13 @@ export const ModToolsMessageHandler: FC<{}> = props =>
dispatchModToolsState({
type: ModToolsActions.SET_OPEN_USER_CHATLOGS,
payload: {
openUserChatlogs: [...userChatlog, castedEvent.userId]
openUserChatlogs: [ ...userChatlog, castedEvent.userId ]
}
});
return;
}
}
}, [openRooms, dispatchModToolsState, openRoomChatlogs, openUserInfo, openUserChatlogs]);
}, [ openRooms, dispatchModToolsState, openRoomChatlogs, openUserInfo, openUserChatlogs ]);
UseUiEvent(ModToolsEvent.OPEN_ROOM_INFO, onModToolsEvent);
UseUiEvent(ModToolsEvent.OPEN_ROOM_CHATLOG, onModToolsEvent);

View File

@ -17,7 +17,7 @@ import { ModToolsUserView } from './views/user/ModToolsUserView';
export const ModToolsView: FC<{}> = props =>
{
const [ isVisible, setIsVisible ] = useState(false);
const [ selectedUser, setSelectedUser] = useState<ISelectedUser>(null);
const [ selectedUser, setSelectedUser ] = useState<ISelectedUser>(null);
const [ isTicketsVisible, setIsTicketsVisible ] = useState(false);
const [ modToolsState, dispatchModToolsState ] = useReducer(ModToolsReducer, initialModTools);
const { currentRoomId = null, openRooms = null, openRoomChatlogs = null, openUserChatlogs = null, openUserInfo = null } = modToolsState;
@ -179,7 +179,7 @@ export const ModToolsView: FC<{}> = props =>
return;
}
}
}, [openRooms, currentRoomId, openRoomChatlogs, selectedUser, openUserInfo, openUserChatlogs]);
}, [ openRooms, currentRoomId, openRoomChatlogs, selectedUser, openUserInfo, openUserChatlogs ]);
return (
<ModToolsContextProvider value={ { modToolsState, dispatchModToolsState } }>

View File

@ -98,7 +98,7 @@ export const ChatlogView: FC<ChatlogViewProps> = props =>
}
return count;
}, [records]);
}, [ records ]);
const RoomInfo = (props: { roomId: number, roomName: string, uniqueKey: Key, style: CSSProperties }) =>
{

View File

@ -3,7 +3,7 @@ import { FC, useCallback, useEffect, useState } from 'react';
import { SendMessageComposer, TryVisitRoom } from '../../../../api';
import { Button, Column, DraggableWindowPosition, Flex, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../../common';
import { ModToolsOpenRoomChatlogEvent } from '../../../../events/mod-tools/ModToolsOpenRoomChatlogEvent';
import { BatchUpdates, DispatchUiEvent, UseMessageEventHook } from '../../../../hooks';
import { DispatchUiEvent, UseMessageEventHook } from '../../../../hooks';
interface ModToolsRoomViewProps
{
@ -36,15 +36,12 @@ export const ModToolsRoomView: FC<ModToolsRoomViewProps> = props =>
if(!parser || parser.data.flatId !== roomId) return;
BatchUpdates(() =>
{
setLoadedRoomId(parser.data.flatId);
setName(parser.data.room.name);
setOwnerId(parser.data.ownerId);
setOwnerName(parser.data.ownerName);
setOwnerInRoom(parser.data.ownerInRoom);
setUsersInRoom(parser.data.userCount);
});
}, [ roomId ]);
UseMessageEventHook(ModeratorRoomInfoEvent, onModtoolRoomInfoEvent);

View File

@ -19,7 +19,7 @@ export const CfhChatlogView: FC<CfhChatlogViewProps> = props =>
useEffect(() =>
{
SendMessageComposer(new GetCfhChatlogMessageComposer(issueId));
}, [issueId]);
}, [ issueId ]);
const onCfhChatlogEvent = useCallback((event: CfhChatlogEvent) =>
{
@ -28,7 +28,7 @@ export const CfhChatlogView: FC<CfhChatlogViewProps> = props =>
if(!parser || parser.data.issueId !== issueId) return;
setChatlogData(parser.data);
}, [issueId]);
}, [ issueId ]);
UseMessageEventHook(CfhChatlogEvent, onCfhChatlogEvent);
@ -36,7 +36,7 @@ export const CfhChatlogView: FC<CfhChatlogViewProps> = props =>
<NitroCardView className="nitro-mod-tools-chatlog" theme="primary-slim">
<NitroCardHeaderView headerText={'Issue Chatlog'} onCloseClick={onCloseClick} />
<NitroCardContentView className="text-black">
{ chatlogData && <ChatlogView records={[chatlogData.chatRecord]} />}
{ chatlogData && <ChatlogView records={[ chatlogData.chatRecord ]} />}
</NitroCardContentView>
</NitroCardView>
);

View File

@ -13,7 +13,7 @@ export const ModToolsMyIssuesTabView: FC<ModToolsMyIssuesTabViewProps> = props =
{
const { myIssues = null, onIssueHandleClick = null } = props;
const onReleaseIssue = (issueId: number) => SendMessageComposer(new ReleaseIssuesMessageComposer([issueId]));
const onReleaseIssue = (issueId: number) => SendMessageComposer(new ReleaseIssuesMessageComposer([ issueId ]));
return (
<Column gap={ 0 } overflow="hidden">

View File

@ -12,7 +12,7 @@ export const ModToolsOpenIssuesTabView: FC<ModToolsOpenIssuesTabViewProps> = pro
{
const { openIssues = null } = props;
const onPickIssue = (issueId: number) => SendMessageComposer(new PickIssuesMessageComposer([issueId], false, 0, 'pick issue button'));
const onPickIssue = (issueId: number) => SendMessageComposer(new PickIssuesMessageComposer([ issueId ], false, 0, 'pick issue button'));
return (
<Column gap={ 0 } overflow="hidden">

View File

@ -32,21 +32,21 @@ export const ModToolsTicketsView: FC<ModToolsTicketsViewProps> = props =>
if(!tickets) return [];
return tickets.filter(issue => issue.state === IssueMessageData.STATE_OPEN);
}, [tickets]);
}, [ tickets ]);
const myIssues = useMemo(() =>
{
if(!tickets) return [];
return tickets.filter(issue => (issue.state === IssueMessageData.STATE_PICKED) && (issue.pickerUserId === GetSessionDataManager().userId));
}, [tickets]);
}, [ tickets ]);
const pickedIssues = useMemo(() =>
{
if(!tickets) return [];
return tickets.filter(issue => issue.state === IssueMessageData.STATE_PICKED);
}, [tickets]);
}, [ tickets ]);
const onIssueInfoClosed = useCallback((issueId: number) =>
{
@ -57,7 +57,7 @@ export const ModToolsTicketsView: FC<ModToolsTicketsViewProps> = props =>
const newValues = Array.from(issueInfoWindows);
newValues.splice(indexOfValue, 1);
setIssueInfoWindows(newValues);
}, [issueInfoWindows]);
}, [ issueInfoWindows ]);
const onIssueHandleClicked = useCallback((issueId: number) =>
{
@ -71,7 +71,7 @@ export const ModToolsTicketsView: FC<ModToolsTicketsViewProps> = props =>
{
onIssueInfoClosed(issueId);
}
}, [issueInfoWindows, onIssueInfoClosed]);
}, [ issueInfoWindows, onIssueInfoClosed ]);
const CurrentTabComponent = useCallback(() =>
{
@ -82,7 +82,7 @@ export const ModToolsTicketsView: FC<ModToolsTicketsViewProps> = props =>
case 2: return <ModToolsPickedIssuesTabView pickedIssues={pickedIssues}/>;
default: return null;
}
}, [currentTab, myIssues, onIssueHandleClicked, openIssues, pickedIssues]);
}, [ currentTab, myIssues, onIssueHandleClicked, openIssues, pickedIssues ]);
return (
<>

View File

@ -2,7 +2,7 @@ import { ChatRecordData, GetUserChatlogMessageComposer, UserChatlogEvent } from
import { FC, useCallback, useEffect, useState } from 'react';
import { SendMessageComposer } from '../../../../api';
import { DraggableWindowPosition, NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../common';
import { BatchUpdates, UseMessageEventHook } from '../../../../hooks';
import { UseMessageEventHook } from '../../../../hooks';
import { ChatlogView } from '../chatlog/ChatlogView';
interface ModToolsUserChatlogViewProps
@ -23,11 +23,8 @@ export const ModToolsUserChatlogView: FC<ModToolsUserChatlogViewProps> = props =
if(!parser || parser.data.userId !== userId) return;
BatchUpdates(() =>
{
setUsername(parser.data.username);
setUserChatlog(parser.data.roomChatlogs);
});
}, [ userId ]);
UseMessageEventHook(UserChatlogEvent, onModtoolUserChatlogEvent);

View File

@ -43,7 +43,7 @@ export const ModToolsUserRoomVisitsView: FC<ModToolsUserRoomVisitsViewProps> = p
useEffect(() =>
{
SendMessageComposer(new GetRoomVisitsMessageComposer(userId));
}, [userId]);
}, [ userId ]);
if(!userId) return null;

View File

@ -1,7 +1,7 @@
import { CanCreateRoomEventEvent, CantConnectMessageParser, FollowFriendMessageComposer, GenericErrorEvent, GetGuestRoomResultEvent, HabboWebTools, LegacyExternalInterface, NavigatorCategoriesComposer, NavigatorCategoriesEvent, NavigatorHomeRoomEvent, NavigatorMetadataEvent, NavigatorOpenRoomCreatorEvent, NavigatorSearchEvent, NavigatorSettingsComposer, RoomCreatedEvent, RoomDataParser, RoomDoorbellAcceptedEvent, RoomDoorbellEvent, RoomDoorbellRejectedEvent, RoomEnterErrorEvent, RoomEntryInfoMessageEvent, RoomForwardEvent, RoomInfoComposer, RoomScoreEvent, RoomSettingsUpdatedEvent, SecurityLevel, UserInfoEvent, UserPermissionsEvent } from '@nitrots/nitro-renderer';
import { FC, useCallback } from 'react';
import { CreateLinkEvent, CreateRoomSession, DoorStateType, GetConfiguration, GetSessionDataManager, LocalizeText, NotificationAlertType, NotificationUtilities, SendMessageComposer, TryVisitRoom, VisitDesktop } from '../../api';
import { BatchUpdates, UseMessageEventHook } from '../../hooks';
import { UseMessageEventHook } from '../../hooks';
import { useNavigatorContext } from './NavigatorContext';
export const NavigatorMessageHandler: FC<{}> = props =>
@ -271,19 +271,14 @@ export const NavigatorMessageHandler: FC<{}> = props =>
{
const parser = event.getParser();
BatchUpdates(() =>
{
setTopLevelContexts(parser.topLevelContexts);
setTopLevelContext(parser.topLevelContexts.length ? parser.topLevelContexts[0] : null);
});
}, [ setTopLevelContexts, setTopLevelContext ]);
const onNavigatorSearchEvent = useCallback((event: NavigatorSearchEvent) =>
{
const parser = event.getParser();
BatchUpdates(() =>
{
setTopLevelContext(prevValue =>
{
let newValue = prevValue;
@ -313,7 +308,6 @@ export const NavigatorMessageHandler: FC<{}> = props =>
});
setSearchResult(parser.result);
});
}, [ topLevelContexts, setTopLevelContext, setSearchResult ]);
const onNavigatorCategoriesEvent = useCallback((event: NavigatorCategoriesEvent) =>

View File

@ -3,7 +3,7 @@ import { ConvertGlobalRoomIdMessageComposer, HabboWebTools, ILinkEventTracker, L
import { FC, useCallback, useEffect, useRef, useState } from 'react';
import { AddEventLinkTracker, DoorStateType, LocalizeText, RemoveLinkEventTracker, SendMessageComposer, TryVisitRoom } from '../../api';
import { Base, Column, NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../common';
import { BatchUpdates, UseRoomSessionManagerEvent, useSharedNavigatorData } from '../../hooks';
import { UseRoomSessionManagerEvent, useSharedNavigatorData } from '../../hooks';
import { NavigatorContextProvider } from './NavigatorContext';
import { NavigatorMessageHandler } from './NavigatorMessageHandler';
import { NavigatorDoorStateView } from './views/NavigatorDoorStateView';
@ -37,11 +37,8 @@ export const NavigatorView: FC<{}> = props =>
switch(event.type)
{
case RoomSessionEvent.CREATED:
BatchUpdates(() =>
{
setIsVisible(false);
setCreatorOpen(false);
});
return;
}
}, []);
@ -96,11 +93,8 @@ export const NavigatorView: FC<{}> = props =>
switch(parts[1])
{
case 'show': {
BatchUpdates(() =>
{
setIsVisible(true);
setNeedsSearch(true);
});
return;
}
case 'hide':
@ -114,11 +108,8 @@ export const NavigatorView: FC<{}> = props =>
return;
}
BatchUpdates(() =>
{
setIsVisible(true);
setNeedsSearch(true);
});
return;
}
case 'toggle-room-info':
@ -145,11 +136,8 @@ export const NavigatorView: FC<{}> = props =>
}
return;
case 'create':
BatchUpdates(() =>
{
setIsVisible(true);
setCreatorOpen(true);
});
return;
case 'search':
if(parts.length > 2)
@ -162,11 +150,8 @@ export const NavigatorView: FC<{}> = props =>
pendingSearch.current = { value: searchValue, code: topLevelContextCode };
BatchUpdates(() =>
{
setIsVisible(true);
setNeedsSearch(true);
});
}
return;
}

View File

@ -3,7 +3,6 @@ import { HabboClubLevelEnum, RoomCreateComposer } from '@nitrots/nitro-renderer'
import { FC, useEffect, useState } from 'react';
import { GetClubMemberLevel, GetConfiguration, IRoomModel, LocalizeText, RoomModels, SendMessageComposer } from '../../../api';
import { Button, Column, Flex, Grid, LayoutCurrencyIcon, LayoutGridItem, Text } from '../../../common';
import { BatchUpdates } from '../../../hooks';
import { useNavigatorContext } from '../NavigatorContext';
export const NavigatorRoomCreatorView: FC<{}> = props =>
@ -39,11 +38,8 @@ export const NavigatorRoomCreatorView: FC<{}> = props =>
for(let i = 10; i <= 100; i = i + 10) list.push(i);
BatchUpdates(() =>
{
setMaxVisitorsList(list);
setVisitorsCount(list[0]);
});
}
}, [ maxVisitorsList ]);

View File

@ -5,7 +5,7 @@ import { FC, useEffect, useState } from 'react';
import { CreateLinkEvent, GetGroupInformation, GetSessionDataManager, LocalizeText, SendMessageComposer } from '../../../api';
import { Button, Column, Flex, LayoutBadgeImageView, LayoutRoomThumbnailView, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text, UserProfileIconView } from '../../../common';
import { FloorplanEditorEvent, RoomWidgetThumbnailEvent } from '../../../events';
import { BatchUpdates, DispatchUiEvent } from '../../../hooks';
import { DispatchUiEvent } from '../../../hooks';
import { useNavigatorContext } from '../NavigatorContext';
export class NavigatorRoomInfoViewProps
@ -85,11 +85,9 @@ export const NavigatorRoomInfoView: FC<NavigatorRoomInfoViewProps> = props =>
{
if(!navigatorData) return;
BatchUpdates(() =>
{
setIsRoomPicked(navigatorData.currentRoomIsStaffPick);
if(navigatorData.enteredGuestRoom) setIsRoomMuted(navigatorData.enteredGuestRoom.allInRoomMuted);
});
}, [ navigatorData ]);
if(!navigatorData.enteredGuestRoom) return null;
@ -142,7 +140,7 @@ export const NavigatorRoomInfoView: FC<NavigatorRoomInfoViewProps> = props =>
<Flex pointer alignItems="center" gap={ 1 } onClick={ () => processAction('open_group_info') }>
<LayoutBadgeImageView className="flex-none" badgeCode={ navigatorData.enteredGuestRoom.groupBadgeCode } isGroup={ true } />
<Text underline>
{ LocalizeText('navigator.guildbase', ['groupName'], [navigatorData.enteredGuestRoom.groupName]) }
{ LocalizeText('navigator.guildbase', [ 'groupName' ], [ navigatorData.enteredGuestRoom.groupName ]) }
</Text>
</Flex> }
</Column>

View File

@ -2,7 +2,6 @@ import { RoomDataParser } from '@nitrots/nitro-renderer';
import { FC, useEffect, useState } from 'react';
import { IRoomData, LocalizeText } from '../../../../api';
import { Column, Flex, Text } from '../../../../common';
import { BatchUpdates } from '../../../../hooks';
interface NavigatorRoomSettingsTabViewProps
{
@ -25,13 +24,10 @@ export const NavigatorRoomSettingsAccessTabView: FC<NavigatorRoomSettingsTabView
}
useEffect(() =>
{
BatchUpdates(() =>
{
setPassword('');
setConfirmPassword('');
setIsTryingPassword(false);
});
}, [ roomData ]);
return (

Some files were not shown because too many files have changed in this diff Show More