diff --git a/public/ui-config.json.example b/public/ui-config.json.example index d9934672..0497155b 100644 --- a/public/ui-config.json.example +++ b/public/ui-config.json.example @@ -14,6 +14,8 @@ "camera.publish.disabled": false, "hc.disabled": false, "badge.descriptions.enabled": true, + "motto.max.length": 38, + "bot.name.max.length": 15, "hotelview": { "show.avatar": true, "widgets": { diff --git a/src/components/catalog/CatalogMessageHandler.tsx b/src/components/catalog/CatalogMessageHandler.tsx index 9de5b0ce..1d811ed1 100644 --- a/src/components/catalog/CatalogMessageHandler.tsx +++ b/src/components/catalog/CatalogMessageHandler.tsx @@ -2,7 +2,7 @@ import { ApproveNameMessageEvent, CatalogPageMessageEvent, CatalogPagesListEvent import { GuildMembershipsMessageEvent } from '@nitrots/nitro-renderer/src/nitro/communication/messages/incoming/user/GuildMembershipsMessageEvent'; import { FC, useCallback } from 'react'; import { GetFurnitureData, GetProductDataForLocalization, LocalizeText, NotificationAlertType, NotificationUtilities } from '../../api'; -import { CatalogGiftReceiverNotFoundEvent, CatalogNameResultEvent, CatalogPurchasedEvent, CatalogPurchaseFailureEvent, CatalogPurchaseNotAllowedEvent, CatalogPurchaseSoldOutEvent, CatalogSetExtraPurchaseParameterEvent } from '../../events'; +import { CatalogGiftReceiverNotFoundEvent, CatalogNameResultEvent, CatalogPurchasedEvent, CatalogPurchaseFailureEvent, CatalogPurchaseNotAllowedEvent, CatalogPurchaseSoldOutEvent } from '../../events'; import { BatchUpdates, DispatchUiEvent, UseMessageEventHook } from '../../hooks'; import { useCatalogContext } from './CatalogContext'; import { CatalogNode } from './common/CatalogNode'; @@ -20,7 +20,7 @@ import { SubscriptionInfo } from './common/SubscriptionInfo'; export const CatalogMessageHandler: FC<{}> = props => { - const { setIsBusy, pageId, currentType, setRootNode, setOffersToNodes, currentPage, setCurrentOffer, setFrontPageItems, resetState, showCatalogPage, setCatalogOptions = null } = useCatalogContext(); + const { setIsBusy, pageId, currentType, setRootNode, setOffersToNodes, currentPage, setCurrentOffer, setFrontPageItems, resetState, showCatalogPage, setCatalogOptions, setPurchaseOptions } = useCatalogContext(); const onCatalogPagesListEvent = useCallback((event: CatalogPagesListEvent) => { @@ -153,11 +153,21 @@ export const CatalogMessageHandler: FC<{}> = props => if(offer.product && (offer.product.productType === ProductTypeEnum.WALL)) { - DispatchUiEvent(new CatalogSetExtraPurchaseParameterEvent(offer.product.extraParam)); + if(offer.product && (offer.product.productType === ProductTypeEnum.WALL)) + { + setPurchaseOptions(prevValue => + { + const newValue = { ...prevValue }; + + newValue.extraData =( offer.product.extraParam || null); + + return newValue; + }); + } } // (this._isObjectMoverRequested) && (this._purchasableOffer) - }, [ currentType, currentPage, setCurrentOffer ]); + }, [ currentType, currentPage, setCurrentOffer, setPurchaseOptions ]); const onSellablePetPalettesMessageEvent = useCallback((event: SellablePetPalettesMessageEvent) => { diff --git a/src/components/catalog/CatalogView.tsx b/src/components/catalog/CatalogView.tsx index 1cfbe184..84ab63a0 100644 --- a/src/components/catalog/CatalogView.tsx +++ b/src/components/catalog/CatalogView.tsx @@ -39,7 +39,7 @@ export const CatalogView: FC<{}> = props => const [ frontPageItems, setFrontPageItems ] = useState([]); const [ roomPreviewer, setRoomPreviewer ] = useState(null); const [ navigationHidden, setNavigationHidden ] = useState(false); - const [ purchaseOptions, setPurchaseOptions ] = useState({}); + const [ purchaseOptions, setPurchaseOptions ] = useState({ quantity: 1, extraData: null, extraParamRequired: false, previewStuffData: null }); const [ catalogOptions, setCatalogOptions ] = useState({}); const resetState = useCallback(() => diff --git a/src/components/catalog/views/page/layout/CatalogLayoutTrophiesView.tsx b/src/components/catalog/views/page/layout/CatalogLayoutTrophiesView.tsx index ee902ce4..eb6c5ba7 100644 --- a/src/components/catalog/views/page/layout/CatalogLayoutTrophiesView.tsx +++ b/src/components/catalog/views/page/layout/CatalogLayoutTrophiesView.tsx @@ -22,9 +22,11 @@ export const CatalogLayoutTrophiesView: FC = props => setPurchaseOptions(prevValue => { - const extraData = trophyText; + const newValue = { ...prevValue }; - return { ...prevValue, extraData }; + newValue.extraData = trophyText; + + return newValue; }); }, [ currentOffer, trophyText, setPurchaseOptions ]); diff --git a/src/components/catalog/views/page/widgets/CatalogBadgeSelectorWidgetView.tsx b/src/components/catalog/views/page/widgets/CatalogBadgeSelectorWidgetView.tsx index 6d243ede..fb32c1b2 100644 --- a/src/components/catalog/views/page/widgets/CatalogBadgeSelectorWidgetView.tsx +++ b/src/components/catalog/views/page/widgets/CatalogBadgeSelectorWidgetView.tsx @@ -43,10 +43,13 @@ export const CatalogBadgeSelectorWidgetView: FC { - const extraParamRequired = true; - const extraData = ((previewStuffData && previewStuffData.getValue(1)) || null); + const newValue = { ...prevValue }; - return { ...prevValue, extraParamRequired, extraData, previewStuffData }; + newValue.extraParamRequired = true; + newValue.extraData = ((previewStuffData && previewStuffData.getValue(1)) || null); + newValue.previewStuffData = previewStuffData; + + return newValue; }); }, [ currentOffer, previewStuffData, setPurchaseOptions ]); @@ -57,10 +60,10 @@ export const CatalogBadgeSelectorWidgetView: FC - { badges && (badges.length > 0) && badges.map(code => + { badges && (badges.length > 0) && badges.map((code, index) => { return ( - setCurrentBadge(code) }> + setCurrentBadge(code) }> ); diff --git a/src/components/catalog/views/page/widgets/CatalogGuildSelectorWidgetView.tsx b/src/components/catalog/views/page/widgets/CatalogGuildSelectorWidgetView.tsx index 78a367e9..ea856b59 100644 --- a/src/components/catalog/views/page/widgets/CatalogGuildSelectorWidgetView.tsx +++ b/src/components/catalog/views/page/widgets/CatalogGuildSelectorWidgetView.tsx @@ -31,10 +31,13 @@ export const CatalogGuildSelectorWidgetView: FC<{}> = props => setPurchaseOptions(prevValue => { - const extraParamRequired = true; - const extraData = ((previewStuffData && previewStuffData.getValue(1)) || null); + const newValue = { ...prevValue }; - return { ...prevValue, extraParamRequired, extraData, previewStuffData }; + newValue.extraParamRequired = true; + newValue.extraData = ((previewStuffData && previewStuffData.getValue(1)) || null); + newValue.previewStuffData = previewStuffData; + + return newValue; }); }, [ currentOffer, previewStuffData, setPurchaseOptions ]); diff --git a/src/components/catalog/views/page/widgets/CatalogItemGridWidgetView.tsx b/src/components/catalog/views/page/widgets/CatalogItemGridWidgetView.tsx index 7081c873..93ae4540 100644 --- a/src/components/catalog/views/page/widgets/CatalogItemGridWidgetView.tsx +++ b/src/components/catalog/views/page/widgets/CatalogItemGridWidgetView.tsx @@ -1,7 +1,5 @@ import { FC } from 'react'; import { AutoGrid, AutoGridProps } from '../../../../../common/AutoGrid'; -import { CatalogSetExtraPurchaseParameterEvent } from '../../../../../events'; -import { DispatchUiEvent } from '../../../../../hooks'; import { useCatalogContext } from '../../../CatalogContext'; import { IPurchasableOffer } from '../../../common/IPurchasableOffer'; import { ProductTypeEnum } from '../../../common/ProductTypeEnum'; @@ -15,7 +13,7 @@ interface CatalogItemGridWidgetViewProps extends AutoGridProps export const CatalogItemGridWidgetView: FC = props => { const { columnCount = 5, children = null, ...rest } = props; - const { currentOffer = null, setCurrentOffer = null, currentPage = null } = useCatalogContext(); + const { currentOffer = null, setCurrentOffer = null, currentPage = null, setPurchaseOptions = null } = useCatalogContext(); if(!currentPage) return null; @@ -29,7 +27,14 @@ export const CatalogItemGridWidgetView: FC = pro if(offer.product && (offer.product.productType === ProductTypeEnum.WALL)) { - setTimeout(() => DispatchUiEvent(new CatalogSetExtraPurchaseParameterEvent(offer.product.extraParam)), 0); + setPurchaseOptions(prevValue => + { + const newValue = { ...prevValue }; + + newValue.extraData = (offer.product.extraParam || null); + + return newValue; + }); } } diff --git a/src/components/catalog/views/page/widgets/CatalogPurchaseWidgetView.tsx b/src/components/catalog/views/page/widgets/CatalogPurchaseWidgetView.tsx index 4691b8a2..7ed446aa 100644 --- a/src/components/catalog/views/page/widgets/CatalogPurchaseWidgetView.tsx +++ b/src/components/catalog/views/page/widgets/CatalogPurchaseWidgetView.tsx @@ -2,7 +2,7 @@ import { PurchaseFromCatalogComposer } from '@nitrots/nitro-renderer'; import { FC, useCallback, useEffect, useMemo, useState } from 'react'; import { CreateLinkEvent, GetClubMemberLevel, LocalizeText, SendMessageComposer } from '../../../../../api'; import { Button, LayoutLoadingSpinnerView } from '../../../../../common'; -import { CatalogEvent, CatalogInitGiftEvent, CatalogInitPurchaseEvent, CatalogPurchasedEvent, CatalogPurchaseFailureEvent, CatalogPurchaseNotAllowedEvent, CatalogPurchaseSoldOutEvent, CatalogSetExtraPurchaseParameterEvent, CatalogWidgetEvent } from '../../../../../events'; +import { CatalogEvent, CatalogInitGiftEvent, CatalogInitPurchaseEvent, CatalogPurchasedEvent, CatalogPurchaseFailureEvent, CatalogPurchaseNotAllowedEvent, CatalogPurchaseSoldOutEvent, CatalogWidgetEvent } from '../../../../../events'; import { DispatchUiEvent, UseUiEvent } from '../../../../../hooks'; import { GetCurrencyAmount } from '../../../../purse/common/CurrencyHelper'; import { useCatalogContext } from '../../../CatalogContext'; @@ -32,22 +32,6 @@ export const CatalogPurchaseWidgetView: FC = pro UseUiEvent(CatalogWidgetEvent.INIT_PURCHASE, onCatalogInitPurchaseEvent); - const onCatalogSetExtraPurchaseParameterEvent = useCallback((event: CatalogSetExtraPurchaseParameterEvent) => - { - if(!currentOffer) return; - - setPurchaseOptions(prevValue => - { - const newValue = { ...prevValue }; - - newValue.extraData = event.parameter; - - return newValue; - }); - }, [ currentOffer, setPurchaseOptions ]); - - UseUiEvent(CatalogWidgetEvent.SET_EXTRA_PARM, onCatalogSetExtraPurchaseParameterEvent); - const onCatalogEvent = useCallback((event: CatalogEvent) => { switch(event.type) @@ -134,7 +118,7 @@ export const CatalogPurchaseWidgetView: FC = pro return () => { setPurchaseState(CatalogPurchaseState.NONE); - setPurchaseOptions({ quantity: 1, extraData: '', extraParamRequired: false, previewStuffData: null }); + setPurchaseOptions({ quantity: 1, extraData: null, extraParamRequired: false, previewStuffData: null }); } }, [ currentOffer, setPurchaseOptions ]); diff --git a/src/components/catalog/views/page/widgets/CatalogSpacesWidgetView.tsx b/src/components/catalog/views/page/widgets/CatalogSpacesWidgetView.tsx index 746a11bb..8ade2a26 100644 --- a/src/components/catalog/views/page/widgets/CatalogSpacesWidgetView.tsx +++ b/src/components/catalog/views/page/widgets/CatalogSpacesWidgetView.tsx @@ -77,10 +77,12 @@ export const CatalogSpacesWidgetView: FC = props = setPurchaseOptions(prevValue => { - const extraData = selectedOfferForGroup[selectedGroupIndex].product.extraParam; - const extraParamRequired = true; + const newValue = { ...prevValue }; + + newValue.extraData = selectedOfferForGroup[selectedGroupIndex].product.extraParam; + newValue.extraParamRequired = true; - return { ...prevValue, extraData, extraParamRequired }; + return newValue; }); }, [ currentOffer, selectedGroupIndex, selectedOfferForGroup, setPurchaseOptions ]); diff --git a/src/components/catalog/views/page/widgets/CatalogSpinnerWidgetView.tsx b/src/components/catalog/views/page/widgets/CatalogSpinnerWidgetView.tsx index 3ba7b7b9..47f8a3a1 100644 --- a/src/components/catalog/views/page/widgets/CatalogSpinnerWidgetView.tsx +++ b/src/components/catalog/views/page/widgets/CatalogSpinnerWidgetView.tsx @@ -24,9 +24,11 @@ export const CatalogSpinnerWidgetView: FC<{}> = props => setPurchaseOptions(prevValue => { - const quantity = value; + const newValue = { ...prevValue }; - return { ...prevValue, quantity }; + newValue.quantity = value; + + return newValue; }); } diff --git a/src/components/inventory/views/badge/InventoryBadgeView.tsx b/src/components/inventory/views/badge/InventoryBadgeView.tsx index 8471d39d..b000e874 100644 --- a/src/components/inventory/views/badge/InventoryBadgeView.tsx +++ b/src/components/inventory/views/badge/InventoryBadgeView.tsx @@ -91,7 +91,7 @@ export const InventoryBadgeView: FC = props => { badge && (badge.length > 0) && - + { LocalizeBadgeName(badge) } diff --git a/src/components/mod-tools/views/user/ModToolsUserModActionView.tsx b/src/components/mod-tools/views/user/ModToolsUserModActionView.tsx index 4c7b9098..8700bd54 100644 --- a/src/components/mod-tools/views/user/ModToolsUserModActionView.tsx +++ b/src/components/mod-tools/views/user/ModToolsUserModActionView.tsx @@ -58,7 +58,10 @@ export const ModToolsUserModActionView: FC = pro const sendDefaultSanction = () => { + let errorMessage: string = null; const category = topics[selectedTopic]; + if(selectedTopic === -1) errorMessage = 'You must select a CFH topic'; + if(errorMessage) return sendAlert(errorMessage); const messageOrDefault = (message.trim().length === 0) ? LocalizeText(`help.cfh.topic.${category.id}`) : message; SendMessageComposer(new DefaultSanctionMessageComposer(user.userId, selectedTopic, messageOrDefault)); onCloseClick(); diff --git a/src/components/room/widgets/avatar-info/AvatarInfoWidgetRentableBotView.tsx b/src/components/room/widgets/avatar-info/AvatarInfoWidgetRentableBotView.tsx index 1aa4f8fd..0822cff9 100644 --- a/src/components/room/widgets/avatar-info/AvatarInfoWidgetRentableBotView.tsx +++ b/src/components/room/widgets/avatar-info/AvatarInfoWidgetRentableBotView.tsx @@ -1,6 +1,6 @@ import { BotCommandConfigurationEvent, BotRemoveComposer, BotSkillSaveComposer, RequestBotCommandConfigurationComposer, RoomObjectCategory, RoomObjectType } from '@nitrots/nitro-renderer'; import { FC, useCallback, useEffect, useState } from 'react'; -import { GetNitroInstance, LocalizeText, RoomWidgetUpdateInfostandRentableBotEvent, RoomWidgetUpdateRentableBotChatEvent, SendMessageComposer } from '../../../../api'; +import { GetConfiguration, GetNitroInstance, LocalizeText, RoomWidgetUpdateInfostandRentableBotEvent, RoomWidgetUpdateRentableBotChatEvent, SendMessageComposer } from '../../../../api'; import { Button, Column, Flex, Text } from '../../../../common'; import { UseMessageEventHook } from '../../../../hooks'; import { useRoomContext } from '../../RoomContext'; @@ -182,7 +182,7 @@ export const AvatarInfoWidgetRentableBotView: FC { LocalizeText('bot.skill.name.configuration.new.name') } - setNewName(event.target.value) } /> + ('bot.name.max.length', 15) } onChange={ event => setNewName(event.target.value) } /> @@ -191,7 +191,7 @@ export const AvatarInfoWidgetRentableBotView: FC { LocalizeText('bot.skill.name.configuration.new.motto') } - setNewMotto(event.target.value) } /> + ('motto.max.legnth', 38) } onChange={ event => setNewMotto(event.target.value) } /> diff --git a/src/components/room/widgets/context-menu/ContextMenuView.tsx b/src/components/room/widgets/context-menu/ContextMenuView.tsx index 7a10c8ee..3583d521 100644 --- a/src/components/room/widgets/context-menu/ContextMenuView.tsx +++ b/src/components/room/widgets/context-menu/ContextMenuView.tsx @@ -28,7 +28,7 @@ export const ContextMenuView: FC = props => const [ opacity, setOpacity ] = useState(1); const [ isFading, setIsFading ] = useState(false); const [ fadeTime, setFadeTime ] = useState(0); - const [ frozen, setFrozen ] = useState(false); + const [ isFrozen, setIsFrozen ] = useState(false); const elementRef = useRef(); const getOffset = useCallback((bounds: NitroRectangle) => @@ -156,7 +156,7 @@ export const ContextMenuView: FC = props => { let added = false; - if(!frozen) + if(!isFrozen) { added = true; @@ -167,7 +167,7 @@ export const ContextMenuView: FC = props => { if(added) GetTicker().remove(update); } - }, [ frozen, update ]); + }, [ isFrozen, update ]); useEffect(() => { @@ -178,5 +178,5 @@ export const ContextMenuView: FC = props => return () => clearTimeout(timeout); }, [ fades ]); - return ; + return setIsFrozen(true) } onMouseOut={ event => setIsFrozen(false) } { ...rest } />; } diff --git a/src/components/room/widgets/infostand/InfoStandWidgetUserView.tsx b/src/components/room/widgets/infostand/InfoStandWidgetUserView.tsx index 60b97b31..6846e60d 100644 --- a/src/components/room/widgets/infostand/InfoStandWidgetUserView.tsx +++ b/src/components/room/widgets/infostand/InfoStandWidgetUserView.tsx @@ -25,7 +25,7 @@ export const InfoStandWidgetUserView: FC = props = const saveMotto = (motto: string) => { - if(!isEditingMotto || (motto.length > 38)) return; + if(!isEditingMotto || (motto.length > GetConfiguration('motto.max.legnth', 38))) return; widgetHandler.processWidgetMessage(new RoomWidgetChangeMottoMessage(motto)); @@ -195,7 +195,7 @@ export const InfoStandWidgetUserView: FC = props = { !isEditingMotto && setIsEditingMotto(true) }>{ motto }  } { isEditingMotto && - setMotto(event.target.value) } onBlur={ onMottoBlur } onKeyDown={ onMottoKeyDown } autoFocus={ true } /> } + ('motto.max.legnth', 38) } value={ motto } onChange={ event => setMotto(event.target.value) } onBlur={ onMottoBlur } onKeyDown={ onMottoKeyDown } autoFocus={ true } /> } } diff --git a/src/components/room/widgets/room-tools/RoomToolsWidgetView.tsx b/src/components/room/widgets/room-tools/RoomToolsWidgetView.tsx index b35cd7bd..451e3b4f 100644 --- a/src/components/room/widgets/room-tools/RoomToolsWidgetView.tsx +++ b/src/components/room/widgets/room-tools/RoomToolsWidgetView.tsx @@ -9,12 +9,12 @@ import { useRoomContext } from '../../RoomContext'; export const RoomToolsWidgetView: FC<{}> = props => { - const [ isZoomedIn, setIsZoomedIn ] = useState(false); - const [ roomName, setRoomName ] = useState(null); - const [ roomOwner, setRoomOwner ] = useState(null); - const [ roomTags, setRoomTags ] = useState(null); - const [ roomInfoDisplay, setRoomInfoDisplay ] = useState(false); - const [ isOpen, setIsOpen ] = useState(false); + const [ isZoomedIn, setIsZoomedIn ] = useState(false); + const [ roomName, setRoomName ] = useState(null); + const [ roomOwner, setRoomOwner ] = useState(null); + const [ roomTags, setRoomTags ] = useState(null); + const [ roomInfoDisplay, setRoomInfoDisplay ] = useState(false); + const [ isOpen, setIsOpen ] = useState(false); const [ navigatorData, setNavigatorData ] = useSharedState('@navigatorData'); const { widgetHandler = null } = useRoomContext(); @@ -85,7 +85,7 @@ export const RoomToolsWidgetView: FC<{}> = props => { roomTags && roomTags.length > 0 && - { roomTags.map((tag: string) => #{ tag }) } + { roomTags.map((tag, index) => #{ tag }) } } diff --git a/src/events/catalog/CatalogSetExtraPurchaseParameterEvent.ts b/src/events/catalog/CatalogSetExtraPurchaseParameterEvent.ts deleted file mode 100644 index d7f9ca8d..00000000 --- a/src/events/catalog/CatalogSetExtraPurchaseParameterEvent.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { NitroEvent } from '@nitrots/nitro-renderer'; -import { CatalogWidgetEvent } from './CatalogWidgetEvent'; - -export class CatalogSetExtraPurchaseParameterEvent extends NitroEvent -{ - private _parameter: string; - - constructor(parameter: string) - { - super(CatalogWidgetEvent.SET_EXTRA_PARM); - - this._parameter = parameter; - } - - public get parameter(): string - { - return this._parameter; - } -} diff --git a/src/events/catalog/index.ts b/src/events/catalog/index.ts index ff38a456..1e2cd919 100644 --- a/src/events/catalog/index.ts +++ b/src/events/catalog/index.ts @@ -9,7 +9,6 @@ export * from './CatalogPurchaseFailureEvent'; export * from './CatalogPurchaseNotAllowedEvent'; export * from './CatalogPurchaseOverrideEvent'; export * from './CatalogPurchaseSoldOutEvent'; -export * from './CatalogSetExtraPurchaseParameterEvent'; export * from './CatalogSetRoomPreviewerStuffDataEvent'; export * from './CatalogWidgetEvent'; export * from './SetRoomPreviewerStuffDataEvent';