From 40f43900101cc3dcab88e4af01d305bc8bee4300 Mon Sep 17 00:00:00 2001 From: brenoepics Date: Fri, 18 Mar 2022 17:41:17 +0000 Subject: [PATCH 01/58] add relative paths --- package.json | 1 + public/index.html | 1 + 2 files changed, 2 insertions(+) diff --git a/package.json b/package.json index c03ac7f7..195a948d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,7 @@ { "name": "nitro-react", "version": "2.0.0", + "homepage": ".", "private": true, "scripts": { "start": "cross-env BROWSER=none IMAGE_INLINE_SIZE_LIMIT=100000 craco start", diff --git a/public/index.html b/public/index.html index 04f4d7b3..7898a6da 100644 --- a/public/index.html +++ b/public/index.html @@ -15,6 +15,7 @@ + Nitro From 55698a006e6b0192d488fdac6afcb373524eeecf Mon Sep 17 00:00:00 2001 From: laynester Date: Fri, 5 Aug 2022 02:01:44 -0400 Subject: [PATCH 02/58] tab icons, navigation indent, catalog headers --- public/ui-config.json.example | 2 + src/components/catalog/CatalogView.scss | 46 +++++++++++++------ src/components/catalog/CatalogView.tsx | 16 ++++--- .../catalog-header/CatalogHeaderView.tsx | 33 +++++++++++++ .../navigation/CatalogNavigationItemView.tsx | 13 +++--- .../navigation/CatalogNavigationSetView.tsx | 5 +- .../page/layout/CatalogLayoutDefaultView.tsx | 26 ++++++----- 7 files changed, 101 insertions(+), 40 deletions(-) create mode 100644 src/components/catalog/views/catalog-header/CatalogHeaderView.tsx diff --git a/public/ui-config.json.example b/public/ui-config.json.example index 403bb68a..863d4609 100644 --- a/public/ui-config.json.example +++ b/public/ui-config.json.example @@ -120,6 +120,8 @@ "catalog.asset.url": "${image.library.url}catalogue", "catalog.asset.image.url": "${catalog.asset.url}/%name%.gif", "catalog.asset.icon.url": "${catalog.asset.url}/icon_%name%.png", + "catalog.tab.icons": false, + "catalog.headers": false, "chat.input.maxlength": 100, "chat.styles.disabled": [], "chat.styles": [ diff --git a/src/components/catalog/CatalogView.scss b/src/components/catalog/CatalogView.scss index 4101cd13..dde64cfc 100644 --- a/src/components/catalog/CatalogView.scss +++ b/src/components/catalog/CatalogView.scss @@ -2,7 +2,7 @@ width: $catalog-width; height: $catalog-height; - font[size='16'] { + font[size="16"] { font-size: 20px; } @@ -22,7 +22,7 @@ .nitro-catalog-gift { width: 325px; - + .gift-preview { width: 80px; height: 80px; @@ -37,15 +37,24 @@ } .nitro-catalog-navigation-grid-container { - border-color: #B6BEC5 !important; - background-color: #CDD3D9; + border-color: #b6bec5 !important; + background-color: #cdd3d9; border: 2px solid; + .nitro-catalog-navigation-section { + display: grid; + + .nitro-catalog-navigation-section { + padding-left: 5px; + border-left: 2px solid #b6bec5; + } + } + .layout-grid-item { font-size: $font-size-sm; height: 23px !important; border-color: unset !important; - background-color: #CDD3D9; + background-color: #cdd3d9; border: 0 !important; padding: 1px 3px; @@ -58,23 +67,21 @@ } .nitro-catalog-layout-info-loyalty { - .info-loyalty-content { background-repeat: no-repeat; background-position: top right; - background-image: url('../../assets/images/catalog/diamond_info_illustration.gif'); - padding-right:123px; + background-image: url("../../assets/images/catalog/diamond_info_illustration.gif"); + padding-right: 123px; } .info-image { width: 123px; - height:350px; - background-image: url('../../assets/images/catalog/diamond_info_illustration.gif'); + height: 350px; + background-image: url("../../assets/images/catalog/diamond_info_illustration.gif"); } } .nitro-catalog-layout-vip-buy-grid { - .layout-grid-item { height: 50px !important; max-height: 50px !important; @@ -82,20 +89,19 @@ .icon-hc-banner { width: 68px; height: 40px; - background: url('../../assets/images/catalog/hc_big.png') center no-repeat; + background: url("../../assets/images/catalog/hc_big.png") center + no-repeat; } } } .nitro-catalog-layout-marketplace-grid { - .layout-grid-item { height: 75px !important; } } .nitro-catalog-layout-vip-gifts-grid { - .layout-grid-item { height: 55px !important; max-height: 55px !important; @@ -108,8 +114,18 @@ } .nitro-catalog-layout-bundle-grid { - .layout-grid-item { background-color: transparent; } } + +.nitro-catalog-header { + width: 290px; + height: 60px; + align-self: center; + + display: flex; + justify-content: center; + overflow: hidden; + flex-shrink: 0; +} diff --git a/src/components/catalog/CatalogView.tsx b/src/components/catalog/CatalogView.tsx index 3af9b189..f15fe8d2 100644 --- a/src/components/catalog/CatalogView.tsx +++ b/src/components/catalog/CatalogView.tsx @@ -1,8 +1,9 @@ import { ILinkEventTracker } from '@nitrots/nitro-renderer'; import { FC, useEffect } from 'react'; -import { AddEventLinkTracker, LocalizeText, RemoveLinkEventTracker } from '../../api'; -import { Column, Grid, NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../common'; +import { AddEventLinkTracker, GetConfiguration, LocalizeText, RemoveLinkEventTracker } from '../../api'; +import { Column, Flex, Grid, NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../common'; import { useCatalog } from '../../hooks'; +import { CatalogIconView } from './views/catalog-icon/CatalogIconView'; import { CatalogGiftView } from './views/gift/CatalogGiftView'; import { CatalogNavigationView } from './views/navigation/CatalogNavigationView'; import { GetCatalogLayout } from './views/page/layout/GetCatalogLayout'; @@ -10,7 +11,7 @@ import { MarketplacePostOfferView } from './views/page/layout/marketplace/Market export const CatalogView: FC<{}> = props => { - const { isVisible = false, setIsVisible = null, rootNode = null, currentPage = null, navigationHidden = false, setNavigationHidden = null, activeNodes = [], searchResult = null, setSearchResult = null, openPageByName = null, openPageByOfferId = null, activateNode = null } = useCatalog(); + const { isVisible = false, setIsVisible = null, rootNode = null, currentPage = null, navigationHidden = false, setNavigationHidden = null, activeNodes = [], searchResult = null, setSearchResult = null, openPageByName = null, openPageByOfferId = null, activateNode = null, getNodeById } = useCatalog(); useEffect(() => { @@ -68,7 +69,7 @@ export const CatalogView: FC<{}> = props => return ( <> { isVisible && - + setIsVisible(false) } /> { rootNode && (rootNode.children.length > 0) && rootNode.children.map(child => @@ -81,8 +82,11 @@ export const CatalogView: FC<{}> = props => if(searchResult) setSearchResult(null); activateNode(child); - } }> - { child.localization } + } } > + + { GetConfiguration('catalog.tab.icons') && } + { child.localization } + ); }) } diff --git a/src/components/catalog/views/catalog-header/CatalogHeaderView.tsx b/src/components/catalog/views/catalog-header/CatalogHeaderView.tsx new file mode 100644 index 00000000..e6f02bc2 --- /dev/null +++ b/src/components/catalog/views/catalog-header/CatalogHeaderView.tsx @@ -0,0 +1,33 @@ +import { FC, useEffect, useMemo, useRef } from 'react'; +import { GetConfiguration } from '../../../../api'; +import { Base } from '../../../../common'; + +export interface CatalogHeaderViewProps +{ + image?: string; +} + +export const CatalogHeaderView: FC = props => +{ + let { image = null } = props; + + const imageEl = useRef(); + + const fallback = useMemo(()=> + { + return ((GetConfiguration('catalog.asset.image.url')).replace('%name%', 'catalog_header_roombuilder')); + },[]) + + useEffect(()=> + { + if(image == null && imageEl !== null) imageEl.current.src = fallback; + },[ image, imageEl,fallback ]) + + return + + { + currentTarget.src = fallback; + } + } /> + ; +} diff --git a/src/components/catalog/views/navigation/CatalogNavigationItemView.tsx b/src/components/catalog/views/navigation/CatalogNavigationItemView.tsx index 5eb1c45c..9179edba 100644 --- a/src/components/catalog/views/navigation/CatalogNavigationItemView.tsx +++ b/src/components/catalog/views/navigation/CatalogNavigationItemView.tsx @@ -1,7 +1,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { FC } from 'react'; import { ICatalogNode } from '../../../../api'; -import { LayoutGridItem, Text } from '../../../../common'; +import { Base, LayoutGridItem, Text } from '../../../../common'; import { useCatalog } from '../../../../hooks'; import { CatalogIconView } from '../catalog-icon/CatalogIconView'; import { CatalogNavigationSetView } from './CatalogNavigationSetView'; @@ -9,23 +9,24 @@ import { CatalogNavigationSetView } from './CatalogNavigationSetView'; export interface CatalogNavigationItemViewProps { node: ICatalogNode; + child?: boolean; } export const CatalogNavigationItemView: FC = props => { - const { node = null } = props; + const { node = null, child = false } = props; const { activateNode = null } = useCatalog(); return ( - <> - activateNode(node) }> + + activateNode(node) } className={ child ? 'inset' : '' }> { node.localization } { node.isBranch && } { node.isOpen && node.isBranch && - } - + } + ); } diff --git a/src/components/catalog/views/navigation/CatalogNavigationSetView.tsx b/src/components/catalog/views/navigation/CatalogNavigationSetView.tsx index 19f71f47..8bfdd480 100644 --- a/src/components/catalog/views/navigation/CatalogNavigationSetView.tsx +++ b/src/components/catalog/views/navigation/CatalogNavigationSetView.tsx @@ -5,11 +5,12 @@ import { CatalogNavigationItemView } from './CatalogNavigationItemView'; export interface CatalogNavigationSetViewProps { node: ICatalogNode; + child?: boolean; } export const CatalogNavigationSetView: FC = props => { - const { node = null } = props; + const { node = null, child = false } = props; return ( <> @@ -17,7 +18,7 @@ export const CatalogNavigationSetView: FC = props { if(!n.isVisible) return null; - return + return }) } ); diff --git a/src/components/catalog/views/page/layout/CatalogLayoutDefaultView.tsx b/src/components/catalog/views/page/layout/CatalogLayoutDefaultView.tsx index 262685ae..adde3fb8 100644 --- a/src/components/catalog/views/page/layout/CatalogLayoutDefaultView.tsx +++ b/src/components/catalog/views/page/layout/CatalogLayoutDefaultView.tsx @@ -1,7 +1,8 @@ import { FC } from 'react'; -import { ProductTypeEnum } from '../../../../../api'; +import { GetConfiguration, ProductTypeEnum } from '../../../../../api'; import { Column, Flex, Grid, Text } from '../../../../../common'; import { useCatalog } from '../../../../../hooks'; +import { CatalogHeaderView } from '../../catalog-header/CatalogHeaderView'; import { CatalogAddOnBadgeWidgetView } from '../widgets/CatalogAddOnBadgeWidgetView'; import { CatalogItemGridWidgetView } from '../widgets/CatalogItemGridWidgetView'; import { CatalogLimitedItemWidgetView } from '../widgets/CatalogLimitedItemWidgetView'; @@ -14,20 +15,22 @@ import { CatalogLayoutProps } from './CatalogLayout.types'; export const CatalogLayoutDefaultView: FC = props => { const { page = null } = props; - const { currentOffer = null } = useCatalog(); + const { currentOffer = null,currentPage } = useCatalog(); return ( - - - - - - { !currentOffer && + <> + + + { GetConfiguration('catalog.headers') && } + + + + { !currentOffer && <> { !!page.localization.getImage(1) && } } - { currentOffer && + { currentOffer && <> { (currentOffer.product.productType !== ProductTypeEnum.BADGE) && @@ -49,7 +52,8 @@ export const CatalogLayoutDefaultView: FC = props => } - - + + + ); } From c0d57e81667e667dce37116fdac5b7f3f3d9fbdd Mon Sep 17 00:00:00 2001 From: object Date: Fri, 5 Aug 2022 23:01:59 +0000 Subject: [PATCH 03/58] Fix auto-scroll helper chat (Issue #208) --- .../guide-tool/views/GuideToolOngoingView.tsx | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/components/guide-tool/views/GuideToolOngoingView.tsx b/src/components/guide-tool/views/GuideToolOngoingView.tsx index 7dd01850..080de332 100644 --- a/src/components/guide-tool/views/GuideToolOngoingView.tsx +++ b/src/components/guide-tool/views/GuideToolOngoingView.tsx @@ -1,5 +1,5 @@ import { GuideSessionGetRequesterRoomMessageComposer, GuideSessionInviteRequesterMessageComposer, GuideSessionMessageMessageComposer, GuideSessionRequesterRoomMessageEvent, GuideSessionResolvedMessageComposer } from '@nitrots/nitro-renderer'; -import { FC, KeyboardEvent, useCallback, useState } from 'react'; +import { FC, KeyboardEvent, useCallback, useEffect, useRef, useState } from 'react'; import { GetSessionDataManager, GuideToolMessageGroup, LocalizeText, SendMessageComposer, TryVisitRoom } from '../../../api'; import { Base, Button, ButtonGroup, Column, Flex, LayoutAvatarImageView, Text } from '../../../common'; import { useMessageEvent } from '../../../hooks'; @@ -16,10 +16,18 @@ interface GuideToolOngoingViewProps export const GuideToolOngoingView: FC = props => { + const scrollDiv = useRef(null); + const { isGuide = false, userId = 0, userName = null, userFigure = null, isTyping = false, messageGroups = [] } = props; const [ messageText, setMessageText ] = useState(''); + useEffect(() => + { + scrollDiv.current?.scrollIntoView({ block: 'end', behavior: 'smooth' }); + + }, [ messageGroups ]); + const visit = useCallback(() => { SendMessageComposer(new GuideSessionGetRequesterRoomMessageComposer()); @@ -38,7 +46,7 @@ export const GuideToolOngoingView: FC = props => useMessageEvent(GuideSessionRequesterRoomMessageEvent, event => { const parser = event.getParser(); - + TryVisitRoom(parser.requesterRoomId); }); @@ -100,7 +108,8 @@ export const GuideToolOngoingView: FC = props => } ); - }) } + }) } +
From d5361ef5b39a2f152636d605406bec8d60565a9e Mon Sep 17 00:00:00 2001 From: object Date: Sat, 6 Aug 2022 01:16:30 +0000 Subject: [PATCH 04/58] Fix prevent zalgo-text (Issue #23) --- .../room/widgets/chat-input/ChatInputView.tsx | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/components/room/widgets/chat-input/ChatInputView.tsx b/src/components/room/widgets/chat-input/ChatInputView.tsx index dcfb514e..b474378d 100644 --- a/src/components/room/widgets/chat-input/ChatInputView.tsx +++ b/src/components/room/widgets/chat-input/ChatInputView.tsx @@ -89,6 +89,15 @@ export const ChatInputView: FC<{}> = props => if(text.length <= maxChatLength) { + const re = /%CC%/g + const hasZalgo = txt => re.test(encodeURIComponent(txt)); + + if (hasZalgo(text)) + { + setChatValue(''); + return; + } + setChatValue(''); sendChat(text, chatType, recipientName, chatStyleId); } @@ -141,7 +150,7 @@ export const ChatInputView: FC<{}> = props => } return; } - + }, [ floodBlocked, inputRef, chatModeIdWhisper, anotherInputHasFocus, setInputFocus, checkSpecialKeywordForInput, sendChatValue ]); useUiEvent(RoomWidgetUpdateChatInputContentEvent.CHAT_INPUT_CONTENT, event => From 9ac3e977dc3a9ed789814a1b8347887c230075c9 Mon Sep 17 00:00:00 2001 From: object Date: Sat, 6 Aug 2022 13:19:16 +0000 Subject: [PATCH 05/58] Fix feature #238 - Inventory (badges) --- .../inventory/views/badge/InventoryBadgeItemView.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/inventory/views/badge/InventoryBadgeItemView.tsx b/src/components/inventory/views/badge/InventoryBadgeItemView.tsx index e5bfb71c..bb6c54af 100644 --- a/src/components/inventory/views/badge/InventoryBadgeItemView.tsx +++ b/src/components/inventory/views/badge/InventoryBadgeItemView.tsx @@ -6,14 +6,14 @@ import { useInventoryBadges, useInventoryUnseenTracker } from '../../../../hooks export const InventoryBadgeItemView: FC> = props => { const { badgeCode = null, children = null, ...rest } = props; - const { selectedBadgeCode = null, setSelectedBadgeCode = null, getBadgeId = null } = useInventoryBadges(); + const { selectedBadgeCode = null, setSelectedBadgeCode = null, toggleBadge = null, getBadgeId = null } = useInventoryBadges(); const { isUnseen = null } = useInventoryUnseenTracker(); const unseen = isUnseen(UnseenItemCategory.BADGE, getBadgeId(badgeCode)); return ( - setSelectedBadgeCode(badgeCode) } { ...rest }> + setSelectedBadgeCode(badgeCode) } onDoubleClick={ event => toggleBadge(selectedBadgeCode) } { ...rest }> { children } ); -} +} \ No newline at end of file From bba59686defd9e3ef276e4a0fbd4077ff363c1e2 Mon Sep 17 00:00:00 2001 From: object Date: Sat, 6 Aug 2022 13:30:14 +0000 Subject: [PATCH 06/58] Fix feature #238 - Inventory (bots) --- src/components/inventory/views/bot/InventoryBotItemView.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/inventory/views/bot/InventoryBotItemView.tsx b/src/components/inventory/views/bot/InventoryBotItemView.tsx index d2a15cf4..d2130693 100644 --- a/src/components/inventory/views/bot/InventoryBotItemView.tsx +++ b/src/components/inventory/views/bot/InventoryBotItemView.tsx @@ -26,13 +26,16 @@ export const InventoryBotItemView: FC> case MouseEventType.ROLL_OUT: if(!isMouseDown || (selectedBot !== botItem)) return; + attemptBotPlacement(botItem); + return; + case 'dblclick': attemptBotPlacement(botItem); return; } } return ( - + { children } From 688ca3c32bf1fc88055ca7c3ec88f95f29078748 Mon Sep 17 00:00:00 2001 From: object Date: Sat, 6 Aug 2022 13:33:46 +0000 Subject: [PATCH 07/58] Fix feature #238 - Inventory (items) --- .../inventory/views/furniture/InventoryFurnitureItemView.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/inventory/views/furniture/InventoryFurnitureItemView.tsx b/src/components/inventory/views/furniture/InventoryFurnitureItemView.tsx index f72c6ab5..f5e84814 100644 --- a/src/components/inventory/views/furniture/InventoryFurnitureItemView.tsx +++ b/src/components/inventory/views/furniture/InventoryFurnitureItemView.tsx @@ -24,6 +24,9 @@ export const InventoryFurnitureItemView: FC<{ groupItem: GroupItem }> = props => case MouseEventType.ROLL_OUT: if(!isMouseDown || !(groupItem === selectedItem)) return; + attemptItemPlacement(groupItem); + return; + case 'dblclick': attemptItemPlacement(groupItem); return; } @@ -31,5 +34,5 @@ export const InventoryFurnitureItemView: FC<{ groupItem: GroupItem }> = props => const count = groupItem.getUnlockedCount(); - return ; + return ; } From 2318e27781f4342d891018afd24ccb80816e3e91 Mon Sep 17 00:00:00 2001 From: object Date: Sat, 6 Aug 2022 13:36:55 +0000 Subject: [PATCH 08/58] Fix feature #238 - Inventory (pets) --- .../inventory/views/pet/InventoryPetItemView.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/components/inventory/views/pet/InventoryPetItemView.tsx b/src/components/inventory/views/pet/InventoryPetItemView.tsx index 41b0619e..aad45f95 100644 --- a/src/components/inventory/views/pet/InventoryPetItemView.tsx +++ b/src/components/inventory/views/pet/InventoryPetItemView.tsx @@ -26,13 +26,16 @@ export const InventoryPetItemView: FC> case MouseEventType.ROLL_OUT: if(!isMouseDown || !(petItem === selectedPet)) return; + attemptPetPlacement(petItem); + return; + case 'dblclick': attemptPetPlacement(petItem); return; } } - + return ( - + { children } From 7929866c334192a83247ed3b27898a388ebcb83f Mon Sep 17 00:00:00 2001 From: object Date: Sat, 6 Aug 2022 16:55:10 +0000 Subject: [PATCH 09/58] Add new funcionality for stickies notes ! --- .../furniture/FurnitureStickieView.tsx | 30 ++++++++++++++----- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/src/components/room/widgets/furniture/FurnitureStickieView.tsx b/src/components/room/widgets/furniture/FurnitureStickieView.tsx index cfa23e26..2f0e0fee 100644 --- a/src/components/room/widgets/furniture/FurnitureStickieView.tsx +++ b/src/components/room/widgets/furniture/FurnitureStickieView.tsx @@ -5,6 +5,8 @@ import { useFurnitureStickieWidget } from '../../../../hooks'; const STICKIE_COLORS = [ '9CCEFF','FF9CFF', '9CFF9C','FFFF33' ]; const STICKIE_COLOR_NAMES = [ 'blue', 'pink', 'green', 'yellow' ]; +const STICKIE_TYPES = [ 'post_it','post_it_shakesp', 'post_it_dreams','post_it_xmas', 'post_it_vd', 'post_it_juninas' ]; +const STICKIE_TYPE_NAMES = [ 'post_it', 'shakesp', 'dreams', 'christmas', 'heart', 'juninas' ]; const getStickieColorName = (color: string) => { @@ -15,30 +17,42 @@ const getStickieColorName = (color: string) => return STICKIE_COLOR_NAMES[index]; } +const getStickieTypeName = (type: string) => +{ + let index = STICKIE_TYPES.indexOf(type); + + if(index === -1) index = 0; + + return STICKIE_TYPE_NAMES[index]; +} + export const FurnitureStickieView: FC<{}> = props => { - const { objectId = -1, color = '0', text = '', canModify = false, updateColor = null, updateText = null, trash = null, onClose = null } = useFurnitureStickieWidget(); + const { objectId = -1, color = '0', text = '', type = '', canModify = false, updateColor = null, updateText = null, trash = null, onClose = null } = useFurnitureStickieWidget(); const [ isEditing, setIsEditing ] = useState(false); useEffect(() => { setIsEditing(false); - }, [ objectId, color, text ]); + }, [ objectId, color, text, type ]); if(objectId === -1) return null; return ( -
+
- { canModify && + { canModify && <>
- { STICKIE_COLORS.map(color => - { - return
updateColor(color) } style={ { backgroundColor: ColorUtils.makeColorHex(color) } } /> - }) } + { type == 'post_it' && + <> + { STICKIE_COLORS.map(color => + { + return
updateColor(color) } style={ { backgroundColor: ColorUtils.makeColorHex(color) } } /> + }) } + } }
From ff8af8d902dd86b42595351bb05db41b6d2f1c4a Mon Sep 17 00:00:00 2001 From: object Date: Sat, 6 Aug 2022 16:57:32 +0000 Subject: [PATCH 10/58] Add new scss images for stickies notes --- .../widgets/furniture/FurnitureWidgets.scss | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/components/room/widgets/furniture/FurnitureWidgets.scss b/src/components/room/widgets/furniture/FurnitureWidgets.scss index a129da04..e7d8bdf2 100644 --- a/src/components/room/widgets/furniture/FurnitureWidgets.scss +++ b/src/components/room/widgets/furniture/FurnitureWidgets.scss @@ -161,6 +161,26 @@ background-position: -2px -184px; } + &.stickie-christmas { + background-image: url("../../../../assets/images/room-widgets/stickie-widget/stickie-christmas.png"); + } + + &.stickie-shakesp { + background-image: url("../../../../assets/images/room-widgets/stickie-widget/stickie-shakesp.png"); + } + + &.stickie-dreams { + background-image: url("../../../../assets/images/room-widgets/stickie-widget/stickie-dreams.png"); + } + + &.stickie-heart { + background-image: url("../../../../assets/images/room-widgets/stickie-widget/stickie-heart.png"); + } + + &.stickie-juninas { + background-image: url("../../../../assets/images/room-widgets/stickie-widget/stickie-juninas.png"); + } + &.stickie-close { width: 10px; height: 10px; @@ -202,7 +222,7 @@ font-weight: bold; font-size: 16px; text-shadow: 0px 1px white; - + &.engraving-lock-3 { background-position: 0px -210px; color: #614110; @@ -262,7 +282,7 @@ .youtube-video-container { //min-height: 366px; - + .empty-video { background-color: black; color: white; From c3776e7d7cad17e4d3f86866f90026b92475ccab Mon Sep 17 00:00:00 2001 From: object Date: Sat, 6 Aug 2022 17:02:54 +0000 Subject: [PATCH 11/58] New hook 'type' for stickie notes ! --- .../rooms/widgets/furniture/useFurnitureStickieWidget.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/hooks/rooms/widgets/furniture/useFurnitureStickieWidget.ts b/src/hooks/rooms/widgets/furniture/useFurnitureStickieWidget.ts index f1e89134..7cc15975 100644 --- a/src/hooks/rooms/widgets/furniture/useFurnitureStickieWidget.ts +++ b/src/hooks/rooms/widgets/furniture/useFurnitureStickieWidget.ts @@ -10,6 +10,7 @@ const useFurnitureStickieWidgetState = () => const [ category, setCategory ] = useState(-1); const [ color, setColor ] = useState('0'); const [ text, setText ] = useState(''); + const [ type, setType ] = useState(''); const [ canModify, setCanModify ] = useState(false); const onClose = () => @@ -18,6 +19,7 @@ const useFurnitureStickieWidgetState = () => setCategory(-1); setColor('0'); setText(''); + setType(''); setCanModify(false); } @@ -44,7 +46,7 @@ const useFurnitureStickieWidgetState = () => const roomObject = GetRoomEngine().getRoomObject(event.roomId, event.objectId, event.category); if(!roomObject) return; - + const data = roomObject.model.getValue(RoomObjectVariable.FURNITURE_ITEMDATA); if(data.length < 6) return; @@ -66,6 +68,7 @@ const useFurnitureStickieWidgetState = () => setCategory(event.category); setColor(color || '0'); setText(text || ''); + setType(roomObject.type || 'post_it'); setCanModify(GetRoomSession().isRoomOwner || GetSessionDataManager().isModerator || IsOwnerOfFurniture(roomObject)); }); @@ -76,7 +79,7 @@ const useFurnitureStickieWidgetState = () => onClose(); }); - return { objectId, color, text, canModify, updateColor, updateText, trash, onClose }; + return { objectId, color, text, type, canModify, updateColor, updateText, trash, onClose }; } export const useFurnitureStickieWidget = useFurnitureStickieWidgetState; From 64c818d3782b6b8b65682c336fc9884996391c43 Mon Sep 17 00:00:00 2001 From: object Date: Sat, 6 Aug 2022 17:05:23 +0000 Subject: [PATCH 12/58] Dreams stickie note --- .../stickie-widget/stickie-dreams.png | Bin 0 -> 5095 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/assets/images/room-widgets/stickie-widget/stickie-dreams.png diff --git a/src/assets/images/room-widgets/stickie-widget/stickie-dreams.png b/src/assets/images/room-widgets/stickie-widget/stickie-dreams.png new file mode 100644 index 0000000000000000000000000000000000000000..27ccbdbc517971bc7f7bfce785dc7f001c6ccdcb GIT binary patch literal 5095 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 Date: Sat, 6 Aug 2022 17:05:54 +0000 Subject: [PATCH 13/58] Juninas stickie note --- .../stickie-widget/stickie-juninas.png | Bin 0 -> 405 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/assets/images/room-widgets/stickie-widget/stickie-juninas.png diff --git a/src/assets/images/room-widgets/stickie-widget/stickie-juninas.png b/src/assets/images/room-widgets/stickie-widget/stickie-juninas.png new file mode 100644 index 0000000000000000000000000000000000000000..1d64ddab7162122bab7cb7163ef626a0d6199041 GIT binary patch literal 405 zcmeAS@N?(olHy`uVBq!ia0vp^JArr;2Q!e=+%j)1kYX$ja(7}_cTVOdki(Mh=|1&sftpxEo3p^r=85sBu zfiR<}hF1g7U?xu&$B>G+x91M#0>xPzJAS{Hbe4I<6=s$BZRh$*p6_>h_VlB`{HTAM zB`f6z6}&&~&y{<--#M7S`dpZE%Kyi*KfLp&)IaF{6#rwvpQiUG|34`Hq+jFvk6(WB r{Rh#XtZTgM+UI{-sP}pI;|j)`7VrKhD+qN0gNVV?)z4*}Q$iB}f)JJQ literal 0 HcmV?d00001 From e581fd23d5a899d56fe822a20dd23167eae602ad Mon Sep 17 00:00:00 2001 From: object Date: Sat, 6 Aug 2022 17:06:19 +0000 Subject: [PATCH 14/58] Shakesp stickie note --- .../stickie-widget/stickie-shakesp.png | Bin 0 -> 5036 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/assets/images/room-widgets/stickie-widget/stickie-shakesp.png diff --git a/src/assets/images/room-widgets/stickie-widget/stickie-shakesp.png b/src/assets/images/room-widgets/stickie-widget/stickie-shakesp.png new file mode 100644 index 0000000000000000000000000000000000000000..d5011c74b29bd0641a0c9897c207903d63a3491c GIT binary patch literal 5036 zcmc&YcQ_nQusTr^AtFlDQ=&#f^cr`ZIPFgFLO7i}L{B2oTM#|Eb4b)g^bon|<%l2% z?#?;AM3iXHFaN)P-`j6yXJ===o!Qy>cJ|viBLf{KdQN&WGBPHxuC~b~ZMnn-I?Bub z&WD2cmxLT)qN7DtGs3-k$xyj!LNv+9>Qfj_9jPy63P$=c;N|?r*Z7q(b3DolcM0W| zONA!5GK<9m`Gg%zp7da($)RA91LU_vOjTq(C)t+FFkUMkp; zs_a(KHpEi%l`@N!atk8Lf`qmumRY>>m1zpSw^RrnNqI=9u)!BW3B@o%F?9LA#jS}I zmtcc0fz1^{XR;x`iebxT7C+w_6H3i~Wa`i78!wl@2qk8dZ}g_~42ftPLJ4d(*KoPi zbQx_sodsDz+b)-w5=u;om$pz=3ngYal;ujL-C~)=a=GO~0dzjkXfg-#JsrGI2pdn+ z9ZLa@zX4-kgT~%~hmy2LQbCtNV?&K#E{Pk`!~lBnf78f#H_jei+PvbcYl$EuyV~;~ zlK1+coyo|q$APsqVNdNgb5G1?LBGD8teL>SqNfv`8D>6uFfjNyL2tPNEaj$&nOgd~ z9s_xGfV|Yy^NWjaHNm!7@5p)G6#}=a?4q?&A&2ThUZ1>u{rUDf3~bk~w}&%LW3NqX zfBJ@isRl^f2?g(p^(Rc3Lu$g_UJlIvcb)$~QTQaG3Kdz+g#y20a`#vZT6+Sl^xqX2=7{{8Jtqb0$B8X=Q20d`_p9TAL8Zjtfy3F(Pj-U5 z&-2}F?@wdl(qp;~meznGWO^F&Iwb}k{BG;cQ-aKfCcG}Xv^n`CYGT(mMzKxbkHd|t z&5rlv_nMu@EJEp{8VT_RFva9fVJ@OQi3TyTlKy7m6pO!bIt2NBb#NIv?oIy@NcZap zYm;@)x1Ak$6jR+p%%KVqe}B)GyHmxt>7Ng1;>~#(aplbSERWOoC0MfAdVbFl#{#TF zuj;diDU8&uM&~G6ENm+b7jJhPZb8BQ5nT`Fa;qDy%CIvpoEW)d&HkZlKAch zG16Cibkn#P-k1vT%jTaAvi*Fe=cPg4U;P=xdR^m+noB(X=-0LIjcu~5^4hK?ukwB^ zVk^(k=YO79n>tmYAQX}$mT|7#*Db7Jk5tI`DGpV7&E4b2xtlBp5gy^!MpYJ`uipOQ z7AnbnKwC5J^h*jPIGj9To&TOuHO;8=_OehaZ7#=R`*n0*3R%UR zY%_dI+i$`{giiJoPeVv3N$lYTnKhjyliE&Lj$5?eU{89W>*8j&%KMJ19%2!1Cq2%| zS>Oc}iiz*x-#;)~iwLtnU;KIhZM9#1VyVKnk3kv94b>asazWA?_aAK3okb6EJ)}0L zc&*6&Whwx^e!$!v|Nb6fpsvx1UmE=B7Ml}PD?pE~)-(P(RxUJs7O!B?8_m*0Sc$$% zHC{U5`;)dogUKdet%la4*>hT>WiPK2uinjzSvWikM35D_h!ccTt@B{Bd^A9ol~z4! zk=)xx2-)OnIOpI!N{Oj;zWGfb!E0(>Pl$osW4KL^w15nYb!%;{Twk;B z?Z%02VQxbI(xP{~Zf@PHjfQPa-8kY{+1$s@bOGpd`!soDlA$_IIxbEIXT5(okLd_X z#lq#bH7pr|spfKekQ3|I^aWPNVK@3s;zyWm;-&K*W`x73G`0p=CP5<4q^0v-bNf6a zi2iPkDl4ea`1MdN#!^=1?Fiu5Mt+IQk?t$WZ!|tl=Dh0$iz;Hy9ry(JMhJnX%iyWl{k0^f=nq`eOMaB!t@p#k_nm z*xg>tJPta(LWnh-lI!|T$_f6e$3o(F~mNM z&eoFwZHx6~K4tI{{FQ2H3s0iTFRak08P^aLbhNdh=T;iw?&i#nhU+-x``Sb!{qqZi zV`4^yZc>a=*X%jfqnFU#vql8lTkWyEeJXT6=FLcc3xgfz`L?Uy7h^{o8T@GcW!PI? zX#Pe&>kdX?-2mDrJ3>mxA^&@znLoH`ox~6Y?`+CYjl_oMDX4KphqjtU-Mn?Vz3Y7y z2t|`Fei4yc-!+X|nwOqlbSx>7JURj(_Y2^u*wy4LJJ$3bZ&svyf)Lc5iC0Y%%9n7h zhZNU@K}5R^Ht+b!?A_?AB{sHvlPiu-e*{Mw^Q&?}O1-SG@Gq=9_;vP(zDQ-e&ah+u z;IO|X+l?;%NJ{%DLc4M33qKAfigoeOcRySu4She5x9E`e10&inpEu*hoiQzoc^^(L zZoW%a6ONO#qYfQlKk8HoKl}Sf<{aQ@Xem*f60)J;81S-k%8@BpxrTQsGKYu z^4S0Nfp-aA|7eRrn%zCkz$?qm<~@(XGp6{V3RS7%>(FG1W6W~3cuCIb@Ufy;Y7+KE ztdtx@9_fH6_UWCF@Zc2AtzQ3XI=f!foz3Mxd$Oj{C->@KW~aH|W<)}`gGINW74r@n zr=4!#UYI=Ek#{rK&kqK|0v^gkhGm<*+)!_XM+>F5wuEaH(LQO&U_`nYi3xktTYQlD zEKWW{o-%_!)^G1JD9F9-W&;hi`*%`hz&)!rusG^QXo-J76gt!WeDCy=wuJpbO|XA1 zpieAlury90GgQ(n{e2r=fRD?~mB6IaO`c>Xf7p-15pbTup#0KC40n960W)KXFt(n< zf-01y-&w-ttBkLH2dZCY-T-)mOUu3klQFuoT7`scXOg!~h z;=;Nfj3gVyG1)k#Rq-G(KZKQP-(aRVZ|_bxD|QPfXY%#l{oX}4Y~xeA$#l-Ivs(9R zZ|3FvYvd0Pf?#T4M=Mzi+KP=OR_sLvgKb5bn5=vJZLi_en5`q+)8IzkO!-HQWw%~5 zEWr2kvI~vXmxqB;G&|Rc$x;9AzAW>`YQ;hZcer)**e-P&Y$Keg zD1OOQ%Z|0QzYl#XSZcABD?Q$iqkhKPRr(DX^oY?C#7y1g$+q8Qt+$?OAH-;bdH zSG#`)vAv1$zRozI`yj-jid;Prx9i`s6|A^4HPtTw$*R=fz9p%muan%f#M<@vCWTxY z!TnV`)!ym`JwYk07f$z2p6%$yAGMwomVjnV7mfd5&UNk%<%Q z1Xwep9=|M;qUwG9B1>y`3`{&kiTp31!!iv4ju=@sUeNAXpK$h*U@6l=Z!h*;i&&Pv z;S$>x6UuKjsX~rN{caE=ZuCVZTq|hP{FOZwMh&@FI@28};kyMKR zm;UVAQqp$AHL`l5K#=CbUIn1lQWG*RPcee;NwhwYatjNUm+y$2FZ><4V}z_w#4x1^p`-(hD7J`ETt_KaJt_kiq7<^y(mvRtaz{S@^@)B(@etaCVqqWN3oU z%8GyHKo{%vrO(R>zya>`f7Z804Gd~fzd5=AI{S>_)G6C6wrURxuX?+^>f{z$g$M}O z4dlsxYUGGFr;)k}9Ka*FQ+luPul@J_3qLQn<4=2fmN6I%tOjz|(s?nGPUg;M*DSt? z=$E`_iHxRRqoC`sDIn!<>67YQ+alJ>Kv#x9`wQe+h6vx-7p}n zm#4GhlaIV%_Rj}Xd}Xf*JO#xWPa*)c2irTx6)}e?K8}Gin|k^NGGD-n>VFPb1cUb? z?YLVKCMnwwV~|Q%*bUs$J<21BFO`CyIjeFOa%%h46JmN} zq+dz8s81w1K$*nW13H`U`KBUv`PA^=%?;j6ouw2F)u{6fWDz{7hqA(@PAm?5&n%C9 z&zijR%!;UC_R{-6>X_OtAw@JVFR%Lh%rkqJ!G*h62mq*>64r^zd|_Q?%cC9{aVq*X z=1|L~hU2cls;EIKmW{K%^6nT`1=@Jd;02JIEC5ex{Gw!au3)G74*1T(Srq4u4Djms z$^PBGOY{87^wHn_<4v8q&uz^aY~Z20LaS>}n5j^37%ahP_(xTfUeh~QR6VsPclBHp z2%^eY7H^xAd)n(DW(q!RlRWMC<8N;eNlkk!7#a5TbpOawCF1mSsi)^;6?sm7?58B6 z{Je(Rsh3ZwvPg987TB+gX5(3b#ryd8p3L=8O!Mzxo*AKfoxnegbPwFkNLky~=b&V# z5nlCO!xY?76f^Hasn6G`>P80SX5-A6DnF882}B9`bf>NlrRT|7i-rkCdtcueHNi4^ z%s(?KG3`$_kSNuo=ZhJ3%<1i=JzCzJ-H`gWzu_6E)|UHd|5-MQGdm<@O(6m@vCIS| zTpcX4Epo~p@4KJinY|`#$}~Lp)gv16arjS&z5WID)xB#D=MvH<_}LU6UbO)$rSO1= zKtI2Ldxeyz=LPOFlREll;#3aS3N9Oz@UM&?BoVZV`Tnp%y)5_nsw595J$&S@-hR+t it&Rsl|MSJUkB0gEYKt2Jtd~DEWMH6yc8!+9i~j*J;rwR+ literal 0 HcmV?d00001 From fdda4aacc95b3af6b9a5aa4aae0bc3015a4f82d4 Mon Sep 17 00:00:00 2001 From: object Date: Sat, 6 Aug 2022 17:06:40 +0000 Subject: [PATCH 15/58] Heart stickie note --- .../room-widgets/stickie-widget/stickie-heart.png | Bin 0 -> 945 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/assets/images/room-widgets/stickie-widget/stickie-heart.png diff --git a/src/assets/images/room-widgets/stickie-widget/stickie-heart.png b/src/assets/images/room-widgets/stickie-widget/stickie-heart.png new file mode 100644 index 0000000000000000000000000000000000000000..455238513ae84ee27c35e49718b3549aefe70781 GIT binary patch literal 945 zcmV;i15W&jP)_l^{00001b5ch_0Itp) z=>Px#1ZP1_K>z@;j|==^1poj57*I@9MF0Q*?(XjY|Nq_H-OQPpssI4Y008a)0N3yV zNdN!<32;bRa{vGi!vFvd!vV){sAK>D10qR8K~#9!?b=~(n?MkTVYfHv6l*O(9i?$|f$8Sma08yXli!V}oo8!JMrw3t6lgT`_ye0UZ88w zBmH=Zu0Kni{{mfo4(!E?bnujUZl~){$bER3j-J2I&2;eYz=K!lpzgsdbokz5YNew( zkJsq%jS!1h>9Ee?Rl4yuYigt8I)~Tk#(O>n59mgn!2`PWj?%^>x>dLFh;F`LweXN` z)-61w+wX=k9@FhQ#$!71UVE5!(}_C58+7KKypFf%OkKxYbZR|;hBxU{UBjDnZY_k2 zx9MD6#@lpq9fyP`=ww~O6LfYB$`;Si+4>gG(CPIvHJ+l=^%_sn`L#bKo}=^i63@{c z>y}>eB;8Se#glZ;nyV+CrF-g6JWF@27hCZ(-Bn-lG~Kt>?Sbd%zWM{t)1B+|GTuRV z)-&Eg_pUJ Date: Mon, 8 Aug 2022 01:01:55 -0400 Subject: [PATCH 16/58] Fix the if statement --- .../room/widgets/chat-input/ChatInputView.tsx | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/components/room/widgets/chat-input/ChatInputView.tsx b/src/components/room/widgets/chat-input/ChatInputView.tsx index b474378d..f5db0f43 100644 --- a/src/components/room/widgets/chat-input/ChatInputView.tsx +++ b/src/components/room/widgets/chat-input/ChatInputView.tsx @@ -89,17 +89,15 @@ export const ChatInputView: FC<{}> = props => if(text.length <= maxChatLength) { - const re = /%CC%/g - const hasZalgo = txt => re.test(encodeURIComponent(txt)); - - if (hasZalgo(text)) + if(/%CC%/g.test(encodeURIComponent(text))) { setChatValue(''); - return; } - - setChatValue(''); - sendChat(text, chatType, recipientName, chatStyleId); + else + { + setChatValue(''); + sendChat(text, chatType, recipientName, chatStyleId); + } } setChatValue(append); From 7c68755014839a162363d97912c4b97f303a5bb7 Mon Sep 17 00:00:00 2001 From: Bill Date: Mon, 8 Aug 2022 12:17:59 -0400 Subject: [PATCH 17/58] Fix catalog purchase extra data --- .../views/page/widgets/CatalogPurchaseWidgetView.tsx | 6 +----- src/hooks/catalog/useCatalog.ts | 7 +++++++ 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/components/catalog/views/page/widgets/CatalogPurchaseWidgetView.tsx b/src/components/catalog/views/page/widgets/CatalogPurchaseWidgetView.tsx index 5cca1d29..83190db0 100644 --- a/src/components/catalog/views/page/widgets/CatalogPurchaseWidgetView.tsx +++ b/src/components/catalog/views/page/widgets/CatalogPurchaseWidgetView.tsx @@ -103,11 +103,7 @@ export const CatalogPurchaseWidgetView: FC = pro { if(!currentOffer) return; - return () => - { - setPurchaseState(CatalogPurchaseState.NONE); - setPurchaseOptions({ quantity: 1, extraData: null, extraParamRequired: false, previewStuffData: null }); - } + setPurchaseState(CatalogPurchaseState.NONE); }, [ currentOffer, setPurchaseOptions ]); useEffect(() => diff --git a/src/hooks/catalog/useCatalog.ts b/src/hooks/catalog/useCatalog.ts index 25d0d26d..1cb43237 100644 --- a/src/hooks/catalog/useCatalog.ts +++ b/src/hooks/catalog/useCatalog.ts @@ -874,6 +874,13 @@ const useCatalogState = () => { if(!searchResult && currentPage && (currentPage.pageId === -1)) openPageById(previousPageId); }, [ searchResult, currentPage, previousPageId, openPageById ]); + + useEffect(() => + { + if(!currentOffer) return; + + setPurchaseOptions({ quantity: 1, extraData: null, extraParamRequired: false, previewStuffData: null }); + }, [ currentOffer ]); useEffect(() => { From b084ba62109c8272b35202ef1a2f2115b85d24d8 Mon Sep 17 00:00:00 2001 From: Bill Date: Mon, 8 Aug 2022 13:31:46 -0400 Subject: [PATCH 18/58] Fix wired furni selection --- .../wired/views/WiredFurniSelectorView.tsx | 14 ++++++++++++-- src/hooks/wired/useWired.ts | 5 +++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/components/wired/views/WiredFurniSelectorView.tsx b/src/components/wired/views/WiredFurniSelectorView.tsx index 9b38f972..b08a569b 100644 --- a/src/components/wired/views/WiredFurniSelectorView.tsx +++ b/src/components/wired/views/WiredFurniSelectorView.tsx @@ -1,11 +1,21 @@ -import { FC } from 'react'; +import { FC, useEffect } from 'react'; import { LocalizeText } from '../../../api'; import { Column, Text } from '../../../common'; import { useWired } from '../../../hooks'; export const WiredFurniSelectorView: FC<{}> = props => { - const { trigger = null, furniIds = [] } = useWired(); + const { trigger = null, furniIds = [], setAllowsFurni = null } = useWired(); + + useEffect(() => + { + setAllowsFurni(true); + + return () => + { + setAllowsFurni(false); + } + }, [ setAllowsFurni ]); return ( diff --git a/src/hooks/wired/useWired.ts b/src/hooks/wired/useWired.ts index 43f91f11..7b9de9a2 100644 --- a/src/hooks/wired/useWired.ts +++ b/src/hooks/wired/useWired.ts @@ -12,6 +12,7 @@ const useWiredState = () => const [ stringParam, setStringParam ] = useState(''); const [ furniIds, setFurniIds ] = useState([]); const [ actionDelay, setActionDelay ] = useState(0); + const [ allowsFurni, setAllowsFurni ] = useState(false); const { showConfirm = null } = useNotification(); const saveWired = () => @@ -51,7 +52,7 @@ const useWiredState = () => const selectObjectForWired = (objectId: number, category: number) => { - if(!trigger) return; + if(!trigger || !allowsFurni) return; if(objectId <= 0) return; @@ -125,7 +126,7 @@ const useWiredState = () => } }, [ trigger ]); - return { trigger, setTrigger, intParams, setIntParams, stringParam, setStringParam, furniIds, setFurniIds, actionDelay, setActionDelay, saveWired, selectObjectForWired }; + return { trigger, setTrigger, intParams, setIntParams, stringParam, setStringParam, furniIds, setFurniIds, actionDelay, setActionDelay, setAllowsFurni, saveWired, selectObjectForWired }; } export const useWired = () => useBetween(useWiredState); From 9ea0ffd6dbfb94ec008e1a6c4d639369d2712cd1 Mon Sep 17 00:00:00 2001 From: Bill Date: Mon, 8 Aug 2022 23:54:20 -0400 Subject: [PATCH 19/58] Fix room thumbnail camera bounds --- src/common/index.scss | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/src/common/index.scss b/src/common/index.scss index 3a08bf3c..9b427c67 100644 --- a/src/common/index.scss +++ b/src/common/index.scss @@ -5,10 +5,10 @@ background-color: $grid-bg-color; &.active { - border-color: $grid-active-border-color !important; + border-color: $grid-active-border-color !important; &:not(.clear-bg) { - background-color: $grid-active-bg-color !important; + background-color: $grid-active-bg-color !important; } } @@ -53,7 +53,7 @@ position: absolute; width: 110px; height: 110px; - margin-top: 38px; + margin-top: 30px; margin-left: 3px; } } @@ -110,8 +110,7 @@ .gift-incognito { width: 37px; height: 48px; - background: url("../assets/images/gift/incognito.png") center - no-repeat; + background: url("../assets/images/gift/incognito.png") center no-repeat; } .gift-avatar { @@ -168,23 +167,27 @@ } @-webkit-keyframes sk-bouncedelay { + 0%, 80%, 100% { -webkit-transform: scale(0); } + 40% { -webkit-transform: scale(1); } } @keyframes sk-bouncedelay { + 0%, 80%, 100% { -webkit-transform: scale(0); transform: scale(0); } + 40% { -webkit-transform: scale(1); transform: scale(1); @@ -195,8 +198,7 @@ position: relative; width: 110px; height: 110px; - background: url("../assets/images/navigator/thumbnail_placeholder.png") - no-repeat center; + background: url("../assets/images/navigator/thumbnail_placeholder.png") no-repeat center; background-color: rgba($black, 0.125); } @@ -375,15 +377,13 @@ content: ""; width: 100%; height: 100%; - background: url("../assets/images/unique/grid-bg-glass.png") center - no-repeat; + background: url("../assets/images/unique/grid-bg-glass.png") center no-repeat; bottom: 0; z-index: 4; } &.sold-out:after { - background: url("../assets/images/unique/grid-bg-sold-out.png") center - no-repeat, + background: url("../assets/images/unique/grid-bg-sold-out.png") center no-repeat, url("../assets/images/unique/grid-bg-glass.png") center no-repeat; } @@ -395,8 +395,7 @@ bottom: 1px; width: 100%; height: 9px; - background: url("../assets/images/unique/grid-count-bg.png") center - no-repeat; + background: url("../assets/images/unique/grid-count-bg.png") center no-repeat; z-index: 3; } } @@ -438,8 +437,7 @@ .unique-complete-plate { width: 170px; height: 29px; - background: url("../assets/images/unique/catalog-info-amount-bg.png") - no-repeat center; + background: url("../assets/images/unique/catalog-info-amount-bg.png") no-repeat center; z-index: 1; padding-top: 3px; @@ -535,12 +533,10 @@ z-index: 1; transition: all 1s; border-radius: calc(#{$border-radius} / 2); - background: repeating-linear-gradient( - $tertiary, - $tertiary 50%, - $quaternary 50%, - $quaternary 100% - ); + background: repeating-linear-gradient($tertiary, + $tertiary 50%, + $quaternary 50%, + $quaternary 100%); } .nitro-progress-bar-text { From 70f66a8ec53ce5c98ac2aa65429af285c36b0617 Mon Sep 17 00:00:00 2001 From: Bill Date: Tue, 9 Aug 2022 11:02:59 -0400 Subject: [PATCH 20/58] Fix wired again --- src/components/wired/views/WiredBaseView.tsx | 7 ++++++- .../wired/views/WiredFurniSelectorView.tsx | 14 ++------------ src/hooks/wired/useWired.ts | 5 +++-- 3 files changed, 11 insertions(+), 15 deletions(-) diff --git a/src/components/wired/views/WiredBaseView.tsx b/src/components/wired/views/WiredBaseView.tsx index 6227c669..1128f19e 100644 --- a/src/components/wired/views/WiredBaseView.tsx +++ b/src/components/wired/views/WiredBaseView.tsx @@ -19,7 +19,7 @@ export const WiredBaseView: FC> = props => const [ wiredName, setWiredName ] = useState(null); const [ wiredDescription, setWiredDescription ] = useState(null); const [ needsSave, setNeedsSave ] = useState(false); - const { trigger = null, setTrigger = null, setIntParams = null, setStringParam = null, setFurniIds = null, saveWired = null } = useWired(); + const { trigger = null, setTrigger = null, setIntParams = null, setStringParam = null, setFurniIds = null, setAllowsFurni = null, saveWired = null } = useWired(); const onClose = () => setTrigger(null); @@ -83,6 +83,11 @@ export const WiredBaseView: FC> = props => } }, [ trigger, hasSpecialInput, requiresFurni, setIntParams, setStringParam, setFurniIds ]); + useEffect(() => + { + setAllowsFurni(requiresFurni); + }, [ requiresFurni, setAllowsFurni ]); + return ( diff --git a/src/components/wired/views/WiredFurniSelectorView.tsx b/src/components/wired/views/WiredFurniSelectorView.tsx index b08a569b..9b38f972 100644 --- a/src/components/wired/views/WiredFurniSelectorView.tsx +++ b/src/components/wired/views/WiredFurniSelectorView.tsx @@ -1,21 +1,11 @@ -import { FC, useEffect } from 'react'; +import { FC } from 'react'; import { LocalizeText } from '../../../api'; import { Column, Text } from '../../../common'; import { useWired } from '../../../hooks'; export const WiredFurniSelectorView: FC<{}> = props => { - const { trigger = null, furniIds = [], setAllowsFurni = null } = useWired(); - - useEffect(() => - { - setAllowsFurni(true); - - return () => - { - setAllowsFurni(false); - } - }, [ setAllowsFurni ]); + const { trigger = null, furniIds = [] } = useWired(); return ( diff --git a/src/hooks/wired/useWired.ts b/src/hooks/wired/useWired.ts index 7b9de9a2..c4628f45 100644 --- a/src/hooks/wired/useWired.ts +++ b/src/hooks/wired/useWired.ts @@ -1,7 +1,7 @@ import { ConditionDefinition, Triggerable, TriggerDefinition, UpdateActionMessageComposer, UpdateConditionMessageComposer, UpdateTriggerMessageComposer, WiredActionDefinition, WiredFurniActionEvent, WiredFurniConditionEvent, WiredFurniTriggerEvent, WiredSaveSuccessEvent } from '@nitrots/nitro-renderer'; import { useEffect, useState } from 'react'; import { useBetween } from 'use-between'; -import { IsOwnerOfFloorFurniture, LocalizeText, SendMessageComposer, WiredSelectionVisualizer } from '../../api'; +import { IsOwnerOfFloorFurniture, LocalizeText, SendMessageComposer, WiredFurniType, WiredSelectionVisualizer } from '../../api'; import { useMessageEvent } from '../events'; import { useNotification } from '../notification'; @@ -12,7 +12,7 @@ const useWiredState = () => const [ stringParam, setStringParam ] = useState(''); const [ furniIds, setFurniIds ] = useState([]); const [ actionDelay, setActionDelay ] = useState(0); - const [ allowsFurni, setAllowsFurni ] = useState(false); + const [ allowsFurni, setAllowsFurni ] = useState(WiredFurniType.STUFF_SELECTION_OPTION_NONE); const { showConfirm = null } = useNotification(); const saveWired = () => @@ -123,6 +123,7 @@ const useWiredState = () => return []; }); + setAllowsFurni(WiredFurniType.STUFF_SELECTION_OPTION_NONE); } }, [ trigger ]); From e1bf00472a7fbf26d033af6fc1532e1ae750ac20 Mon Sep 17 00:00:00 2001 From: Bill Date: Tue, 9 Aug 2022 11:53:50 -0400 Subject: [PATCH 21/58] Fix avatar editor scrolling --- .../figure-set/AvatarEditorFigureSetItemView.tsx | 16 +++++----------- .../figure-set/AvatarEditorFigureSetView.tsx | 12 ++++++++++-- .../AvatarEditorPaletteSetItemView.tsx | 11 ++++------- .../palette-set/AvatarEditorPaletteSetView.tsx | 12 ++++++++++-- 4 files changed, 29 insertions(+), 22 deletions(-) diff --git a/src/components/avatar-editor/views/figure-set/AvatarEditorFigureSetItemView.tsx b/src/components/avatar-editor/views/figure-set/AvatarEditorFigureSetItemView.tsx index 8df5b95d..fd28dc55 100644 --- a/src/components/avatar-editor/views/figure-set/AvatarEditorFigureSetItemView.tsx +++ b/src/components/avatar-editor/views/figure-set/AvatarEditorFigureSetItemView.tsx @@ -1,4 +1,4 @@ -import { FC, useCallback, useEffect, useState } from 'react'; +import { FC, useEffect, useState } from 'react'; import { AvatarEditorGridPartItem, GetConfiguration } from '../../../../api'; import { LayoutCurrencyIcon, LayoutGridItem, LayoutGridItemProps } from '../../../../common'; import { AvatarEditorIcon } from '../AvatarEditorIcon'; @@ -15,20 +15,14 @@ export const AvatarEditorFigureSetItemView: FC('hc.disabled', false); - const rerender = useCallback(() => - { - setUpdateId(prevValue => (prevValue + 1)); - }, []); - useEffect(() => { + const rerender = () => setUpdateId(prevValue => (prevValue + 1)); + partItem.notify = rerender; - return () => - { - partItem.notify = null; - } - }, [ partItem, rerender ]); + return () => partItem.notify = null; + }, [ partItem ]); return ( diff --git a/src/components/avatar-editor/views/figure-set/AvatarEditorFigureSetView.tsx b/src/components/avatar-editor/views/figure-set/AvatarEditorFigureSetView.tsx index 8a813a03..3755731c 100644 --- a/src/components/avatar-editor/views/figure-set/AvatarEditorFigureSetView.tsx +++ b/src/components/avatar-editor/views/figure-set/AvatarEditorFigureSetView.tsx @@ -1,4 +1,4 @@ -import { Dispatch, FC, SetStateAction, useCallback } from 'react'; +import { Dispatch, FC, SetStateAction, useCallback, useEffect, useRef } from 'react'; import { AvatarEditorGridPartItem, CategoryData, IAvatarEditorCategoryModel } from '../../../../api'; import { AutoGrid } from '../../../../common'; import { AvatarEditorFigureSetItemView } from './AvatarEditorFigureSetItemView'; @@ -13,6 +13,7 @@ export interface AvatarEditorFigureSetViewProps export const AvatarEditorFigureSetView: FC = props => { const { model = null, category = null, setMaxPaletteCount = null } = props; + const elementRef = useRef(null); const selectPart = useCallback((item: AvatarEditorGridPartItem) => { @@ -27,8 +28,15 @@ export const AvatarEditorFigureSetView: FC = pro setMaxPaletteCount(partItem.maxColorIndex || 1); }, [ model, category, setMaxPaletteCount ]); + useEffect(() => + { + if(!model || !category || !elementRef || !elementRef.current) return; + + elementRef.current.scrollTop = 0; + }, [ model, category ]); + return ( - + { (category.parts.length > 0) && category.parts.map((item, index) => selectPart(item) } />) } diff --git a/src/components/avatar-editor/views/palette-set/AvatarEditorPaletteSetItemView.tsx b/src/components/avatar-editor/views/palette-set/AvatarEditorPaletteSetItemView.tsx index 8138e951..638a9d18 100644 --- a/src/components/avatar-editor/views/palette-set/AvatarEditorPaletteSetItemView.tsx +++ b/src/components/avatar-editor/views/palette-set/AvatarEditorPaletteSetItemView.tsx @@ -1,4 +1,4 @@ -import { FC, useCallback, useEffect, useState } from 'react'; +import { FC, useEffect, useState } from 'react'; import { AvatarEditorGridColorItem, GetConfiguration } from '../../../../api'; import { LayoutCurrencyIcon, LayoutGridItem, LayoutGridItemProps } from '../../../../common'; @@ -14,17 +14,14 @@ export const AvatarEditorPaletteSetItem: FC = p const hcDisabled = GetConfiguration('hc.disabled', false); - const rerender = useCallback(() => - { - setUpdateId(prevValue => (prevValue + 1)); - }, []); - useEffect(() => { + const rerender = () => setUpdateId(prevValue => (prevValue + 1)); + colorItem.notify = rerender; return () => colorItem.notify = null; - }); + }, [ colorItem ]); return ( diff --git a/src/components/avatar-editor/views/palette-set/AvatarEditorPaletteSetView.tsx b/src/components/avatar-editor/views/palette-set/AvatarEditorPaletteSetView.tsx index 4ed984be..c55dcb47 100644 --- a/src/components/avatar-editor/views/palette-set/AvatarEditorPaletteSetView.tsx +++ b/src/components/avatar-editor/views/palette-set/AvatarEditorPaletteSetView.tsx @@ -1,4 +1,4 @@ -import { FC, useCallback } from 'react'; +import { FC, useCallback, useEffect, useRef } from 'react'; import { AvatarEditorGridColorItem, CategoryData, IAvatarEditorCategoryModel } from '../../../../api'; import { AutoGrid } from '../../../../common'; import { AvatarEditorPaletteSetItem } from './AvatarEditorPaletteSetItemView'; @@ -14,6 +14,7 @@ export interface AvatarEditorPaletteSetViewProps export const AvatarEditorPaletteSetView: FC = props => { const { model = null, category = null, paletteSet = [], paletteIndex = -1 } = props; + const elementRef = useRef(null); const selectColor = useCallback((item: AvatarEditorGridColorItem) => { @@ -24,8 +25,15 @@ export const AvatarEditorPaletteSetView: FC = p model.selectColor(category.name, index, paletteIndex); }, [ model, category, paletteSet, paletteIndex ]); + useEffect(() => + { + if(!model || !category || !elementRef || !elementRef.current) return; + + elementRef.current.scrollTop = 0; + }, [ model, category ]); + return ( - + { (paletteSet.length > 0) && paletteSet.map((item, index) => selectColor(item) } />) } From 2b0b98e3b32c5dbd02e097597fca0b13a127e810 Mon Sep 17 00:00:00 2001 From: Rasmus Date: Wed, 10 Aug 2022 00:24:48 +0000 Subject: [PATCH 22/58] Replace stickie-juninas.png --- .../stickie-widget/stickie-juninas.png | Bin 405 -> 28162 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/src/assets/images/room-widgets/stickie-widget/stickie-juninas.png b/src/assets/images/room-widgets/stickie-widget/stickie-juninas.png index 1d64ddab7162122bab7cb7163ef626a0d6199041..faaea9d1e6303afbb0ee6846e08d5936ab5e066e 100644 GIT binary patch literal 28162 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

N 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 From 8fd762522336e9cd5448d90f18c1674f50862336 Mon Sep 17 00:00:00 2001 From: Rasmus Date: Wed, 10 Aug 2022 00:24:59 +0000 Subject: [PATCH 23/58] Replace stickie-dreams.png --- .../stickie-widget/stickie-dreams.png | Bin 5095 -> 26556 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/src/assets/images/room-widgets/stickie-widget/stickie-dreams.png b/src/assets/images/room-widgets/stickie-widget/stickie-dreams.png index 27ccbdbc517971bc7f7bfce785dc7f001c6ccdcb..1723bdcb061392a06feacc51e40d7108b113fadc 100644 GIT binary patch literal 26556 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�v~n=?I0_(WlwAn@duV^Jm-?w~x+k=33l#}t#C ze{4}ZO`6X(T*fvD(nTEFH9W8Aos&SD1GZQTyW%n4ZQS)Ucm%aVGO!V+8$lY=+*C>p z0I^2hI&-D(80K}e;@T=#`A{e>;OE?xQddQ{63DOT3=s1xp5hQ8KNX3yFotBmV8FxRvYV}Dgg#uU8j9laifYVT;+t~<6x$hqJnM6c)24&6TFx5O1k-?*)(h8I% zT$Pc+_o>e1_H4eLj<0^-i(sR0Jak!q>nNomrxEleP^ZX|7S&o!`V=6&>rB~ZjWy;3 zFlO~qy`B7_e&aXcItq^Rle2qf&Pg&u(wgYW-9XPJvhvHOr<156C<=8?>bv@WdF41N-5x@FGI%1G&5o8LXz61bvgz zyn3Gs0~r&rlId6%yk{zQgN*R$^XThBsHZz!)N%y0;`OR4N2^=}S7+s94m0v9xr`hZHcLTQD9a=iRkHnHm*Yz#Lr$u!b=%5iyLmuF1eK=%Abuu9TL zPi4`K_Fxxy1#wt?=*%I|Nq3qB{qBfPf)=Ap>Qx4GG#GDIjL$vaky1Z|+9u@oY=lB$Hl&gv|BSEq-hQ zpha*-P|Ud_Hnip>>d|<~hy34=uBrT>(!WuTW;CSnMjKc425?8lD$p>`1m@ZJF3CCI z=s=!VOBW|3i-V36XQLTyzr{<5EeaVA9TG~RhZmXM>c9-Imjk%CKkh3Bi%4@X`R2IC zcaz8e2$39j_NXw623pRc1Bz-IaS%zKW_tq4Pl&Bww@Q9)k%_U$L>o~-G|4>_W;3u5 zzV~MO6L49vGioWRQ9aucAn|DM>Xl9sJZmb~az;3y17`8YldCn$apMrtqs5BVRV*OP+MPH&Rm18`XtySCoo*r98Ct2;d#%p^g zt>DqBlP*zh&vbZ>X2GU)I?yn_jg|SD0!bkUMIpoe&&qXNVh7xJo8gW)p-!4;OvGUb zj1=YXZJgsXI5f{WK9!FnKkRq3-;KVblj-P1H+SYZ;!!0kTVFoM1#C4;-rGZP$;%VR zDG$AKVNx1Rvelpyer*d}E5Az#DR!{pbS>1fKG6QOenH7ij*G6+1aiyN1$&paESDz1 z6p+;H|B7{Q8&_DXO&b|jy`jT9XYE*7W-E!w&}Rzz#)yp}+cgB(8BHMVa1)P?;Mz@_ z+C+=^_-Efgo&_M<+jA=ykt#ATI|@OP;TF6&hv6ctw<_bULO(~DpN-PA#7d98IYPSN3K%leDGG@Uy3!C zP;aZA*Uk-jXzBi-@6K2NK5QfKMJ3TINSe(}$&5@qzqe8C9;JA1CYh3qmXUb;3^yjU zi~0272q>_cX88G2jb2_)4<1{gr>z=#^hCW2cn|St(c4=y40-`Eu4YIf^H;C)-Z)O< zmCYMfAs8R?tMx?GKyd!D^ZgsxTydz$@OhB%vPYwwyU<3{B;JWhLB2nXbtE*=zya_r z+fCCaljGG(9rIaw(vwHY!3X>@$#K2Q4Bf(#_4(#3jb@w+OzVbf@L z_|=9&NvO+iLcU}^J9*u-2v8W=Us}#BjI1Y&G;fwDIQINW#808&hvTY=&F{xds z8km@PEjb=7%1x-hDXa|^@>?4AP7J!X^IYNWSvxfZkz5=|KnLne4ke*_@sVWg=t<#Q zjS%8ADHvBpoA!uFtG4tfW|LH`AAR<#zA<&k6;YnHj!(fh7AfqovrlK3bz!Os7+xxt zVaP&PO|H;*EoDbsB0pD9PgnGzp0?)sH3}^t z{o=et%vm#wZ5QU%Rm)3r-A5Q~xsYT`l5`;`#aza6jD<&zpih5)u3_a_zME1~aJGGS z&&0nIjh{cK-a*WWV0K>wU-!U$;Os;92!BJ!l#OXzf z-wEES7(lG!6;QJ1y>RbWju0k5j(+3orDr)77r zbYpj2lFNj&vU^+I`7j{`KX{)N$`s6A_H#NJG*Qy%C0=N`6&^vrP<1^0QiXW9U6IF< zJ4+)0Uc=GQ&B&26EBBsPFj>sDvT`PtHsQeH$_AgPM|_p*Pju;SA93m(Mb$X^EC_V z3!aL}J2Pcyq%?0GD)6fuu^FHBeYlXF65<&_^+56?DApKxV-5acrc5kpcI__Z;minS zj#e`}<}~b|tIZ;SQMHrUnOiJ3TvR^-S@p#q1ty@#K7$VJ<~4&S2~br-fZ6zB>`vB| zVRvn^ru4+cYn9RO)n@3xi-p*0#8`NZGbx#_?6{66=&Xq&p#|FXR zK401KS`tlBdg90y*2*G4W>sY~k_RSF09=zpotNhIaJ|#1N~GSGPrkSsl@wF2B1exL z4*hHqGj0mINK3pj0zcZrf&Ryjw@r95n$T#H<|({%UzVtQ3;hk6NzaH^E`+V!WixJO zl#WzLmH3@o>l_Nc%w{N{4kB)wrn08Xm3h2GVKe@YN-3VSj_y_+L`SnzTDfw$I+@F3 ziqfnNvf!RjSvbuS>Qh%DA7>&8v;#vnZ1m`=>1ejf?dzLHM&W=g_|`?<Ak)aq=e-Z?3gwdkkdgw?4 zehJA4ERtqu)zSn=8{32uolG|*?QN7$GAW@-Irf##oA@9?DirqR;74b_x_8PgYRV9^ z!>pDs(yorKza;}@PS`%fE;W2bIQoN}+r#AON4zwsufq>bVed#fCN)G7iIqj|KCv&+uWerFO41jJbCeHmiS;JgqU*wx=M{8WgWt{k7Vs z)uS`HVCm?DGJOB=`Z-V;B04^!U>gJQM1V3z!q^Z?5#fj*AN4HM$@*g0YSKi(ovzlb z+_iy;Q+iwH3B?z;n&dnESNnFz64kv;3JdR4BeDMTb>C#^9u(#;b{Pk(+B$oWQJ5FO zPhRW&W@2e(Q%ziSX$Ksen42;1WsPMI3)8;j0NWnyAU*mod=oaFGgJO>53dwx87eKBV*!%L#CS3c*>L@8*fNiGLHePn7HLL$NnF zwI4gGYO<0tYwmO3Ajp(t5qVslF(Ot?knk$ZsB+p{qCA2^C*8zfz*qd@31T>NxI3{7EtY zrX#dV>!g<0F4V&TpFE-0NO;nU9?IK=k8EQA6<$JpVX(Nt_9w}~+9Er->|WA7ERJCM z9nSng{?mDY0?dahL54N8bFqlz#)QmjzcY&*C4xEWkt9t_P@rE z^gA;ww4?N^tGS{#Wi=3##s#s!Ay_(ekcN>6-WF;c74>iEJkf5#;g0pB z(4H1B{^OXw^mcg+laQhr<5E$B1*3V3bu{57QB|yo4OPwg*-;PNPbqc2dyL!+F&YV5 z7Izg3R*?D@F9(~H0e1srK-}>3_(-z9Ag9h^&HQSW+|Ni3vvoulmJ~jeB~qocR%E8e zhbtYM%t~HB-pZ3W!1)OS0gzBuDGZgwp1l3cgpSk55`(q)BdC=osCO1`&Jy)&2U8)B z^}Tk*-H#s##}f1{!Ze)n+Lm6OqC9c)q$f{=HIKi2Cc8kH{d=6IdgQus>*5{UzJFRn zV8@Y-%P_GrRZVYyTgwXA@ldAAI@7Y$3ds0BRs?g|CKVH%Q=z)r9#9I5>^KD_-kY_Lez(lwUXILq!yC@VLZ~sVcP#QcINz`9u>xO& zcH!Z%477B=;1hYJklkFGWM>amB$llzx@an7_HlKwWs(uzU9z--itAV_(KLT_&lCZD zXPgT`FjISUfuRlV9?n4IRb}Y8;wrC55T(bi98qYHfVP(-*m#^jXwA&QvpAUxnZ) zBPvftW&UP|fX+W{St~?MEND7H)(D<|sEuA@ON~Hs4Oc;#T?Jan0H2{bbCCGnANAv2 z)C<`}gC@5$^^?t*iC~0h*UOAoisx4L(SL8Wr6fm@I9NJ<54$O&dye}SIorPN|3mtx zJ5W%5r%Y@yBZ=)(!(>3)+zMi56YC=6)sJ7{sR9ujEm@TPrB-0H)7GKp-xy1bb;X!2 zhoi(@@f0melcmG*=k57x%UXg?%{b5SIcXq{y%O`&`({TypnTmH_HZO^0-=4?IL$R@ zp;URFC4VFg!pJzsAWn#Er%dJbHp4d-<29qS2EiBEOL~h^aY2U^>9D!bIN(sp<{t$& zEM$dJPSo*lxE>rfdn>DQ#KzbgXPD6XbsetdYb47Xu3Tatr@UgR+))M-!9n)FVxhcZ z3`}Q!qlhsk{v=g<4CXPS9K+2_v9iDw*EkTnIS>)`2MsoFE%cozfgE$;r;6T%32jaw3cNw}#dPeUq zGx!yUvXPethvm@e7LF9iiPQE#gsE?}ojfrJHh-WRR{MobHlp}v9;rJ70wuX?ioM;dWRs-H++&qU4_o!c!se{shXqyM$D#plj#4MbZ ztboEPAP&Dcd{Gv}QKEM@og01vS{{#pOx=tt%?|_{lApLf)XX?_<6bXH2|LseH7$rY zyZ(K-6&iUeor>o-rfiOPRW@8?eln@5%7=I+-~yw9V6G@hrg>o39N8vIW~&lpSFM~H zwP|@~pP8($M*+O83dpFW9^%@+R0%a}5BBT|f7!SYvCp`_UFr<@MygHvSt#2yJm5Qx zR%x&xXJU(vGD&rxKgx}-Ci1gg`(>^m{K>;2Veu-hh6Hc_+$ShP`M6DkScf#v=7bjhPMH$$15BK9;{3`queNCd?P zq0WnRWj`D|cZO5!=7biizI1iS*gQgVhm;Yl5*ht$q@%PnyK!_ZRjwKeU$?W*{VX+A za2qx@8_N7vv7^1R;jdbmcVwd(JoEdm{tb{@w1Xvpf;{>%E+t!`g2b*aFsW3?4&8F6 zQ@o|rab$hK)cYy#wCXXhSALBX@5KzgkuZm+8R&`&+m=$ah{PsaRbFIAm}U!km1t7R zN;kzCS63&RJT9))Ha$z{mkWa=6+9V7tgKl+qYk2llNbnZ|4Ch!>{A&ZY8*`UvPR3$ zShu{6*WI`07FF>K<3}I>>!v8YA(i?gZ<1U#R2>~SrF7PWPHH>xvgYPz*O(&!!K5Ky zd?%mDw9rri$({e`$1CU^X{$xc_yA_L=-lIAe4|89oW%SKNqPMZW)G>+6`2l4$!$#A z1Fvrbawm=Th7Zu(Se4K3*vFKN1##V4jBnb*_$_w5fBW*}ewEJyxq$DG*ZUfD8jxD5l%5W9#&5FC zp|AI!n9eUewsYeX$vgNhB@7@#9=S^U;~9F%vbiR~d<_b?7=Cvq<)Rmc`NW^9^p_=< zh_6!6yvTwnpSf{idIjY__}0%I{zlZ!wUtp?mm%^*l`%td*__2P$fnkG%`k&eaTC#5HLsRNkK$%QW}6r9F9g5Vis@nml5 ze@ilR-5x9r7^JR4+hxM|zqoMM#K5FoBzE>#+xBZHHpXX>Mn;otoA&oxZmE&9vHpQJ z+g%!?R|O>m#Dppqx*Lj8|7a=H9OirED3Kp5_VF6OU^OPK)Gv(sKLI-(#Nw{J>)sW4 zbOqkgq^yIL7I|^<9d8^$_Znf)z=##baH2;|i?h<&pltJVIU`~;9S_~MC_ktD#rAI7 z7!Y3sZ_jNE--`;J`Xu15-<7nK{JH|By}BTDD6pJl@Q&}`-$%7k7>Y6`gYybg0W2~! zndTJP&~)VU82Q14H+Ij7835T~8)5yLxBG!KK8u__im2I}3b!~gZF(0N(KPSkz{<%Q z()`9-l-D-G$z_PqjvIS2z?P^%=56WMw;w#FBv2#pJ~Z{#QNu<1-TTWeWqG9LNGhrW z=XMz@%)uvU1GvbEBin%C`w_9*qD73pqCV-1|ruatMII{2BBxLd?7PF1Qz%67?nZeKai&xGMR8f>e9q2bx>9jSqye=9iklMRGHHhr$ZRZPFyHSRw=!qG$g0hLu+KD zY`h*>G_4zX`0dZ#JpS$Z_|cE=O5{A+ufF=eOZK#wCN==Zahv6>C0KU19vc+B&B#fX zb1<`FpLR#pRd1Gxs}_?lT*>$LY?sVhjG?*nXM0u`w1+P?SEXVn+QUZ$k7=p+ z&BMy8`m`~I#e`XEg}Q%CICFi=i8e)i_qwlPc#rP>&lJd&ElI;jd;YD)*}b+a=f)r3r*w6S@G@|QAHYjlW z=a0`*-CQ1tJ_bG|>#mllz;fv^ypT0)yF@M49}ra9DKl*Z^UmUSwK8kRE(2U8fLZH& zX>R{Aa(f^%Gqvf9qdb2V`DuydcUfzX!fd*A^*Q#jWGO>-I(*7pEllb1G^>yP;L$p* za&wApESWP|%1Z8p4i5J6p&a|pq{vGI4Vw>%^u-Rs06_t`+HKu{$8mBFMGKt5X7B)H z&3QT!*{Ql=r&pw1jiCgeGZdGzpdCGv2tT7Xy-w*ashsEo#{$IQ6CkXq`lrAJOQW*E zEFwMkrOnDA*YE|qeH+etBz6^`10H=u_T5Fka(VTcC6a1b@wK95V}FnrC&SWgvT%a$ zk`p_I4T+*Lb`@IG+UHk$h?O;2Wn~@^atP}>?_MjIICvz;kkgy-Z=5JfAIHr_{ns_= zadmZ9-SS2i#FSN4?_oc z8kl8>lN8iQbeI-+Nw+Pd7;WemY@DAgWW;F*G{@L3A7&~-FeC6=OHZm!qWx;0mPKyI z-`MoRSs4f$o}>?&v8rES#B2>prjT>JLmu zBVqH7a7@-!giHtwC#jB7QV^Gc0j1HH%z>tA%n6!(pqTiaH)``>Fj#3J^pd(uKxQFP#rJ;EX~u=7Du68 zrG2ohiUbDNW!l?s^)WAzla*6+kK9bfk`E_hp4sB|3ml$%79o}sv)qosP!}H?+oH6N ze5T+7Y&mbAm`gXHbL6r(Fn5`B%RH$|^x}!qAAO8Cn~f#bG#00R%ITm zXJRp9ZwEH-r-;=%9sSzY%eP;6N|}q`>SZ||XV!nV=MJ=_MaMB1Z&bFybI%z?AFVz5 z0WpqM$dm+XS9vn2YB1t1Xfl>`ED&-^1zb$Tnv1>@>&wf zjVk)g4YV(wv4ee-axYeg$qgMz$~VJ0dPbu|BZ0`1%43C)Na4ibEA4wdX}Mu|Jj{uW zX1)pSeqSV;KbB1$N6;8Kt}R}fhCu^i$$Za7R~DzV#xyUe2^1h2e(Dq03P~?0`y{g^ z>O99|mob4TVPd9ktTm+*s5!Wmj^6aB zEpzR;92}h}gssT|_ry|3hr(@C9~~*^j!)}C#wl(^P^i|oV}R6g+|5Bm{eZUUnMOQw z!kKYFx5X;`mj)~PyvS}VCPAQ0Fk@o-LPxudik6|ai`1qSaTAj_Lu4jqmAUZdG+olM z+K9zJBOFE@ak5nOAx}~Wr}W2X)=aIUbmHJH8Wnl~J@L2$79Tul!l@NILKI+cC@9rM zBNRyJuoAEi1(8kUN(l9gDWsIm|@b9InDcP0q8m z*!13V*H59&4KOr4`&^>-H5f{T>D06KU20nIs>9M@X}Ef_Q7(c_i~mTtxh<~(jOgj( zIQnH-WFNhlT}5c4_Rze&*`Pf-QsDX&A3K-s1_L=Ih{6<$!P6d`fURj@>yYNKe*6fw zzmkKijqx~*y#|3cXuuRUt_2@+m(d2|4*NDvr;RXWf>u!LshV5fRz>EHn82o(A^dj= zr^4~x%Sq-eJ~eI(q(J_RF;~*b3rQ8AGE7n94Y8CD=!8OFHs28ivGbMoEwlCQk#e$Z zeoC2%JSXcY{hfv+DRjvNe`E{JncF(lk}%KoG1zHnS1S8wkESPvwzRSnPjPaG*;yx; zcW-KN7wlEM3Yhn0bUXX2NE0ig+_HlFbIh7qh-*4L71bR+OloC{KZ?z!^FWJYU8dQ* z09}@9qER^)VC?F!YBr08(bYcgGuu=Kg*jtU?Q5vDBzJ>{rJqY^H^b6Wz&SJ|DWCZ4M!vmX(f?QK5w0+Z%}yqgLNM zG#E(=S1BPu*}?~P1Sx2`Hw*Uoar2Ia43 z1^lpKFB=?Yp8<&ag`92srM zg)4^E$C2cT?FJ5+BxaE+-qpVI{k2rbOa_~_B-@0B(n%3yo*(ZP;yT`i^TcxYvH<`TW*5`?ELgB?@7?{k zM}oi;#AI~8v*!F5DWWW2?H?FH>}|Sfu?T?9itiM!;<+`j^jL_v1|{Zoh`Q-v2A|{v z5qr{y+ebUoNg~t&lB@u=)tq=^b88$&TTr~u?%7qkC0WG zld6>@NLWO-P-l%iS=#C{E{|XensWJWl+INlSU3Uk`WoP z`HAAA%ZhemT=BIX-#1z6>Y)#&mI3~(Ir>iy4jrQb8>O<;TRWK&6n3<}%frHWj(AC9 z7sVId{L8PW)6@{qxg=Z_-c2kfK}$ewp&fq1#9mzIoIoy|inc zM@Np!OCdx6X~;t_5>rGr0M*A3V&Ku#v(Sw!Q4s2+6b?&)+KwovaBGp;ZCtve%2UOr8@5 z<3rkm^R_aJhNzqd3=>8nTBwtKyD^YBxO(#~L=oo*@ga>Z9Ww}w(?PDw7CPKh4;TzA z#>heh@4x`30dt`FP#0M9lyQ0n^M*9$_k@j42> zKi}6tl}bkd01vK7L_t)ZoEl=@zVAuAx2`b38@d7}R{NU0ru%|W61Dnqc}j%!Mk zw#Y|yJ(?2KP@$Vf0_i9K#<&b=F7STOfIz4*y)F>C_}+USrO-vhmNj^}o*tuBPSZBV zGx>0Oa_<0(v~TT4(+=Du0TC`QXC%dsI}zudv24Gh?t72coow?)z>6{p;LC`){x z#Zi~)QLUhUfRae-oNfa4=KYL8gLAD@po=)U@Q|J&o*HqvG=J{zU53+kdRuZxjH$jN z_8JPnGAA!Y5fLlk$mGdWHua12r1q1Hc_3P(tud_^p*k4UjMk9T@cKP6;K{)k%#-Bf zvyJ96K9plLc@D zjj&6^;a>2dP>-(IXvnZR$o9_pSGkQ|0*1eaD>4ukaz&ZKg zLNMrHLMDLGv0?9wA5a$*vt3yWKqEf9kypg_G~*c)$)kcnJTy8sBw{!JF&>yswO2GItUu=t+;q`@pB(P+QY9J{iA@Lu;w?k)$hQ*1F<1S$MBAWgtST5}P-= z@SSB2rn5r#`RZe~Zucq~-h^&FfpKuScnB`-CCBt#l{f^|UdXU$lY=!)RJ}M&tN;4c z#_hR8fkqN7JBg03y*}Y69JA~uEBQ9)ug}Q&J_lQzQuZ~tq(u2LYpB)m??Z%>iE=c#*&;s zDe>$3A2T0)g0ab3%UaVMp}FO>T~7M?RQ38B+!iMmvIS&BpJuwg5}eE4WP%EuDKiV{v3rgqdg+A^+;HOURh5Ukxw zd`+CKcUW!#vZhI52n%F27`1&~Mt<2}8`FZ$!X|Jl?%IT~kIyi$bQ@odik&+5SjA|P zyZHW(@7Im?_I&&~!Qgl0u6zLJ?hEJwRqdg7EV~w=UARtP;85~KM9SE)s_8g8?b)zE zTjp-|$qO)fsHYrTk=uJWg-&1SEa4kap^&+-Lw-Ja=HqME=x8#z zqaHl+&lXj1ds;)6hZpz9chzpo!hSwsGm%ie`92r#lKEjB+Ttk!1Nza0Q(P;yBq8F= z@qkS6rs(~^O&5l7oT|!LIDKTb2?yBjSXo)&v9kv3i8E}Rx=BRznE z{D2mmtN|-x5FJKF4|?0jLo4FLwAF!---haji-_v!+297KoB&PJPKWZ6(B}Ne{V!jx zh1<&$2G6j)=)yibsL$xBT8uHd(c0IAd|S+4N}xENqy;^KzdzriXNTiz&S97NkU^yAkEw5( zG5h9qoesVI_OaCFRG)IBC6@o1ra?#nIHofN=|ei-$0)<*wHN|}k$TvfM+PIznpOx5 zj!?{%_5w{`~Qv;Dx6VsWv4#TzWGC#5wsEl@x_u2N*zp&=`5n3%XCO5aY z+*5}np}`3gcp^M{e>pzl$EQZ~J)&CLur2tH&!c;0Z!qAous3V8kMDUMZpg`U;ocdO z9W9N~rOU8)$jLg%@hT~-D{e|#R7}g)k z!Qh56-s%^6a*E(xGWu2zvPg&#-&-~$Dc;7j=wi%P2Kd-+(Zqp8WgnoNI zM(p)8=KbZEFDZ6t;UjG)!^59HTmzX;H2lp!{oryORGfVSp}(^(V_;+xBBVN`N}Jkv zph_h(;lJcUx8U#XlY-6bE`4pK+!0N*50-TuH%F95D?r6<>h_l%?Ff7K>-QGz7;@pW z=x2Z4Ukith`p0zwZ+v^sEHAcTa&b^>k7bMY4+*T!uFXoZa{9enER11HF2Qo6@fLyL zOd5^SE^ACh8&=ehYzJ2D7nbuFSoa`Sp(nnbOmc3m&ND^1QFHh-p04`%75ZXK*A>(k<@{>{;mV z{^=%o4Q>4c-LOX9fp6E0%6?=c9oHU7#};LPBSU9QvNuL8qOiW+JQ1pY?*Ggmi5-+ zncX6_PJDwRH8S8z3u!pH!ys+FhkP_=rfrdT$!JeG1gmb5^W%HfKYwOb@TSmvzvbbb z3Lma|i~9BL`S=}AkmN^lFG}Bo0sF?0$c=@?LM0pG5P8dc?Mf7JL zZhE=j2d3@?I8Qp48DfRk4q9fOK_lFD6GQY{1dr46JUmxsX)@>e6~=|1oIp3lsQeCake2&*b8z| z^i5w5Rk*o1&is5#&9R|7|4iY>A-rIa2DCw0O-gW;pVoPIx5c9khu&S9DjdL8kS}`_ zc~Z>P0#pCB5f{FGvJ&Kf{5RA;{L7EK;rsXhhWg$A`m6fKzyDi2rD?lv7tEAVNy==~ z#Jm$GZE>CXXq}e2_R`5!^ zl=4x7^86A|04KT)_RxPYEYWYEa|L@1bzDDkW_iCQW z@aj_?4PT45A*KwiV|ETAjC#Vve0z?KVa1lBe$r-Jm>89i--pU4MfdJlg}QWo;tmCc z9iw~dNz`r&=j}N&mt@dw*9lp|Bl`D+|MC5{fnM%^mRKC#fi%;?KNCr&U%&r%)bIZ1 zf3JW1-+zZgThd+$XS$AtJBz-%+XpY_te19-^o2aUJZzR_a2sXsjZBjrjH2flG2LhS zz{WVI&U5A_*D%rG$c9YM%@fJo*1)@UwuJl@p~~J_!S54v0c>IOq)6-$`+NJj+t>c` ziF5EN=LxbRZqw8Q`TEK5jWhCE7WQB3!af#v&%MrX~5bq#epgR)5K)49T#+BO{yDLoE zPK)P3iEUNYw_mIPJzI#`6d*sIGZ!kJphVVdv`6f}|GTkVpE^vZ`5CP@@(##ejY>x_ z@Ij#Kx0mZsq1&mkmUg;5$3{*2lg>(tMUbI5897lFQ!UV#D|L9<6D$-!wUgtu!B!kl zYk^YQLhu%?{*m5avU%6NMUATZ{H5ANyX(Ch1z$}C;k_mXt~B8HG%$;Q{QbXQ>UV$r zS0iFeWUL6ZXi9nf-mXUJg%qERlopNt#fp{;+PSY&7wB?WZwHI> zZEEkZ7ow$XV6O*d{WJp2|h>1_dR12hE&FaBL1Pa(f@yhjEWo2=V#_hci>iSb``1 zLAh@_>(7PK?m-AKQSM~bAO3V*)c^V?d)*eZ{_v*<^7ymVgC_?GGQxv^imVrRmy%jq zAVr`w2J~ps8WenzLD>wO3YG@2^Ryf~lbIt5=>gd#F&Rl#1?X-PpEAgmItD-`vgu5> zMvvBXOgpMzy_;S{`E0CB6x9vc`v~dN{Fx6P`Q{_i56fViXg0T{NGM6*W2cU-#6${0atFph67om_aoPqUBaNl|4F4IOB?M<1zVpq#j&%4%!#*nILA+`WJyQ}O9M_MWCpxr!u z^TF-fsAKp>2m0u|!5ZQ+LP$=l+mF6ppxx*RWmqtTd&kT7=7L(2i+X!Ghxtx%(r@CZTi>S2468v0->2qw-NVtu^a78M@1< zo+cYoF&ZS=sUlhr*Qoc;@}tybGGe9+_XeJjA9ZxK>>V#J$3llmao(TrhuU>-qL saI#QwP6{pcYG)LFc)v$dk^bxd1A*D04t@QwZ~y=R07*qoM6N<$g4&gitpET3 literal 5095 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 Date: Wed, 10 Aug 2022 16:14:52 +0000 Subject: [PATCH 24/58] Adding new buttons in right panel --- .../infostand/InfoStandWidgetPetView.tsx | 215 +++++++++++++----- 1 file changed, 154 insertions(+), 61 deletions(-) diff --git a/src/components/room/widgets/avatar-info/infostand/InfoStandWidgetPetView.tsx b/src/components/room/widgets/avatar-info/infostand/InfoStandWidgetPetView.tsx index 7847f439..5d803b33 100644 --- a/src/components/room/widgets/avatar-info/infostand/InfoStandWidgetPetView.tsx +++ b/src/components/room/widgets/avatar-info/infostand/InfoStandWidgetPetView.tsx @@ -1,7 +1,9 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { FC } from 'react'; -import { AvatarInfoPet, LocalizeText } from '../../../../../api'; -import { Base, Column, Flex, LayoutPetImageView, Text, UserProfileIconView } from '../../../../../common'; +import { PetRespectComposer, PetType } from '@nitrots/nitro-renderer'; +import { FC, useEffect } from 'react'; +import { AvatarInfoPet, CreateLinkEvent, GetConfiguration, GetSessionDataManager, LocalizeText, SendMessageComposer } from '../../../../../api'; +import { Base, Button, Column, Flex, LayoutPetImageView, Text, UserProfileIconView } from '../../../../../common'; +import { usePets, useRoom } from '../../../../../hooks'; interface InfoStandWidgetPetViewProps { @@ -12,72 +14,163 @@ interface InfoStandWidgetPetViewProps export const InfoStandWidgetPetView: FC = props => { const { avatarInfo = null, onClose = null } = props; + const { roomSession = null } = useRoom(); + const { petRespect, changePetRespect } = usePets(); if(!avatarInfo) return null; + useEffect(() => + { + changePetRespect(avatarInfo.respectsPetLeft); + + }, [ avatarInfo ]); + + const processButtonAction = (action: string) => + { + let hideMenu = true; + + if (!action || action == '') return; + + switch (action) + { + case 'respect': + let newRespectsLeftChange = 0; + + changePetRespect(prevValue => + { + newRespectsLeftChange = (prevValue - 1); + + return newRespectsLeftChange; + }); + + GetSessionDataManager().givePetRespect(avatarInfo.id); + if(newRespectsLeftChange > 0) hideMenu = false; + break; + case 'buyfood': + CreateLinkEvent('catalog/open/' + GetConfiguration('catalog.links')['pets.buy_saddle']); + break; + case 'train': + // not coded + break; + case 'treat': + SendMessageComposer(new PetRespectComposer(avatarInfo.id)); + break; + case 'compost': + roomSession?.compostPlant(avatarInfo.id); + break; + case 'pick_up': + roomSession?.pickupPet(avatarInfo.id); + break; + } + + if(hideMenu) onClose(); + } + + useEffect(() => + { + changePetRespect(avatarInfo.respectsPetLeft); + + }, [ avatarInfo ]); + return ( - - - - - { avatarInfo.name } - - - { LocalizeText(`pet.breed.${ avatarInfo.petType }.${ avatarInfo.petBreed }`) } -


-
- - - - - - - { LocalizeText('pet.level', [ 'level', 'maxlevel' ], [ avatarInfo.level.toString(), avatarInfo.maximumLevel.toString() ]) } - - { LocalizeText('infostand.pet.text.happiness') } - - - { avatarInfo.happyness + '/' + avatarInfo.maximumHappyness } - - - + + + + + + { avatarInfo.name } + + + { LocalizeText(`pet.breed.${ avatarInfo.petType }.${ avatarInfo.petBreed }`) } +
+
+ + + + - - { LocalizeText('infostand.pet.text.experience') } - - - { avatarInfo.experience + '/' + avatarInfo.levelExperienceGoal } - - - + + { LocalizeText('pet.level', [ 'level', 'maxlevel' ], [ avatarInfo.level.toString(), avatarInfo.maximumLevel.toString() ]) } + + { LocalizeText('infostand.pet.text.happiness') } + + + { avatarInfo.happyness + '/' + avatarInfo.maximumHappyness } + + + + + + { LocalizeText('infostand.pet.text.experience') } + + + { avatarInfo.experience + '/' + avatarInfo.levelExperienceGoal } + + + + + + { LocalizeText('infostand.pet.text.energy') } + + + { avatarInfo.energy + '/' + avatarInfo.maximumEnergy } + + + + - - { LocalizeText('infostand.pet.text.energy') } - - - { avatarInfo.energy + '/' + avatarInfo.maximumEnergy } - - - - - - -
-
- - { LocalizeText('infostand.text.petrespect', [ 'count' ], [ avatarInfo.respect.toString() ]) } - { LocalizeText('pet.age', [ 'age' ], [ avatarInfo.age.toString() ]) } -
-
- - - - - { LocalizeText('infostand.text.petowner', [ 'name' ], [ avatarInfo.ownerName ]) } - - +
+
+
+ + { avatarInfo.petType !== PetType.MONSTERPLANT && + { LocalizeText('infostand.text.petrespect', [ 'count' ], [ avatarInfo.respect.toString() ]) } + } + { LocalizeText('pet.age', [ 'age' ], [ avatarInfo.age.toString() ]) } +
+
+ + + + + { LocalizeText('infostand.text.petowner', [ 'name' ], [ avatarInfo.ownerName ]) } + + +
+ + { avatarInfo.petType !== PetType.MONSTERPLANT && + + } + { avatarInfo.isOwner && avatarInfo.petType !== PetType.MONSTERPLANT && + + } + { !avatarInfo.dead && ((avatarInfo.energy / avatarInfo.maximumEnergy) < 0.98) && avatarInfo.petType === PetType.MONSTERPLANT && + + } + { roomSession?.isRoomOwner && avatarInfo.petType === PetType.MONSTERPLANT && + + } + { avatarInfo.isOwner && + + } + { (petRespect > 0) && avatarInfo.petType !== PetType.MONSTERPLANT && + + } + ); } From 058088b7896c31709b8a9083ec4eeef52c2c0106 Mon Sep 17 00:00:00 2001 From: object Date: Wed, 10 Aug 2022 16:24:22 +0000 Subject: [PATCH 25/58] Listening new states for the respects count --- .../menu/AvatarInfoWidgetOwnPetView.tsx | 37 +++++++++++-------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/src/components/room/widgets/avatar-info/menu/AvatarInfoWidgetOwnPetView.tsx b/src/components/room/widgets/avatar-info/menu/AvatarInfoWidgetOwnPetView.tsx index 107393b5..763a7a00 100644 --- a/src/components/room/widgets/avatar-info/menu/AvatarInfoWidgetOwnPetView.tsx +++ b/src/components/room/widgets/avatar-info/menu/AvatarInfoWidgetOwnPetView.tsx @@ -1,7 +1,7 @@ import { PetRespectComposer, PetType, RoomObjectCategory, RoomObjectType, RoomObjectVariable, RoomUnitGiveHandItemPetComposer } from '@nitrots/nitro-renderer'; import { FC, useEffect, useMemo, useState } from 'react'; import { AvatarInfoPet, CreateLinkEvent, GetConfiguration, GetOwnRoomObject, GetSessionDataManager, LocalizeText, SendMessageComposer } from '../../../../../api'; -import { useRoom } from '../../../../../hooks'; +import { usePets, useRoom } from '../../../../../hooks'; import { ContextMenuHeaderView } from '../../context-menu/ContextMenuHeaderView'; import { ContextMenuListItemView } from '../../context-menu/ContextMenuListItemView'; import { ContextMenuView } from '../../context-menu/ContextMenuView'; @@ -21,8 +21,14 @@ export const AvatarInfoWidgetOwnPetView: FC = p { const { avatarInfo = null, onClose = null } = props; const [ mode, setMode ] = useState(MODE_NORMAL); - const [ respectsLeft, setRespectsLeft ] = useState(0); const { roomSession = null } = useRoom(); + const { petRespect, changePetRespect } = usePets(); + + useEffect(() => + { + changePetRespect(avatarInfo.respectsPetLeft); + + }, [ avatarInfo ]); const canGiveHandItem = useMemo(() => { @@ -49,18 +55,18 @@ export const AvatarInfoWidgetOwnPetView: FC = p switch(name) { case 'respect': - let newRespectsLeft = 0; + let newRespectsLeftChange = 0; - setRespectsLeft(prevValue => + changePetRespect(prevValue => { - newRespectsLeft = (prevValue - 1); + newRespectsLeftChange = (prevValue - 1); - return newRespectsLeft; + return newRespectsLeftChange; }); GetSessionDataManager().givePetRespect(avatarInfo.id); - if(newRespectsLeft > 0) hideMenu = false; + if(newRespectsLeftChange > 0) hideMenu = false; break; case 'treat': SendMessageComposer(new PetRespectComposer(avatarInfo.id)); @@ -132,7 +138,8 @@ export const AvatarInfoWidgetOwnPetView: FC = p return MODE_NORMAL; }); - setRespectsLeft(avatarInfo.respectsPetLeft); + changePetRespect(avatarInfo.respectsPetLeft); + }, [ avatarInfo ]); return ( @@ -142,9 +149,9 @@ export const AvatarInfoWidgetOwnPetView: FC = p { (mode === MODE_NORMAL) && <> - { (respectsLeft > 0) && + { (petRespect > 0) && processAction('respect') }> - { LocalizeText('infostand.button.petrespect', [ 'count' ], [ respectsLeft.toString() ]) } + { LocalizeText('infostand.button.petrespect', [ 'count' ], [ petRespect.toString() ]) } } processAction('train') }> { LocalizeText('infostand.button.train') } @@ -170,9 +177,9 @@ export const AvatarInfoWidgetOwnPetView: FC = p { LocalizeText('infostand.button.toggle_riding_permission') } - { (respectsLeft > 0) && + { (petRespect > 0) && processAction('respect') }> - { LocalizeText('infostand.button.petrespect', [ 'count' ], [ respectsLeft.toString() ]) } + { LocalizeText('infostand.button.petrespect', [ 'count' ], [ petRespect.toString() ]) } } processAction('train') }> { LocalizeText('infostand.button.train') } @@ -189,9 +196,9 @@ export const AvatarInfoWidgetOwnPetView: FC = p processAction('dismount') }> { LocalizeText('infostand.button.dismount') } - { (respectsLeft > 0) && + { (petRespect > 0) && processAction('respect') }> - { LocalizeText('infostand.button.petrespect', [ 'count' ], [ respectsLeft.toString() ]) } + { LocalizeText('infostand.button.petrespect', [ 'count' ], [ petRespect.toString() ]) } } } { (mode === MODE_MONSTER_PLANT) && @@ -209,7 +216,7 @@ export const AvatarInfoWidgetOwnPetView: FC = p } { !avatarInfo.dead && ((avatarInfo.energy / avatarInfo.maximumEnergy) < 0.98) && processAction('treat') }> - { LocalizeText('infostand.button.treat') } + { LocalizeText('infostand.button.pettreat') } } { !avatarInfo.dead && (avatarInfo.level === avatarInfo.maximumLevel) && avatarInfo.breedable && <> From 6afbba964d29536d5b6731845be7473e63784941 Mon Sep 17 00:00:00 2001 From: object Date: Wed, 10 Aug 2022 16:29:43 +0000 Subject: [PATCH 26/58] Listening new state for respects and replace treat --- .../menu/AvatarInfoWidgetPetView.tsx | 37 +++++++++++-------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/src/components/room/widgets/avatar-info/menu/AvatarInfoWidgetPetView.tsx b/src/components/room/widgets/avatar-info/menu/AvatarInfoWidgetPetView.tsx index a4cc6721..29090b49 100644 --- a/src/components/room/widgets/avatar-info/menu/AvatarInfoWidgetPetView.tsx +++ b/src/components/room/widgets/avatar-info/menu/AvatarInfoWidgetPetView.tsx @@ -1,7 +1,7 @@ import { PetRespectComposer, PetType, RoomControllerLevel, RoomObjectCategory, RoomObjectType, RoomObjectVariable, RoomUnitGiveHandItemPetComposer } from '@nitrots/nitro-renderer'; import { FC, useEffect, useMemo, useState } from 'react'; import { AvatarInfoPet, GetOwnRoomObject, GetSessionDataManager, LocalizeText, SendMessageComposer } from '../../../../../api'; -import { useRoom } from '../../../../../hooks'; +import { usePets, useRoom } from '../../../../../hooks'; import { ContextMenuHeaderView } from '../../context-menu/ContextMenuHeaderView'; import { ContextMenuListItemView } from '../../context-menu/ContextMenuListItemView'; import { ContextMenuView } from '../../context-menu/ContextMenuView'; @@ -21,8 +21,14 @@ export const AvatarInfoWidgetPetView: FC = props = { const { avatarInfo = null, onClose = null } = props; const [ mode, setMode ] = useState(MODE_NORMAL); - const [ respectsLeft, setRespectsLeft ] = useState(0); const { roomSession = null } = useRoom(); + const { petRespect, changePetRespect } = usePets(); + + useEffect(() => + { + changePetRespect(avatarInfo.respectsPetLeft); + + }, [ avatarInfo ]); const canPickUp = useMemo(() => { @@ -54,18 +60,18 @@ export const AvatarInfoWidgetPetView: FC = props = switch(name) { case 'respect': - let newRespectsLeft = 0; + let newRespectsLeftChange = 0; - setRespectsLeft(prevValue => + changePetRespect(prevValue => { - newRespectsLeft = (prevValue - 1); + newRespectsLeftChange = (prevValue - 1); - return newRespectsLeft; + return newRespectsLeftChange; }); GetSessionDataManager().givePetRespect(avatarInfo.id); - if(newRespectsLeft > 0) hideMenu = false; + if(newRespectsLeftChange > 0) hideMenu = false; break; case 'treat': SendMessageComposer(new PetRespectComposer(avatarInfo.id)); @@ -99,7 +105,8 @@ export const AvatarInfoWidgetPetView: FC = props = return MODE_NORMAL; }); - setRespectsLeft(avatarInfo.respectsPetLeft); + changePetRespect(avatarInfo.respectsPetLeft); + }, [ avatarInfo ]); return ( @@ -107,9 +114,9 @@ export const AvatarInfoWidgetPetView: FC = props = { avatarInfo.name } - { (mode === MODE_NORMAL) && (respectsLeft > 0) && + { (mode === MODE_NORMAL) && (petRespect > 0) && processAction('respect') }> - { LocalizeText('infostand.button.petrespect', [ 'count' ], [ respectsLeft.toString() ]) } + { LocalizeText('infostand.button.petrespect', [ 'count' ], [ petRespect.toString() ]) } } { (mode === MODE_SADDLED_UP) && <> @@ -117,9 +124,9 @@ export const AvatarInfoWidgetPetView: FC = props = processAction('mount') }> { LocalizeText('infostand.button.mount') } } - { (respectsLeft > 0) && + { (petRespect > 0) && processAction('respect') }> - { LocalizeText('infostand.button.petrespect', [ 'count' ], [ respectsLeft.toString() ]) } + { LocalizeText('infostand.button.petrespect', [ 'count' ], [ petRespect.toString() ]) } } } { (mode === MODE_RIDING) && @@ -127,14 +134,14 @@ export const AvatarInfoWidgetPetView: FC = props = processAction('dismount') }> { LocalizeText('infostand.button.dismount') } - { (respectsLeft > 0) && + { (petRespect > 0) && processAction('respect') }> - { LocalizeText('infostand.button.petrespect', [ 'count' ], [ respectsLeft.toString() ]) } + { LocalizeText('infostand.button.petrespect', [ 'count' ], [ petRespect.toString() ]) } } } { (mode === MODE_MONSTER_PLANT) && !avatarInfo.dead && ((avatarInfo.energy / avatarInfo.maximumEnergy) < 0.98) && processAction('treat') }> - { LocalizeText('infostand.button.treat') } + { LocalizeText('infostand.button.pettreat') } } { canPickUp && processAction('pick_up') }> From 7b90987b293454ac1028a09ccc99ccafc4f12bea Mon Sep 17 00:00:00 2001 From: object Date: Wed, 10 Aug 2022 16:30:40 +0000 Subject: [PATCH 27/58] Add new global export --- src/hooks/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hooks/index.ts b/src/hooks/index.ts index 91a23d23..98a0d049 100644 --- a/src/hooks/index.ts +++ b/src/hooks/index.ts @@ -12,6 +12,7 @@ export * from './inventory'; export * from './mod-tools'; export * from './navigator'; export * from './notification'; +export * from './pets'; export * from './purse'; export * from './rooms'; export * from './session'; From d2b2c363aa49d9922d58dd0acf07eadcf5308e87 Mon Sep 17 00:00:00 2001 From: object Date: Wed, 10 Aug 2022 16:32:13 +0000 Subject: [PATCH 28/58] New hook for the pets --- src/hooks/pets/index.ts | 1 + src/hooks/pets/usePets.ts | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 src/hooks/pets/index.ts create mode 100644 src/hooks/pets/usePets.ts diff --git a/src/hooks/pets/index.ts b/src/hooks/pets/index.ts new file mode 100644 index 00000000..055b581e --- /dev/null +++ b/src/hooks/pets/index.ts @@ -0,0 +1 @@ +export * from './usePets'; diff --git a/src/hooks/pets/usePets.ts b/src/hooks/pets/usePets.ts new file mode 100644 index 00000000..6453458e --- /dev/null +++ b/src/hooks/pets/usePets.ts @@ -0,0 +1,16 @@ +import { useState } from 'react'; +import { useBetween } from 'use-between'; + +const usePetsState = () => +{ + const [ petRespect, setPetRespect ] = useState(0); + + const changePetRespect = (respects: React.SetStateAction) => + { + setPetRespect(respects); + } + + return { petRespect, setPetRespect, changePetRespect }; +} + +export const usePets = () => useBetween(usePetsState); From 6dc2b678caa7f3324202e33576fc875016e2dad2 Mon Sep 17 00:00:00 2001 From: Bill Date: Thu, 11 Aug 2022 13:26:07 -0400 Subject: [PATCH 29/58] Fix SelectReportedChatsView --- src/components/help/views/SelectReportedChatsView.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/help/views/SelectReportedChatsView.tsx b/src/components/help/views/SelectReportedChatsView.tsx index d83e6a02..0dfba492 100644 --- a/src/components/help/views/SelectReportedChatsView.tsx +++ b/src/components/help/views/SelectReportedChatsView.tsx @@ -21,6 +21,7 @@ export const SelectReportedChatsView: FC<{}> = props => return messengerHistory.filter(chat => (chat.entityId === activeReport.reportedUserId) && (chat.type === ChatEntryType.TYPE_IM)); } + return []; }, [ activeReport, chatHistory, messengerHistory ]); const selectChat = (chatEntry: IChatEntry) => @@ -62,7 +63,7 @@ export const SelectReportedChatsView: FC<{}> = props => { LocalizeText('help.emergency.chat_report.description') } - { !!!userChats.length && + { !userChats || !userChats.length && { LocalizeText('help.cfh.error.no_user_data') } } { (userChats.length > 0) && From 138b3d64e6c88590650c1c92b295617b471eca0c Mon Sep 17 00:00:00 2001 From: Bill Date: Thu, 11 Aug 2022 13:29:54 -0400 Subject: [PATCH 30/58] Fix change name --- src/components/help/HelpView.tsx | 29 +++++++++---------- .../help/views/name-change/NameChangeView.tsx | 6 ++-- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/src/components/help/HelpView.tsx b/src/components/help/HelpView.tsx index 7a257be7..e0df417c 100644 --- a/src/components/help/HelpView.tsx +++ b/src/components/help/HelpView.tsx @@ -70,8 +70,6 @@ export const HelpView: FC<{}> = props => setIsVisible(true); }, [ activeReport ]); - - if(!isVisible && !activeReport) return null; const CurrentStepView = () => { @@ -97,19 +95,20 @@ export const HelpView: FC<{}> = props => return ( <> - - - - - - - - - - - - - + { isVisible && + + + + + + + + + + + + + } diff --git a/src/components/help/views/name-change/NameChangeView.tsx b/src/components/help/views/name-change/NameChangeView.tsx index d4959efc..5cc76a9a 100644 --- a/src/components/help/views/name-change/NameChangeView.tsx +++ b/src/components/help/views/name-change/NameChangeView.tsx @@ -17,13 +17,11 @@ export const NameChangeView:FC<{}> = props => const [ layout, setLayout ] = useState(INIT); const [ newUsername, setNewUsername ] = useState(''); - const onHelpNameChangeEvent = useCallback((event: HelpNameChangeEvent) => + useUiEvent(HelpNameChangeEvent.INIT, event => { setLayout(INIT); setIsVisible(true); - }, []); - - useUiEvent(HelpNameChangeEvent.INIT, onHelpNameChangeEvent); + }); const onAction = useCallback((action: string, value?: string) => { From aeeb1aff87014472b0ed9871c447fc4db1bb1cb4 Mon Sep 17 00:00:00 2001 From: object Date: Fri, 12 Aug 2022 15:08:21 +0000 Subject: [PATCH 31/58] Fix / New input for trade amount --- .../views/furniture/InventoryTradeView.tsx | 47 +++++++++++++++---- 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/src/components/inventory/views/furniture/InventoryTradeView.tsx b/src/components/inventory/views/furniture/InventoryTradeView.tsx index 3de9eef8..9825dc28 100644 --- a/src/components/inventory/views/furniture/InventoryTradeView.tsx +++ b/src/components/inventory/views/furniture/InventoryTradeView.tsx @@ -12,6 +12,7 @@ interface InventoryTradeViewProps } const MAX_ITEMS_TO_TRADE: number = 9; +const MIN_VALUE: number = 1; export const InventoryTradeView: FC = props => { @@ -21,6 +22,7 @@ export const InventoryTradeView: FC = props => const [ otherGroupItem, setOtherGroupItem ] = useState(null); const [ filteredGroupItems, setFilteredGroupItems ] = useState(null); const [ countdownTick, setCountdownTick ] = useState(3); + const [ quantity, setQuantity ] = useState(1); const { ownUser = null, otherUser = null, groupItems = [], tradeState = TradeState.TRADING_STATE_READY, progressTrade = null, removeItem = null, setTradeState = null } = useInventoryTrade(); const { simpleAlert = null } = useNotification(); @@ -118,6 +120,24 @@ export const InventoryTradeView: FC = props => return } + const updateQuantity = (value: number | string, totalItemCount: number) => + { + if(isNaN(Number(value)) || Number(value) < 0 || value == '') value = 1; + + value = Math.max(Number(value), MIN_VALUE); + value = Math.min(Number(value), totalItemCount); + + if(value === quantity) return; + + setQuantity(value); + } + + const changeCount = (totalItemCount: number) => + { + updateQuantity(Number(quantity), totalItemCount); + attemptItemOffer(Number(quantity)); + } + useEffect(() => { if(tradeState !== TradeState.TRADING_STATE_COUNTDOWN) return; @@ -159,18 +179,29 @@ export const InventoryTradeView: FC = props => const count = item.getUnlockedCount(); return ( - (count && setGroupItem(item)) }> + (count && setGroupItem(item)) } onDoubleClick={ event => attemptItemOffer(1) }> { ((count > 0) && (groupItem === item)) && - } + + } ); }) } - - { groupItem ? groupItem.name : LocalizeText('catalog_selectproduct') } - + + + + setQuantity(event.target.value == '' || isNaN(event.target.valueAsNumber) || event.target.valueAsNumber < 0 ? '' : event.target.valueAsNumber) } /> + + + + + + + { groupItem ? groupItem.name : LocalizeText('catalog_selectproduct') } + + @@ -188,7 +219,7 @@ export const InventoryTradeView: FC = props => if(!item) return ; return ( - setOwnGroupItem(item) }> + setOwnGroupItem(item) } onDoubleClick={ event => removeItem(item)> { (ownGroupItem === item) && + { avatarInfo.isOwner && + + } + { avatarInfo.isOwner && + + } + { (petRespect > 0) && + + } + - + ); + } + + const InfoStandMonsterplantPet = () => + { + return ( + + + + + + { avatarInfo.name } + + + { LocalizeText(`pet.breed.${ avatarInfo.petType }.${ avatarInfo.petBreed }`) } +
+
+ + + + + + { !avatarInfo.dead && + + { LocalizeText('pet.level', [ 'level', 'maxlevel' ], [ avatarInfo.level.toString(), avatarInfo.maximumLevel.toString() ]) } + + } + +
+
+

+ + + { LocalizeText('infostand.pet.text.wellbeing') } + + + { avatarInfo.dead ? '00:00:00' : ConvertSeconds((remainingTimeToLive == 0 ? avatarInfo.remainingTimeToLive : remainingTimeToLive)).split(':')[1] + ':' + ConvertSeconds((remainingTimeToLive == null || remainingTimeToLive == undefined ? 0 : remainingTimeToLive)).split(':')[2] + ':' + ConvertSeconds((remainingTimeToLive == null || remainingTimeToLive == undefined ? 0 : remainingTimeToLive)).split(':')[3] } + + + + +

+

+ { remainingGrowTime != 0 && remainingGrowTime > 0 && + + { LocalizeText('infostand.pet.text.growth') }
+ +
+ } +

+

+ + { LocalizeText('Nivel de rareza:') } + + +

+ { LocalizeText('pet.age', [ 'age' ], [ avatarInfo.age.toString() ]) } +
+
+ + + + + { LocalizeText('infostand.text.petowner', [ 'name' ], [ avatarInfo.ownerName ]) } + + + +
+
+ + { !avatarInfo.dead && ((avatarInfo.energy / avatarInfo.maximumEnergy) < 0.98) && + + } + { roomSession?.isRoomOwner && + + } + { avatarInfo.isOwner && + + } + +
+ ); + } + + return ( + <> + { avatarInfo.petType !== PetType.MONSTERPLANT && + + } + { avatarInfo.petType === PetType.MONSTERPLANT && + + } + ); } From c0326644ad28306851eb6b75ae926d0ea146b57a Mon Sep 17 00:00:00 2001 From: Bill Date: Sun, 14 Aug 2022 00:28:02 -0400 Subject: [PATCH 40/58] Reset trade quantity, fix template --- .../views/furniture/InventoryTradeView.tsx | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/components/inventory/views/furniture/InventoryTradeView.tsx b/src/components/inventory/views/furniture/InventoryTradeView.tsx index 9825dc28..77337fcd 100644 --- a/src/components/inventory/views/furniture/InventoryTradeView.tsx +++ b/src/components/inventory/views/furniture/InventoryTradeView.tsx @@ -12,7 +12,6 @@ interface InventoryTradeViewProps } const MAX_ITEMS_TO_TRADE: number = 9; -const MIN_VALUE: number = 1; export const InventoryTradeView: FC = props => { @@ -22,7 +21,7 @@ export const InventoryTradeView: FC = props => const [ otherGroupItem, setOtherGroupItem ] = useState(null); const [ filteredGroupItems, setFilteredGroupItems ] = useState(null); const [ countdownTick, setCountdownTick ] = useState(3); - const [ quantity, setQuantity ] = useState(1); + const [ quantity, setQuantity ] = useState(1); const { ownUser = null, otherUser = null, groupItems = [], tradeState = TradeState.TRADING_STATE_READY, progressTrade = null, removeItem = null, setTradeState = null } = useInventoryTrade(); const { simpleAlert = null } = useNotification(); @@ -120,11 +119,11 @@ export const InventoryTradeView: FC = props => return } - const updateQuantity = (value: number | string, totalItemCount: number) => + const updateQuantity = (value: number, totalItemCount: number) => { - if(isNaN(Number(value)) || Number(value) < 0 || value == '') value = 1; + if(isNaN(Number(value)) || Number(value) < 0 || !value) value = 1; - value = Math.max(Number(value), MIN_VALUE); + value = Math.max(Number(value), 1); value = Math.min(Number(value), totalItemCount); if(value === quantity) return; @@ -134,10 +133,15 @@ export const InventoryTradeView: FC = props => const changeCount = (totalItemCount: number) => { - updateQuantity(Number(quantity), totalItemCount); - attemptItemOffer(Number(quantity)); + updateQuantity(quantity, totalItemCount); + attemptItemOffer(quantity); } + useEffect(() => + { + setQuantity(1); + }, [ groupItem ]); + useEffect(() => { if(tradeState !== TradeState.TRADING_STATE_COUNTDOWN) return; @@ -192,7 +196,7 @@ export const InventoryTradeView: FC = props => - setQuantity(event.target.value == '' || isNaN(event.target.valueAsNumber) || event.target.valueAsNumber < 0 ? '' : event.target.valueAsNumber) } /> + setQuantity(event.target.valueAsNumber) } /> @@ -219,11 +223,11 @@ export const InventoryTradeView: FC = props => if(!item) return ; return ( - setOwnGroupItem(item) } onDoubleClick={ event => removeItem(item)> + setOwnGroupItem(item) } onDoubleClick={ event => removeItem(item) }> { (ownGroupItem === item) && - } + } ); }) } From 55fe644e95c8f84cd983f4c3ff744510aa5d37ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berkay=20G=C3=BCnd=C3=BCz?= Date: Mon, 15 Aug 2022 04:23:49 +0300 Subject: [PATCH 41/58] Ability to change maximum wired message length --- public/ui-config.json.example | 1 + .../wired/views/actions/WiredActionBotTalkToAvatarView.tsx | 4 ++-- src/components/wired/views/actions/WiredActionBotTalkView.tsx | 4 ++-- src/components/wired/views/actions/WiredActionChatView.tsx | 4 ++-- .../wired/views/actions/WiredActionKickFromRoomView.tsx | 4 ++-- .../wired/views/actions/WiredActionMuteUserView.tsx | 4 ++-- 6 files changed, 11 insertions(+), 10 deletions(-) diff --git a/public/ui-config.json.example b/public/ui-config.json.example index 403bb68a..585a5319 100644 --- a/public/ui-config.json.example +++ b/public/ui-config.json.example @@ -16,6 +16,7 @@ "badge.descriptions.enabled": true, "motto.max.length": 38, "bot.name.max.length": 15, + "wired.message.max.length": "31", "navigator.room.models": [ { "clubLevel": 0, "tileSize": 104, "name": "a" }, { "clubLevel": 0, "tileSize": 94, "name": "b" }, diff --git a/src/components/wired/views/actions/WiredActionBotTalkToAvatarView.tsx b/src/components/wired/views/actions/WiredActionBotTalkToAvatarView.tsx index f2866e05..178c1983 100644 --- a/src/components/wired/views/actions/WiredActionBotTalkToAvatarView.tsx +++ b/src/components/wired/views/actions/WiredActionBotTalkToAvatarView.tsx @@ -1,5 +1,5 @@ import { FC, useEffect, useState } from 'react'; -import { LocalizeText, WiredFurniType, WIRED_STRING_DELIMETER } from '../../../../api'; +import { GetConfiguration, LocalizeText, WiredFurniType, WIRED_STRING_DELIMETER } from '../../../../api'; import { Column, Flex, Text } from '../../../../common'; import { useWired } from '../../../../hooks'; import { WiredActionBaseView } from './WiredActionBaseView'; @@ -35,7 +35,7 @@ export const WiredActionBotTalkToAvatarView: FC<{}> = props => { LocalizeText('wiredfurni.params.message') } - setMessage(event.target.value) } /> + ('wired.message.max.length') } value={ message } onChange={ event => setMessage(event.target.value) } /> diff --git a/src/components/wired/views/actions/WiredActionBotTalkView.tsx b/src/components/wired/views/actions/WiredActionBotTalkView.tsx index b457c431..6a4f1bb3 100644 --- a/src/components/wired/views/actions/WiredActionBotTalkView.tsx +++ b/src/components/wired/views/actions/WiredActionBotTalkView.tsx @@ -1,5 +1,5 @@ import { FC, useEffect, useState } from 'react'; -import { LocalizeText, WiredFurniType, WIRED_STRING_DELIMETER } from '../../../../api'; +import { GetConfiguration, LocalizeText, WiredFurniType, WIRED_STRING_DELIMETER } from '../../../../api'; import { Column, Flex, Text } from '../../../../common'; import { useWired } from '../../../../hooks'; import { WiredActionBaseView } from './WiredActionBaseView'; @@ -35,7 +35,7 @@ export const WiredActionBotTalkView: FC<{}> = props => { LocalizeText('wiredfurni.params.message') } - setMessage(event.target.value) } /> + ('wired.message.max.length') } value={ message } onChange={ event => setMessage(event.target.value) } /> diff --git a/src/components/wired/views/actions/WiredActionChatView.tsx b/src/components/wired/views/actions/WiredActionChatView.tsx index b570af7f..0a8d18ec 100644 --- a/src/components/wired/views/actions/WiredActionChatView.tsx +++ b/src/components/wired/views/actions/WiredActionChatView.tsx @@ -1,5 +1,5 @@ import { FC, useEffect, useState } from 'react'; -import { LocalizeText, WiredFurniType } from '../../../../api'; +import { GetConfiguration, LocalizeText, WiredFurniType } from '../../../../api'; import { Column, Text } from '../../../../common'; import { useWired } from '../../../../hooks'; import { WiredActionBaseView } from './WiredActionBaseView'; @@ -20,7 +20,7 @@ export const WiredActionChatView: FC<{}> = props => { LocalizeText('wiredfurni.params.message') } - setMessage(event.target.value) } maxLength={ 100 } /> + setMessage(event.target.value) } maxLength={ GetConfiguration('wired.message.max.length') } /> ); diff --git a/src/components/wired/views/actions/WiredActionKickFromRoomView.tsx b/src/components/wired/views/actions/WiredActionKickFromRoomView.tsx index e16b6684..b41bd1b1 100644 --- a/src/components/wired/views/actions/WiredActionKickFromRoomView.tsx +++ b/src/components/wired/views/actions/WiredActionKickFromRoomView.tsx @@ -1,5 +1,5 @@ import { FC, useEffect, useState } from 'react'; -import { LocalizeText, WiredFurniType } from '../../../../api'; +import { GetConfiguration, LocalizeText, WiredFurniType } from '../../../../api'; import { Column, Text } from '../../../../common'; import { useWired } from '../../../../hooks'; import { WiredActionBaseView } from './WiredActionBaseView'; @@ -20,7 +20,7 @@ export const WiredActionKickFromRoomView: FC<{}> = props => { LocalizeText('wiredfurni.params.message') } - setMessage(event.target.value) } maxLength={ 100 } /> + setMessage(event.target.value) } maxLength={ GetConfiguration('wired.message.max.length') } /> ); diff --git a/src/components/wired/views/actions/WiredActionMuteUserView.tsx b/src/components/wired/views/actions/WiredActionMuteUserView.tsx index e34bd60a..4df2d4e4 100644 --- a/src/components/wired/views/actions/WiredActionMuteUserView.tsx +++ b/src/components/wired/views/actions/WiredActionMuteUserView.tsx @@ -1,6 +1,6 @@ import { FC, useEffect, useState } from 'react'; import ReactSlider from 'react-slider'; -import { LocalizeText, WiredFurniType } from '../../../../api'; +import { GetConfiguration, LocalizeText, WiredFurniType } from '../../../../api'; import { Column, Text } from '../../../../common'; import { useWired } from '../../../../hooks'; import { WiredActionBaseView } from './WiredActionBaseView'; @@ -36,7 +36,7 @@ export const WiredActionMuteUserView: FC<{}> = props => { LocalizeText('wiredfurni.params.message') } - setMessage(event.target.value) } maxLength={ 100 } /> + setMessage(event.target.value) } maxLength={ GetConfiguration('wired.message.max.length') } /> ); From 96508ab5f2d3a1785707102c76a601e5803bbe31 Mon Sep 17 00:00:00 2001 From: object Date: Wed, 17 Aug 2022 01:52:00 +0000 Subject: [PATCH 42/58] Fix number stacktile --- .../furniture/FurnitureStackHeightView.tsx | 8 +++--- .../useFurnitureStackHeightWidget.ts | 28 +++++++++++++------ 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/components/room/widgets/furniture/FurnitureStackHeightView.tsx b/src/components/room/widgets/furniture/FurnitureStackHeightView.tsx index f3a73b6c..56ea477f 100644 --- a/src/components/room/widgets/furniture/FurnitureStackHeightView.tsx +++ b/src/components/room/widgets/furniture/FurnitureStackHeightView.tsx @@ -7,7 +7,7 @@ import { useFurnitureStackHeightWidget } from '../../../../hooks'; export const FurnitureStackHeightView: FC<{}> = props => { - const { objectId = -1, height = 0, maxHeight = 40, onClose = null, updateHeight = null } = useFurnitureStackHeightWidget(); + const { objectId = -1, height = 0, maxHeight = 40, onClose = null, setHeight = null } = useFurnitureStackHeightWidget(); if(objectId === -1) return null; @@ -22,10 +22,10 @@ export const FurnitureStackHeightView: FC<{}> = props => min={ 0 } max={ maxHeight } step={ 0.01 } - value={ height } - onChange={ event => updateHeight(event) } + value={ isNaN(parseFloat(height.toString())) ? 0 : parseFloat(height.toString()) } + onChange={ event => setHeight(parseFloat(event.toString())) } renderThumb={ (props, state) =>
{ state.valueNow }
} /> - updateHeight(parseFloat(event.target.value)) } /> + setHeight(parseFloat(event.target.value)) } /> } - From 1778204e19c748840aa5baf23f7a9d152c70abf0 Mon Sep 17 00:00:00 2001 From: Bill Date: Wed, 17 Aug 2022 18:44:50 -0400 Subject: [PATCH 45/58] Update FurnitureStackHeightWidget --- .../furniture/FurnitureStackHeightView.tsx | 27 ++++++++++++++---- .../useFurnitureStackHeightWidget.ts | 28 ++++++------------- 2 files changed, 30 insertions(+), 25 deletions(-) diff --git a/src/components/room/widgets/furniture/FurnitureStackHeightView.tsx b/src/components/room/widgets/furniture/FurnitureStackHeightView.tsx index 56ea477f..d4d1039f 100644 --- a/src/components/room/widgets/furniture/FurnitureStackHeightView.tsx +++ b/src/components/room/widgets/furniture/FurnitureStackHeightView.tsx @@ -1,5 +1,5 @@ import { FurnitureStackHeightComposer } from '@nitrots/nitro-renderer'; -import { FC } from 'react'; +import { FC, useEffect, useState } from 'react'; import ReactSlider from 'react-slider'; import { LocalizeText, SendMessageComposer } from '../../../../api'; import { Button, Column, Flex, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../../common'; @@ -7,7 +7,24 @@ import { useFurnitureStackHeightWidget } from '../../../../hooks'; export const FurnitureStackHeightView: FC<{}> = props => { - const { objectId = -1, height = 0, maxHeight = 40, onClose = null, setHeight = null } = useFurnitureStackHeightWidget(); + const { objectId = -1, height = 0, maxHeight = 40, onClose = null, updateHeight = null } = useFurnitureStackHeightWidget(); + const [ tempHeight, setTempHeight ] = useState(''); + + const updateTempHeight = (value: string) => + { + setTempHeight(value); + + const newValue = parseFloat(value); + + if(isNaN(newValue) || (newValue === height)) return; + + updateHeight(newValue); + } + + useEffect(() => + { + setTempHeight(height.toString()); + }, [ height ]); if(objectId === -1) return null; @@ -22,10 +39,10 @@ export const FurnitureStackHeightView: FC<{}> = props => min={ 0 } max={ maxHeight } step={ 0.01 } - value={ isNaN(parseFloat(height.toString())) ? 0 : parseFloat(height.toString()) } - onChange={ event => setHeight(parseFloat(event.toString())) } + value={ height } + onChange={ event => updateHeight(event) } renderThumb={ (props, state) =>
{ state.valueNow }
} /> - setHeight(parseFloat(event.target.value)) } /> + updateTempHeight(event.target.value) } /> - } - { avatarInfo.isOwner && avatarInfo.petType !== PetType.MONSTERPLANT && + } + { avatarInfo.isOwner && (avatarInfo.petType !== PetType.MONSTERPLANT) && - } + } { !avatarInfo.dead && ((avatarInfo.energy / avatarInfo.maximumEnergy) < 0.98) && avatarInfo.petType === PetType.MONSTERPLANT && - } + } { roomSession?.isRoomOwner && avatarInfo.petType === PetType.MONSTERPLANT && - } + } { avatarInfo.isOwner && - } - { (petRespect > 0) && avatarInfo.petType !== PetType.MONSTERPLANT && + } + { (petRespectRemaining > 0) && (avatarInfo.petType !== PetType.MONSTERPLANT) && - } + { LocalizeText('infostand.button.petrespect', [ 'count' ], [ petRespectRemaining.toString() ]) } + } ); diff --git a/src/components/room/widgets/avatar-info/menu/AvatarInfoWidgetAvatarView.tsx b/src/components/room/widgets/avatar-info/menu/AvatarInfoWidgetAvatarView.tsx index 3a4185aa..9556888e 100644 --- a/src/components/room/widgets/avatar-info/menu/AvatarInfoWidgetAvatarView.tsx +++ b/src/components/room/widgets/avatar-info/menu/AvatarInfoWidgetAvatarView.tsx @@ -3,7 +3,7 @@ import { RoomControllerLevel, RoomObjectCategory, RoomObjectVariable, RoomUnitGi import { FC, useEffect, useMemo, useState } from 'react'; import { AvatarInfoUser, CreateLinkEvent, DispatchUiEvent, GetOwnRoomObject, GetSessionDataManager, GetUserProfile, LocalizeText, MessengerFriend, ReportType, RoomWidgetUpdateChatInputContentEvent, SendMessageComposer } from '../../../../../api'; import { Base, Flex } from '../../../../../common'; -import { useFriends, useHelp, useRoom } from '../../../../../hooks'; +import { useFriends, useHelp, useRoom, useSessionInfo } from '../../../../../hooks'; import { ContextMenuHeaderView } from '../../context-menu/ContextMenuHeaderView'; import { ContextMenuListItemView } from '../../context-menu/ContextMenuListItemView'; import { ContextMenuView } from '../../context-menu/ContextMenuView'; @@ -26,10 +26,10 @@ export const AvatarInfoWidgetAvatarView: FC = p { const { avatarInfo = null, onClose = null } = props; const [ mode, setMode ] = useState(MODE_NORMAL); - const [ respectsLeft, setRespectsLeft ] = useState(0); const { canRequestFriend = null } = useFriends(); const { report = null } = useHelp(); const { roomSession = null } = useRoom(); + const { userRespectRemaining = 0, respectUser = null } = useSessionInfo(); const isShowGiveRights = useMemo(() => { @@ -113,13 +113,9 @@ export const AvatarInfoWidgetAvatarView: FC = p setMode(MODE_RELATIONSHIP); break; case 'respect': { - let newRespectsLeft = (respectsLeft - 1); - - setRespectsLeft(newRespectsLeft); + respectUser(avatarInfo.webID); - GetSessionDataManager().giveRespect(avatarInfo.webID); - - if(newRespectsLeft > 0) hideMenu = false; + if((userRespectRemaining - 1) >= 1) hideMenu = false; break; } case 'ignore': @@ -203,7 +199,6 @@ export const AvatarInfoWidgetAvatarView: FC = p useEffect(() => { setMode(MODE_NORMAL); - setRespectsLeft(avatarInfo.respectLeft); }, [ avatarInfo ]); return ( @@ -223,9 +218,9 @@ export const AvatarInfoWidgetAvatarView: FC = p processAction('whisper') }> { LocalizeText('infostand.button.whisper') } - { (respectsLeft > 0) && + { (userRespectRemaining > 0) && processAction('respect') }> - { LocalizeText('infostand.button.respect', [ 'count' ], [ respectsLeft.toString() ]) } + { LocalizeText('infostand.button.respect', [ 'count' ], [ userRespectRemaining.toString() ]) } } { !canRequestFriend(avatarInfo.webID) && processAction('relationship') }> diff --git a/src/components/room/widgets/avatar-info/menu/AvatarInfoWidgetOwnPetView.tsx b/src/components/room/widgets/avatar-info/menu/AvatarInfoWidgetOwnPetView.tsx index 763a7a00..af889c12 100644 --- a/src/components/room/widgets/avatar-info/menu/AvatarInfoWidgetOwnPetView.tsx +++ b/src/components/room/widgets/avatar-info/menu/AvatarInfoWidgetOwnPetView.tsx @@ -1,7 +1,7 @@ import { PetRespectComposer, PetType, RoomObjectCategory, RoomObjectType, RoomObjectVariable, RoomUnitGiveHandItemPetComposer } from '@nitrots/nitro-renderer'; import { FC, useEffect, useMemo, useState } from 'react'; -import { AvatarInfoPet, CreateLinkEvent, GetConfiguration, GetOwnRoomObject, GetSessionDataManager, LocalizeText, SendMessageComposer } from '../../../../../api'; -import { usePets, useRoom } from '../../../../../hooks'; +import { AvatarInfoPet, CreateLinkEvent, GetConfiguration, GetOwnRoomObject, LocalizeText, SendMessageComposer } from '../../../../../api'; +import { useRoom, useSessionInfo } from '../../../../../hooks'; import { ContextMenuHeaderView } from '../../context-menu/ContextMenuHeaderView'; import { ContextMenuListItemView } from '../../context-menu/ContextMenuListItemView'; import { ContextMenuView } from '../../context-menu/ContextMenuView'; @@ -22,13 +22,7 @@ export const AvatarInfoWidgetOwnPetView: FC = p const { avatarInfo = null, onClose = null } = props; const [ mode, setMode ] = useState(MODE_NORMAL); const { roomSession = null } = useRoom(); - const { petRespect, changePetRespect } = usePets(); - - useEffect(() => - { - changePetRespect(avatarInfo.respectsPetLeft); - - }, [ avatarInfo ]); + const { petRespectRemaining = 0, respectPet = null } = useSessionInfo(); const canGiveHandItem = useMemo(() => { @@ -55,18 +49,9 @@ export const AvatarInfoWidgetOwnPetView: FC = p switch(name) { case 'respect': - let newRespectsLeftChange = 0; + respectPet(avatarInfo.id); - changePetRespect(prevValue => - { - newRespectsLeftChange = (prevValue - 1); - - return newRespectsLeftChange; - }); - - GetSessionDataManager().givePetRespect(avatarInfo.id); - - if(newRespectsLeftChange > 0) hideMenu = false; + if((petRespectRemaining - 1) >= 1) hideMenu = false; break; case 'treat': SendMessageComposer(new PetRespectComposer(avatarInfo.id)); @@ -137,9 +122,6 @@ export const AvatarInfoWidgetOwnPetView: FC = p return MODE_NORMAL; }); - - changePetRespect(avatarInfo.respectsPetLeft); - }, [ avatarInfo ]); return ( @@ -149,9 +131,9 @@ export const AvatarInfoWidgetOwnPetView: FC = p { (mode === MODE_NORMAL) && <> - { (petRespect > 0) && + { (petRespectRemaining > 0) && processAction('respect') }> - { LocalizeText('infostand.button.petrespect', [ 'count' ], [ petRespect.toString() ]) } + { LocalizeText('infostand.button.petrespect', [ 'count' ], [ petRespectRemaining.toString() ]) } } processAction('train') }> { LocalizeText('infostand.button.train') } @@ -177,9 +159,9 @@ export const AvatarInfoWidgetOwnPetView: FC = p { LocalizeText('infostand.button.toggle_riding_permission') } - { (petRespect > 0) && + { (petRespectRemaining > 0) && processAction('respect') }> - { LocalizeText('infostand.button.petrespect', [ 'count' ], [ petRespect.toString() ]) } + { LocalizeText('infostand.button.petrespect', [ 'count' ], [ petRespectRemaining.toString() ]) } } processAction('train') }> { LocalizeText('infostand.button.train') } @@ -196,9 +178,9 @@ export const AvatarInfoWidgetOwnPetView: FC = p processAction('dismount') }> { LocalizeText('infostand.button.dismount') } - { (petRespect > 0) && + { (petRespectRemaining > 0) && processAction('respect') }> - { LocalizeText('infostand.button.petrespect', [ 'count' ], [ petRespect.toString() ]) } + { LocalizeText('infostand.button.petrespect', [ 'count' ], [ petRespectRemaining.toString() ]) } } } { (mode === MODE_MONSTER_PLANT) && diff --git a/src/components/room/widgets/avatar-info/menu/AvatarInfoWidgetPetView.tsx b/src/components/room/widgets/avatar-info/menu/AvatarInfoWidgetPetView.tsx index 29090b49..4219ace9 100644 --- a/src/components/room/widgets/avatar-info/menu/AvatarInfoWidgetPetView.tsx +++ b/src/components/room/widgets/avatar-info/menu/AvatarInfoWidgetPetView.tsx @@ -1,7 +1,7 @@ import { PetRespectComposer, PetType, RoomControllerLevel, RoomObjectCategory, RoomObjectType, RoomObjectVariable, RoomUnitGiveHandItemPetComposer } from '@nitrots/nitro-renderer'; import { FC, useEffect, useMemo, useState } from 'react'; import { AvatarInfoPet, GetOwnRoomObject, GetSessionDataManager, LocalizeText, SendMessageComposer } from '../../../../../api'; -import { usePets, useRoom } from '../../../../../hooks'; +import { useRoom, useSessionInfo } from '../../../../../hooks'; import { ContextMenuHeaderView } from '../../context-menu/ContextMenuHeaderView'; import { ContextMenuListItemView } from '../../context-menu/ContextMenuListItemView'; import { ContextMenuView } from '../../context-menu/ContextMenuView'; @@ -22,13 +22,7 @@ export const AvatarInfoWidgetPetView: FC = props = const { avatarInfo = null, onClose = null } = props; const [ mode, setMode ] = useState(MODE_NORMAL); const { roomSession = null } = useRoom(); - const { petRespect, changePetRespect } = usePets(); - - useEffect(() => - { - changePetRespect(avatarInfo.respectsPetLeft); - - }, [ avatarInfo ]); + const { petRespectRemaining = 0, respectPet = null } = useSessionInfo(); const canPickUp = useMemo(() => { @@ -60,18 +54,9 @@ export const AvatarInfoWidgetPetView: FC = props = switch(name) { case 'respect': - let newRespectsLeftChange = 0; + respectPet(avatarInfo.id); - changePetRespect(prevValue => - { - newRespectsLeftChange = (prevValue - 1); - - return newRespectsLeftChange; - }); - - GetSessionDataManager().givePetRespect(avatarInfo.id); - - if(newRespectsLeftChange > 0) hideMenu = false; + if((petRespectRemaining - 1) >= 1) hideMenu = false; break; case 'treat': SendMessageComposer(new PetRespectComposer(avatarInfo.id)); @@ -104,9 +89,6 @@ export const AvatarInfoWidgetPetView: FC = props = return MODE_NORMAL; }); - - changePetRespect(avatarInfo.respectsPetLeft); - }, [ avatarInfo ]); return ( @@ -114,9 +96,9 @@ export const AvatarInfoWidgetPetView: FC = props = { avatarInfo.name } - { (mode === MODE_NORMAL) && (petRespect > 0) && + { (mode === MODE_NORMAL) && (petRespectRemaining > 0) && processAction('respect') }> - { LocalizeText('infostand.button.petrespect', [ 'count' ], [ petRespect.toString() ]) } + { LocalizeText('infostand.button.petrespect', [ 'count' ], [ petRespectRemaining.toString() ]) } } { (mode === MODE_SADDLED_UP) && <> @@ -124,9 +106,9 @@ export const AvatarInfoWidgetPetView: FC = props = processAction('mount') }> { LocalizeText('infostand.button.mount') } } - { (petRespect > 0) && + { (petRespectRemaining > 0) && processAction('respect') }> - { LocalizeText('infostand.button.petrespect', [ 'count' ], [ petRespect.toString() ]) } + { LocalizeText('infostand.button.petrespect', [ 'count' ], [ petRespectRemaining.toString() ]) } } } { (mode === MODE_RIDING) && @@ -134,9 +116,9 @@ export const AvatarInfoWidgetPetView: FC = props = processAction('dismount') }> { LocalizeText('infostand.button.dismount') } - { (petRespect > 0) && + { (petRespectRemaining > 0) && processAction('respect') }> - { LocalizeText('infostand.button.petrespect', [ 'count' ], [ petRespect.toString() ]) } + { LocalizeText('infostand.button.petrespect', [ 'count' ], [ petRespectRemaining.toString() ]) } } } { (mode === MODE_MONSTER_PLANT) && !avatarInfo.dead && ((avatarInfo.energy / avatarInfo.maximumEnergy) < 0.98) && diff --git a/src/hooks/index.ts b/src/hooks/index.ts index 98a0d049..91a23d23 100644 --- a/src/hooks/index.ts +++ b/src/hooks/index.ts @@ -12,7 +12,6 @@ export * from './inventory'; export * from './mod-tools'; export * from './navigator'; export * from './notification'; -export * from './pets'; export * from './purse'; export * from './rooms'; export * from './session'; diff --git a/src/hooks/pets/index.ts b/src/hooks/pets/index.ts deleted file mode 100644 index 055b581e..00000000 --- a/src/hooks/pets/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './usePets'; diff --git a/src/hooks/pets/usePets.ts b/src/hooks/pets/usePets.ts deleted file mode 100644 index 6453458e..00000000 --- a/src/hooks/pets/usePets.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { useState } from 'react'; -import { useBetween } from 'use-between'; - -const usePetsState = () => -{ - const [ petRespect, setPetRespect ] = useState(0); - - const changePetRespect = (respects: React.SetStateAction) => - { - setPetRespect(respects); - } - - return { petRespect, setPetRespect, changePetRespect }; -} - -export const usePets = () => useBetween(usePetsState); diff --git a/src/hooks/session/useSessionInfo.ts b/src/hooks/session/useSessionInfo.ts index faff5dca..911e4d0c 100644 --- a/src/hooks/session/useSessionInfo.ts +++ b/src/hooks/session/useSessionInfo.ts @@ -1,7 +1,7 @@ import { FigureUpdateEvent, RoomUnitChatStyleComposer, UserInfoDataParser, UserInfoEvent, UserSettingsEvent } from '@nitrots/nitro-renderer'; import { useState } from 'react'; import { useBetween } from 'use-between'; -import { SendMessageComposer } from '../../api'; +import { GetSessionDataManager, SendMessageComposer } from '../../api'; import { useMessageEvent } from '../events'; const useSessionInfoState = () => @@ -9,6 +9,8 @@ const useSessionInfoState = () => const [ userInfo, setUserInfo ] = useState(null); const [ userFigure, setUserFigure ] = useState(null); const [ chatStyleId, setChatStyleId ] = useState(0); + const [ userRespectRemaining, setUserRespectRemaining ] = useState(0); + const [ petRespectRemaining, setPetRespectRemaining ] = useState(0); const updateChatStyleId = (styleId: number) => { @@ -17,12 +19,28 @@ const useSessionInfoState = () => SendMessageComposer(new RoomUnitChatStyleComposer(styleId)); } + const respectUser = (userId: number) => + { + GetSessionDataManager().giveRespect(userId); + + setUserRespectRemaining(GetSessionDataManager().respectsLeft); + } + + const respectPet = (petId: number) => + { + GetSessionDataManager().givePetRespect(petId); + + setPetRespectRemaining(GetSessionDataManager().respectsPetLeft); + } + useMessageEvent(UserInfoEvent, event => { const parser = event.getParser(); setUserInfo(parser.userInfo); setUserFigure(parser.userInfo.figure); + setUserRespectRemaining(parser.userInfo.respectsRemaining); + setPetRespectRemaining(parser.userInfo.respectsPetRemaining); }); useMessageEvent(FigureUpdateEvent, event => @@ -39,7 +57,7 @@ const useSessionInfoState = () => setChatStyleId(parser.chatType); }); - return { userInfo, userFigure, chatStyleId, updateChatStyleId }; + return { userInfo, userFigure, chatStyleId, userRespectRemaining, petRespectRemaining, respectUser, respectPet, updateChatStyleId }; } export const useSessionInfo = () => useBetween(useSessionInfoState); From 2b6bf323da9ef7ea274ab57d6a97ae00f89c063b Mon Sep 17 00:00:00 2001 From: Bill Date: Wed, 17 Aug 2022 23:01:22 -0400 Subject: [PATCH 47/58] Update monsterplant infostand --- src/common/layout/LayoutCounterTimeView.tsx | 54 ++++++------------- src/common/layout/LayoutPetImageView.tsx | 31 ++++++++--- .../infostand/InfoStandWidgetPetView.tsx | 34 +++++------- 3 files changed, 55 insertions(+), 64 deletions(-) diff --git a/src/common/layout/LayoutCounterTimeView.tsx b/src/common/layout/LayoutCounterTimeView.tsx index 36150820..7460b054 100644 --- a/src/common/layout/LayoutCounterTimeView.tsx +++ b/src/common/layout/LayoutCounterTimeView.tsx @@ -1,6 +1,7 @@ import { FC, useMemo } from 'react'; -import { Base, BaseProps, Column, Flex, Text } from '..'; import { LocalizeText } from '../../api'; +import { Base, BaseProps } from '../Base'; +import { Flex } from '../Flex'; interface LayoutCounterTimeViewProps extends BaseProps { @@ -24,42 +25,19 @@ export const LayoutCounterTimeView: FC = props => }, [ classNames ]); return ( - <> - - - - -
{ day != '00' ? day : hour }
- { children } - - { day != '00' ? LocalizeText('countdown_clock_unit_days') : LocalizeText('countdown_clock_unit_hours') } -
- - - : - - - - -
{ minutes }
- { children } - - { LocalizeText('countdown_clock_unit_minutes') } -
- - - : - - - - -
{ seconds }
- { children } - - { LocalizeText('countdown_clock_unit_seconds') } -
-
-
- + + +
{ day != '00' ? day : hour }{ day != '00' ? LocalizeText('countdown_clock_unit_days') : LocalizeText('countdown_clock_unit_hours') }
+ + : + +
{ minutes }{ LocalizeText('countdown_clock_unit_minutes') }
+ + : + +
{ seconds }{ LocalizeText('countdown_clock_unit_seconds') }
+ + { children } +
); } diff --git a/src/common/layout/LayoutPetImageView.tsx b/src/common/layout/LayoutPetImageView.tsx index 6d4677be..e504fce2 100644 --- a/src/common/layout/LayoutPetImageView.tsx +++ b/src/common/layout/LayoutPetImageView.tsx @@ -20,6 +20,8 @@ export const LayoutPetImageView: FC = props => { const { figure = '', typeId = -1, paletteId = -1, petColor = 0xFFFFFF, customParts = [], posture = 'std', headOnly = false, direction = 0, scale = 1, style = {}, ...rest } = props; const [ petUrl, setPetUrl ] = useState(null); + const [ width, setWidth ] = useState(0); + const [ height, setHeight ] = useState(0); const isDisposed = useRef(false); const getStyle = useMemo(() => @@ -35,10 +37,13 @@ export const LayoutPetImageView: FC = props => if(!(scale % 1)) newStyle.imageRendering = 'pixelated'; } + newStyle.width = width; + newStyle.height = height; + if(Object.keys(style).length) newStyle = { ...newStyle, ...style }; return newStyle; - }, [ petUrl, scale, style ]); + }, [ petUrl, scale, style, width, height ]); useEffect(() => { @@ -67,8 +72,19 @@ export const LayoutPetImageView: FC = props => { if(isDisposed.current) return; - if(image) setPetUrl(image.src); - else if(texture) setPetUrl(TextureUtils.generateImageUrl(texture)); + if(image) + { + setPetUrl(image.src); + setWidth(image.width); + setHeight(image.height); + } + + else if(texture) + { + setPetUrl(TextureUtils.generateImageUrl(texture)); + setWidth(texture.width); + setHeight(texture.height); + } }, imageFailed: (id) => { @@ -80,9 +96,12 @@ export const LayoutPetImageView: FC = props => { const image = imageResult.getImage(); - if(image) setPetUrl(image.src); - - + if(image) + { + setPetUrl(image.src); + setWidth(image.width); + setHeight(image.height); + } } }, [ figure, typeId, paletteId, petColor, customParts, posture, headOnly, direction ]); diff --git a/src/components/room/widgets/avatar-info/infostand/InfoStandWidgetPetView.tsx b/src/components/room/widgets/avatar-info/infostand/InfoStandWidgetPetView.tsx index f3f2f5db..a590b785 100644 --- a/src/components/room/widgets/avatar-info/infostand/InfoStandWidgetPetView.tsx +++ b/src/components/room/widgets/avatar-info/infostand/InfoStandWidgetPetView.tsx @@ -1,8 +1,8 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { PetRespectComposer, PetType } from '@nitrots/nitro-renderer'; import { FC, useEffect, useState } from 'react'; -import { AvatarInfoPet, CreateLinkEvent, GetConfiguration, LocalizeText, SendMessageComposer, ConvertSeconds } from '../../../../../api'; -import { Base, Button, Column, Flex, LayoutPetImageView, LayoutRarityLevelView, Text, UserProfileIconView, LayoutCounterTimeView } from '../../../../../common'; +import { AvatarInfoPet, ConvertSeconds, CreateLinkEvent, GetConfiguration, LocalizeText, SendMessageComposer } from '../../../../../api'; +import { Base, Button, Column, Flex, LayoutCounterTimeView, LayoutPetImageView, LayoutRarityLevelView, Text, UserProfileIconView } from '../../../../../common'; import { useRoom, useSessionInfo } from '../../../../../hooks'; interface InfoStandWidgetPetViewProps @@ -87,19 +87,15 @@ export const InfoStandWidgetPetView: FC = props =>
{ (avatarInfo.petType === PetType.MONSTERPLANT) && <> - - - - - - { !avatarInfo.dead && - - { LocalizeText('pet.level', [ 'level', 'maxlevel' ], [ avatarInfo.level.toString(), avatarInfo.maximumLevel.toString() ]) } - } - + +
- + + { !avatarInfo.dead && + + { LocalizeText('pet.level', [ 'level', 'maxlevel' ], [ avatarInfo.level.toString(), avatarInfo.maximumLevel.toString() ]) } + } { LocalizeText('infostand.pet.text.wellbeing') } @@ -109,20 +105,18 @@ export const InfoStandWidgetPetView: FC = props => -

-

{ remainingGrowTime != 0 && remainingGrowTime > 0 && - { LocalizeText('infostand.pet.text.growth') }
+ { LocalizeText('infostand.pet.text.growth') }
} -

-

- { LocalizeText('Nivel de rareza:') } + { LocalizeText('infostand.pet.text.raritylevel', [ 'level' ], [ LocalizeText(`infostand.pet.raritylevel.${ avatarInfo.rarityLevel }`) ]) } -

+
+
+ { LocalizeText('pet.age', [ 'age' ], [ avatarInfo.age.toString() ]) }
From 6f191f518ebda3396334214427bc6be244f62f25 Mon Sep 17 00:00:00 2001 From: Bill Date: Wed, 17 Aug 2022 23:05:48 -0400 Subject: [PATCH 48/58] Update the place function --- .../widgets/furniture/FurnitureGiftOpeningView.tsx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/components/room/widgets/furniture/FurnitureGiftOpeningView.tsx b/src/components/room/widgets/furniture/FurnitureGiftOpeningView.tsx index 1478a3bd..75ffe8ba 100644 --- a/src/components/room/widgets/furniture/FurnitureGiftOpeningView.tsx +++ b/src/components/room/widgets/furniture/FurnitureGiftOpeningView.tsx @@ -6,15 +6,16 @@ import { useFurniturePresentWidget, useInventoryFurni } from '../../../../hooks' export const FurnitureGiftOpeningView: FC<{}> = props => { const { objectId = -1, classId = -1, itemType = null, text = null, isOwnerOfFurniture = false, senderName = null, senderFigure = null, placedItemId = -1, placedItemType = null, placedInRoom = false, imageUrl = null, openPresent = null, onClose = null } = useFurniturePresentWidget(); - const { groupItems = null } = useInventoryFurni(); + const { groupItems = [] } = useInventoryFurni(); if(objectId === -1) return null; - const putFurni = (itemId: number) => + const place = (itemId: number) => { - const furni = groupItems?.filter(group => group.items[0].ref == itemId); + const groupItem = groupItems.find(group => (group.getItemById(itemId)?.id === itemId)); + + if(groupItem) attemptItemPlacement(groupItem); - attemptItemPlacement(furni[0]); onClose(); } @@ -54,7 +55,7 @@ export const FurnitureGiftOpeningView: FC<{}> = props => } - From dd728d240179aefc135c69ad6056da559fc35ca4 Mon Sep 17 00:00:00 2001 From: Bill Date: Thu, 18 Aug 2022 00:00:24 -0400 Subject: [PATCH 49/58] Update catalog scrolling --- .../views/navigation/CatalogNavigationItemView.tsx | 14 +++++++++++--- .../views/navigation/CatalogNavigationView.tsx | 2 +- .../page/widgets/CatalogBundleGridWidgetView.tsx | 10 ++++++++-- .../page/widgets/CatalogItemGridWidgetView.tsx | 10 ++++++++-- .../views/page/widgets/CatalogSpacesWidgetView.tsx | 10 ++++++++-- 5 files changed, 36 insertions(+), 10 deletions(-) diff --git a/src/components/catalog/views/navigation/CatalogNavigationItemView.tsx b/src/components/catalog/views/navigation/CatalogNavigationItemView.tsx index 9179edba..b855caa6 100644 --- a/src/components/catalog/views/navigation/CatalogNavigationItemView.tsx +++ b/src/components/catalog/views/navigation/CatalogNavigationItemView.tsx @@ -1,5 +1,5 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { FC } from 'react'; +import { FC, useRef } from 'react'; import { ICatalogNode } from '../../../../api'; import { Base, LayoutGridItem, Text } from '../../../../common'; import { useCatalog } from '../../../../hooks'; @@ -16,10 +16,18 @@ export const CatalogNavigationItemView: FC = pro { const { node = null, child = false } = props; const { activateNode = null } = useCatalog(); + const elementRef = useRef(); + + const selectNode = () => + { + if(node.isBranch && !node.isActive) elementRef?.current?.scrollIntoView(); + + activateNode(node); + } return ( - - activateNode(node) } className={ child ? 'inset' : '' }> + + { node.localization } { node.isBranch && diff --git a/src/components/catalog/views/navigation/CatalogNavigationView.tsx b/src/components/catalog/views/navigation/CatalogNavigationView.tsx index 3924928d..2d03f06d 100644 --- a/src/components/catalog/views/navigation/CatalogNavigationView.tsx +++ b/src/components/catalog/views/navigation/CatalogNavigationView.tsx @@ -20,7 +20,7 @@ export const CatalogNavigationView: FC = props => <> - + { searchResult && (searchResult.filteredNodes.length > 0) && searchResult.filteredNodes.map((n, index) => { return ; diff --git a/src/components/catalog/views/page/widgets/CatalogBundleGridWidgetView.tsx b/src/components/catalog/views/page/widgets/CatalogBundleGridWidgetView.tsx index d98ff1dd..84039c93 100644 --- a/src/components/catalog/views/page/widgets/CatalogBundleGridWidgetView.tsx +++ b/src/components/catalog/views/page/widgets/CatalogBundleGridWidgetView.tsx @@ -1,4 +1,4 @@ -import { FC } from 'react'; +import { FC, useEffect, useRef } from 'react'; import { AutoGrid, AutoGridProps, LayoutGridItem } from '../../../../../common'; import { useCatalog } from '../../../../../hooks'; @@ -11,11 +11,17 @@ export const CatalogBundleGridWidgetView: FC = { const { columnCount = 5, children = null, ...rest } = props; const { currentOffer = null } = useCatalog(); + const elementRef = useRef(); + + useEffect(() => + { + if(elementRef && elementRef.current) elementRef.current.scrollTop = 0; + }, [ currentOffer ]); if(!currentOffer) return null; return ( - + { currentOffer.products && (currentOffer.products.length > 0) && currentOffer.products.map((product, index) => ) } { children } diff --git a/src/components/catalog/views/page/widgets/CatalogItemGridWidgetView.tsx b/src/components/catalog/views/page/widgets/CatalogItemGridWidgetView.tsx index 933dede6..e4660545 100644 --- a/src/components/catalog/views/page/widgets/CatalogItemGridWidgetView.tsx +++ b/src/components/catalog/views/page/widgets/CatalogItemGridWidgetView.tsx @@ -1,4 +1,4 @@ -import { FC } from 'react'; +import { FC, useEffect, useRef } from 'react'; import { IPurchasableOffer, ProductTypeEnum } from '../../../../../api'; import { AutoGrid, AutoGridProps } from '../../../../../common'; import { useCatalog } from '../../../../../hooks'; @@ -13,6 +13,12 @@ export const CatalogItemGridWidgetView: FC = pro { const { columnCount = 5, children = null, ...rest } = props; const { currentOffer = null, setCurrentOffer = null, currentPage = null, setPurchaseOptions = null } = useCatalog(); + const elementRef = useRef(); + + useEffect(() => + { + if(elementRef && elementRef.current) elementRef.current.scrollTop = 0; + }, [ currentPage ]); if(!currentPage) return null; @@ -38,7 +44,7 @@ export const CatalogItemGridWidgetView: FC = pro } return ( - + { currentPage.offers && (currentPage.offers.length > 0) && currentPage.offers.map((offer, index) => ) } { children } diff --git a/src/components/catalog/views/page/widgets/CatalogSpacesWidgetView.tsx b/src/components/catalog/views/page/widgets/CatalogSpacesWidgetView.tsx index fdc3f5f4..3ab901e6 100644 --- a/src/components/catalog/views/page/widgets/CatalogSpacesWidgetView.tsx +++ b/src/components/catalog/views/page/widgets/CatalogSpacesWidgetView.tsx @@ -1,4 +1,4 @@ -import { FC, useEffect, useState } from 'react'; +import { FC, useEffect, useRef, useState } from 'react'; import { IPurchasableOffer, LocalizeText, Offer, ProductTypeEnum } from '../../../../../api'; import { AutoGrid, AutoGridProps, Button, ButtonGroup } from '../../../../../common'; import { useCatalog } from '../../../../../hooks'; @@ -18,6 +18,7 @@ export const CatalogSpacesWidgetView: FC = props = const [ selectedGroupIndex, setSelectedGroupIndex ] = useState(-1); const [ selectedOfferForGroup, setSelectedOfferForGroup ] = useState(null); const { currentPage = null, currentOffer = null, setCurrentOffer = null, setPurchaseOptions = null } = useCatalog(); + const elementRef = useRef(); const setSelectedOffer = (offer: IPurchasableOffer) => { @@ -91,6 +92,11 @@ export const CatalogSpacesWidgetView: FC = props = }); }, [ currentOffer, selectedGroupIndex, selectedOfferForGroup, setPurchaseOptions ]); + useEffect(() => + { + if(elementRef && elementRef.current) elementRef.current.scrollTop = 0; + }, [ selectedGroupIndex ]); + if(!groupedOffers || (selectedGroupIndex === -1)) return null; const offers = groupedOffers[selectedGroupIndex]; @@ -100,7 +106,7 @@ export const CatalogSpacesWidgetView: FC = props = { SPACES_GROUP_NAMES.map((name, index) => ) } - + { offers && (offers.length > 0) && offers.map((offer, index) => setSelectedOffer(offer) } />) } { children } From 46ff82940e4ad8d93e49dc143b50a2585e3d2246 Mon Sep 17 00:00:00 2001 From: Bill Date: Thu, 18 Aug 2022 00:01:13 -0400 Subject: [PATCH 50/58] Catalog updates --- src/components/catalog/CatalogView.scss | 9 +-- .../catalog-header/CatalogHeaderView.tsx | 33 +++++------ .../page/layout/CatalogLayoutDefaultView.tsx | 56 ++++++++++--------- 3 files changed, 43 insertions(+), 55 deletions(-) diff --git a/src/components/catalog/CatalogView.scss b/src/components/catalog/CatalogView.scss index dde64cfc..9e5fe9d7 100644 --- a/src/components/catalog/CatalogView.scss +++ b/src/components/catalog/CatalogView.scss @@ -89,8 +89,7 @@ .icon-hc-banner { width: 68px; height: 40px; - background: url("../../assets/images/catalog/hc_big.png") center - no-repeat; + background: url("../../assets/images/catalog/hc_big.png") center no-repeat; } } } @@ -122,10 +121,4 @@ .nitro-catalog-header { width: 290px; height: 60px; - align-self: center; - - display: flex; - justify-content: center; - overflow: hidden; - flex-shrink: 0; } diff --git a/src/components/catalog/views/catalog-header/CatalogHeaderView.tsx b/src/components/catalog/views/catalog-header/CatalogHeaderView.tsx index e6f02bc2..b51f01b4 100644 --- a/src/components/catalog/views/catalog-header/CatalogHeaderView.tsx +++ b/src/components/catalog/views/catalog-header/CatalogHeaderView.tsx @@ -1,33 +1,26 @@ -import { FC, useEffect, useMemo, useRef } from 'react'; +import { FC, useEffect, useState } from 'react'; import { GetConfiguration } from '../../../../api'; -import { Base } from '../../../../common'; +import { Flex } from '../../../../common'; export interface CatalogHeaderViewProps { - image?: string; + imageUrl?: string; } export const CatalogHeaderView: FC = props => { - let { image = null } = props; + const { imageUrl = null } = props; + const [ displayImageUrl, setDisplayImageUrl ] = useState(''); - const imageEl = useRef(); - - const fallback = useMemo(()=> + useEffect(() => { - return ((GetConfiguration('catalog.asset.image.url')).replace('%name%', 'catalog_header_roombuilder')); - },[]) + setDisplayImageUrl(imageUrl ?? GetConfiguration('catalog.asset.image.url').replace('%name%', 'catalog_header_roombuilder')); + }, [ imageUrl ]); - useEffect(()=> - { - if(image == null && imageEl !== null) imageEl.current.src = fallback; - },[ image, imageEl,fallback ]) - - return - + return + { - currentTarget.src = fallback; - } - } /> - ; + currentTarget.src = GetConfiguration('catalog.asset.image.url').replace('%name%', 'catalog_header_roombuilder'); + } } /> + ; } diff --git a/src/components/catalog/views/page/layout/CatalogLayoutDefaultView.tsx b/src/components/catalog/views/page/layout/CatalogLayoutDefaultView.tsx index adde3fb8..79979a53 100644 --- a/src/components/catalog/views/page/layout/CatalogLayoutDefaultView.tsx +++ b/src/components/catalog/views/page/layout/CatalogLayoutDefaultView.tsx @@ -1,6 +1,6 @@ import { FC } from 'react'; import { GetConfiguration, ProductTypeEnum } from '../../../../../api'; -import { Column, Flex, Grid, Text } from '../../../../../common'; +import { Column, Flex, Grid, LayoutImage, Text } from '../../../../../common'; import { useCatalog } from '../../../../../hooks'; import { CatalogHeaderView } from '../../catalog-header/CatalogHeaderView'; import { CatalogAddOnBadgeWidgetView } from '../widgets/CatalogAddOnBadgeWidgetView'; @@ -15,43 +15,45 @@ import { CatalogLayoutProps } from './CatalogLayout.types'; export const CatalogLayoutDefaultView: FC = props => { const { page = null } = props; - const { currentOffer = null,currentPage } = useCatalog(); + const { currentOffer = null, currentPage = null } = useCatalog(); return ( <> - { GetConfiguration('catalog.headers') && } + { GetConfiguration('catalog.headers') && + } { !currentOffer && - <> - { !!page.localization.getImage(1) && } - - } + <> + { !!page.localization.getImage(1) && + } + + } { currentOffer && - <> - - { (currentOffer.product.productType !== ProductTypeEnum.BADGE) && - <> - - - - } - { (currentOffer.product.productType === ProductTypeEnum.BADGE) && } - - - { currentOffer.localizationName } - - - - - + <> + + { (currentOffer.product.productType !== ProductTypeEnum.BADGE) && + <> + + + + } + { (currentOffer.product.productType === ProductTypeEnum.BADGE) && } - - - } + + { currentOffer.localizationName } + + + + + + + + + } From d30c06738130e9d601d5092181cb014255e3609a Mon Sep 17 00:00:00 2001 From: Bill Date: Thu, 18 Aug 2022 00:06:52 -0400 Subject: [PATCH 51/58] Fix scrolling in the navigator --- src/components/navigator/NavigatorView.tsx | 5 ++++- .../navigator/views/search/NavigatorSearchResultView.tsx | 3 +-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/components/navigator/NavigatorView.tsx b/src/components/navigator/NavigatorView.tsx index 9b3ae5eb..dcc2f9eb 100644 --- a/src/components/navigator/NavigatorView.tsx +++ b/src/components/navigator/NavigatorView.tsx @@ -24,6 +24,7 @@ export const NavigatorView: FC<{}> = props => const [ needsSearch, setNeedsSearch ] = useState(false); const { searchResult = null, topLevelContext = null, topLevelContexts = null, navigatorData = null } = useNavigator(); const pendingSearch = useRef<{ value: string, code: string }>(null); + const elementRef = useRef(); useRoomSessionManagerEvent(RoomSessionEvent.CREATED, event => { @@ -158,6 +159,8 @@ export const NavigatorView: FC<{}> = props => if(!searchResult) return; setIsLoading(false); + + if(elementRef && elementRef.current) elementRef.current.scrollTop = 0; }, [ searchResult ]); useEffect(() => @@ -214,7 +217,7 @@ export const NavigatorView: FC<{}> = props => { !isCreatorOpen && <> - + { (searchResult && searchResult.results.map((result, index) => )) } } diff --git a/src/components/navigator/views/search/NavigatorSearchResultView.tsx b/src/components/navigator/views/search/NavigatorSearchResultView.tsx index 143c3435..a85daaca 100644 --- a/src/components/navigator/views/search/NavigatorSearchResultView.tsx +++ b/src/components/navigator/views/search/NavigatorSearchResultView.tsx @@ -13,7 +13,6 @@ export interface NavigatorSearchResultViewProps extends AutoGridProps export const NavigatorSearchResultView: FC = props => { const { searchResult = null, ...rest } = props; - const [ isExtended, setIsExtended ] = useState(true); const [ displayMode, setDisplayMode ] = useState(0); @@ -44,7 +43,7 @@ export const NavigatorSearchResultView: FC = pro //setIsExtended(searchResult.closed); setDisplayMode(searchResult.mode); - }, [ searchResult,props ]); + }, [ searchResult ]); const gridHasTwoColumns = (displayMode >= NavigatorSearchResultViewDisplayMode.THUMBNAILS); From 147b299b5e14c63f2b38d93fa6736c7a941b31ce Mon Sep 17 00:00:00 2001 From: Bill Date: Thu, 18 Aug 2022 00:14:43 -0400 Subject: [PATCH 52/58] Fix #252 --- src/hooks/catalog/useCatalog.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hooks/catalog/useCatalog.ts b/src/hooks/catalog/useCatalog.ts index 1cb43237..ce72d5be 100644 --- a/src/hooks/catalog/useCatalog.ts +++ b/src/hooks/catalog/useCatalog.ts @@ -835,7 +835,7 @@ const useCatalogState = () => useEffect(() => { - if(!isVisible || !rootNode || !requestedPage.current) return; + if(!isVisible || !rootNode || !offersToNodes || !requestedPage.current) return; switch(requestedPage.current.requestType) { @@ -868,7 +868,7 @@ const useCatalogState = () => requestedPage.current.resetRequest(); return; } - }, [ isVisible, rootNode, currentPage, activateNode, openPageById, openPageByOfferId, openPageByName ]); + }, [ isVisible, rootNode, offersToNodes, currentPage, activateNode, openPageById, openPageByOfferId, openPageByName ]); useEffect(() => { From 16e3457ec85ff91e57a11085c1a45be959a32f3d Mon Sep 17 00:00:00 2001 From: Bill Date: Thu, 18 Aug 2022 01:31:11 -0400 Subject: [PATCH 53/58] Card size/position is now stored in LocalStorage --- src/api/utils/GetLocalStorage.ts | 1 + src/api/utils/SetLocalStorage.ts | 1 + src/api/utils/WindowSaveOptions.ts | 5 +++ src/api/utils/index.ts | 3 ++ src/common/card/NitroCardView.tsx | 36 +++++++++++++++++-- .../draggable-window/DraggableWindow.tsx | 34 +++++++++++------- src/hooks/useLocalStorage.ts | 7 ++-- 7 files changed, 69 insertions(+), 18 deletions(-) create mode 100644 src/api/utils/GetLocalStorage.ts create mode 100644 src/api/utils/SetLocalStorage.ts create mode 100644 src/api/utils/WindowSaveOptions.ts diff --git a/src/api/utils/GetLocalStorage.ts b/src/api/utils/GetLocalStorage.ts new file mode 100644 index 00000000..e8ba878d --- /dev/null +++ b/src/api/utils/GetLocalStorage.ts @@ -0,0 +1 @@ +export const GetLocalStorage = (key: string) => JSON.parse(window.localStorage.getItem(key)) as T ?? null; diff --git a/src/api/utils/SetLocalStorage.ts b/src/api/utils/SetLocalStorage.ts new file mode 100644 index 00000000..02aa8f3d --- /dev/null +++ b/src/api/utils/SetLocalStorage.ts @@ -0,0 +1 @@ +export const SetLocalStorage = (key: string, value: T) => window.localStorage.setItem(key, JSON.stringify(value)); diff --git a/src/api/utils/WindowSaveOptions.ts b/src/api/utils/WindowSaveOptions.ts new file mode 100644 index 00000000..9aa84563 --- /dev/null +++ b/src/api/utils/WindowSaveOptions.ts @@ -0,0 +1,5 @@ +export interface WindowSaveOptions +{ + offset: { x: number, y: number }; + size: { width: number, height: number }; +} diff --git a/src/api/utils/index.ts b/src/api/utils/index.ts index c2f1d4b1..0c51fc49 100644 --- a/src/api/utils/index.ts +++ b/src/api/utils/index.ts @@ -1,6 +1,7 @@ export * from './CloneObject'; export * from './ColorUtils'; export * from './ConvertSeconds'; +export * from './GetLocalStorage'; export * from './LocalizeBadgeDescription'; export * from './LocalizeBageName'; export * from './LocalizeFormattedNumber'; @@ -11,4 +12,6 @@ export * from './PlaySound'; export * from './ProductImageUtility'; export * from './Randomizer'; export * from './RoomChatFormatter'; +export * from './SetLocalStorage'; export * from './SoundNames'; +export * from './WindowSaveOptions'; diff --git a/src/common/card/NitroCardView.tsx b/src/common/card/NitroCardView.tsx index 329d3615..236f615f 100644 --- a/src/common/card/NitroCardView.tsx +++ b/src/common/card/NitroCardView.tsx @@ -1,5 +1,6 @@ -import { FC, useMemo } from 'react'; +import { FC, useEffect, useMemo, useRef } from 'react'; import { Column, ColumnProps } from '..'; +import { GetLocalStorage, SetLocalStorage, WindowSaveOptions } from '../../api'; import { DraggableWindow, DraggableWindowPosition, DraggableWindowProps } from '../draggable-window'; import { NitroCardContextProvider } from './NitroCardContext'; @@ -11,6 +12,7 @@ export interface NitroCardViewProps extends DraggableWindowProps, ColumnProps export const NitroCardView: FC = props => { const { theme = 'primary', uniqueKey = null, handleSelector = '.drag-handler', windowPosition = DraggableWindowPosition.CENTER, disableDrag = false, overflow = 'hidden', position = 'relative', gap = 0, classNames = [], ...rest } = props; + const elementRef = useRef(); const getClassNames = useMemo(() => { @@ -23,10 +25,40 @@ export const NitroCardView: FC = props => return newClassNames; }, [ theme, classNames ]); + useEffect(() => + { + if(!uniqueKey || !elementRef || !elementRef.current) return; + + const localStorage = GetLocalStorage(`nitro.windows.${ uniqueKey }`); + const element = elementRef.current; + + if(localStorage && localStorage.size) + { + element.style.width = `${ localStorage.size.width }px`; + element.style.height = `${ localStorage.size.height }px`; + } + + const observer = new ResizeObserver(event => + { + const newStorage = { ...GetLocalStorage>(`nitro.windows.${ uniqueKey }`) } as WindowSaveOptions; + + newStorage.size = { width: element.offsetWidth, height: element.offsetHeight }; + + SetLocalStorage(`nitro.windows.${ uniqueKey }`, newStorage); + }); + + observer.observe(element); + + return () => + { + observer.disconnect(); + } + }, [ uniqueKey ]); + return ( - + ); diff --git a/src/common/draggable-window/DraggableWindow.tsx b/src/common/draggable-window/DraggableWindow.tsx index 05813e42..286d51d1 100644 --- a/src/common/draggable-window/DraggableWindow.tsx +++ b/src/common/draggable-window/DraggableWindow.tsx @@ -2,10 +2,10 @@ import { MouseEventType, TouchEventType } from '@nitrots/nitro-renderer'; import { CSSProperties, FC, Key, MouseEvent as ReactMouseEvent, ReactNode, TouchEvent as ReactTouchEvent, useCallback, useEffect, useRef, useState } from 'react'; import { createPortal } from 'react-dom'; import { Base } from '..'; +import { GetLocalStorage, SetLocalStorage, WindowSaveOptions } from '../../api'; import { DraggableWindowPosition } from './DraggableWindowPosition'; const CURRENT_WINDOWS: HTMLElement[] = []; -const POS_MEMORY: Map = new Map(); const BOUNDS_THRESHOLD_TOP: number = 0; const BOUNDS_THRESHOLD_LEFT: number = 0; @@ -138,7 +138,14 @@ export const DraggableWindow: FC = props => setOffset({ x: offsetX, y: offsetY }); setIsDragging(false); - if(uniqueKey !== null) POS_MEMORY.set(uniqueKey, { x: offsetX, y: offsetY }); + if(uniqueKey !== null) + { + const newStorage = { ...GetLocalStorage(`nitro.windows.${ uniqueKey }`) } as WindowSaveOptions; + + newStorage.offset = { x: offsetX, y: offsetY }; + + SetLocalStorage(`nitro.windows.${ uniqueKey }`, newStorage); + } }, [ dragHandler, delta, offset, uniqueKey ]); const onDragMouseUp = useCallback((event: MouseEvent) => @@ -187,17 +194,6 @@ export const DraggableWindow: FC = props => break; } - if(uniqueKey !== null) - { - const memory = POS_MEMORY.get(uniqueKey); - - if(memory) - { - offsetX = memory.x; - offsetY = memory.y; - } - } - setDelta({ x: 0, y: 0 }); setOffset({ x: offsetX, y: offsetY }); @@ -253,6 +249,18 @@ export const DraggableWindow: FC = props => } }, [ isDragging, onDragMouseUp, onDragMouseMove, onDragTouchUp, onDragTouchMove ]); + useEffect(() => + { + if(!uniqueKey) return; + + const localStorage = GetLocalStorage(`nitro.windows.${ uniqueKey }`); + + if(!localStorage || !localStorage.offset) return; + + setDelta({ x: 0, y: 0 }); + if(localStorage.offset) setOffset(localStorage.offset); + }, [ uniqueKey ]); + return ( createPortal( diff --git a/src/hooks/useLocalStorage.ts b/src/hooks/useLocalStorage.ts index f0cc26cb..1e55fb93 100644 --- a/src/hooks/useLocalStorage.ts +++ b/src/hooks/useLocalStorage.ts @@ -1,5 +1,6 @@ import { NitroLogger } from '@nitrots/nitro-renderer'; import { Dispatch, SetStateAction, useState } from 'react'; +import { GetLocalStorage, SetLocalStorage } from '../api'; const useLocalStorageState = (key: string, initialValue: T): [ T, Dispatch>] => { @@ -9,9 +10,9 @@ const useLocalStorageState = (key: string, initialValue: T): [ T, Dispatch(key); - return item ? JSON.parse(item) : initialValue; + return item ?? initialValue; } catch(error) @@ -28,7 +29,7 @@ const useLocalStorageState = (key: string, initialValue: T): [ T, Dispatch Date: Thu, 18 Aug 2022 01:45:04 -0400 Subject: [PATCH 54/58] Reset the sizes if the screen size changes --- src/hooks/session/useSessionInfo.ts | 34 +++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/src/hooks/session/useSessionInfo.ts b/src/hooks/session/useSessionInfo.ts index 911e4d0c..6f480fea 100644 --- a/src/hooks/session/useSessionInfo.ts +++ b/src/hooks/session/useSessionInfo.ts @@ -1,8 +1,9 @@ import { FigureUpdateEvent, RoomUnitChatStyleComposer, UserInfoDataParser, UserInfoEvent, UserSettingsEvent } from '@nitrots/nitro-renderer'; -import { useState } from 'react'; +import { useEffect, useState } from 'react'; import { useBetween } from 'use-between'; -import { GetSessionDataManager, SendMessageComposer } from '../../api'; +import { GetLocalStorage, GetSessionDataManager, SendMessageComposer } from '../../api'; import { useMessageEvent } from '../events'; +import { useLocalStorage } from '../useLocalStorage'; const useSessionInfoState = () => { @@ -11,6 +12,7 @@ const useSessionInfoState = () => const [ chatStyleId, setChatStyleId ] = useState(0); const [ userRespectRemaining, setUserRespectRemaining ] = useState(0); const [ petRespectRemaining, setPetRespectRemaining ] = useState(0); + const [ screenSize, setScreenSize ] = useLocalStorage('nitro.screensize', { width: window.innerWidth, height: window.innerHeight }); const updateChatStyleId = (styleId: number) => { @@ -57,6 +59,34 @@ const useSessionInfoState = () => setChatStyleId(parser.chatType); }); + useEffect(() => + { + const currentScreenSize = <{ width: number, height: number }>GetLocalStorage('nitro.screensize'); + + if(currentScreenSize && ((currentScreenSize.width !== window.innerWidth) || (currentScreenSize.height !== window.innerHeight))) + { + let i = window.localStorage.length; + + while(i > 0) + { + const key = window.localStorage.key(i); + + if(key && key.startsWith('nitro.window')) window.localStorage.removeItem(key); + + i--; + } + } + + const onResize = (event: UIEvent) => setScreenSize({ width: window.innerWidth, height: window.innerHeight }); + + window.addEventListener('resize', onResize); + + return () => + { + window.removeEventListener('resize', onResize); + } + }, [ setScreenSize ]); + return { userInfo, userFigure, chatStyleId, userRespectRemaining, petRespectRemaining, respectUser, respectPet, updateChatStyleId }; } From 43f3f1895e9f6d185705b73b5b1c7de75e1147ae Mon Sep 17 00:00:00 2001 From: Bill Date: Thu, 18 Aug 2022 01:48:27 -0400 Subject: [PATCH 55/58] Center the catalog header --- .../catalog/views/catalog-header/CatalogHeaderView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/catalog/views/catalog-header/CatalogHeaderView.tsx b/src/components/catalog/views/catalog-header/CatalogHeaderView.tsx index b51f01b4..eb8d92ce 100644 --- a/src/components/catalog/views/catalog-header/CatalogHeaderView.tsx +++ b/src/components/catalog/views/catalog-header/CatalogHeaderView.tsx @@ -17,7 +17,7 @@ export const CatalogHeaderView: FC = props => setDisplayImageUrl(imageUrl ?? GetConfiguration('catalog.asset.image.url').replace('%name%', 'catalog_header_roombuilder')); }, [ imageUrl ]); - return + return { currentTarget.src = GetConfiguration('catalog.asset.image.url').replace('%name%', 'catalog_header_roombuilder'); From 1fafc9342a2c38b9aaf1e394ad649e00282f8a8a Mon Sep 17 00:00:00 2001 From: Bill Date: Thu, 18 Aug 2022 12:17:01 -0400 Subject: [PATCH 56/58] Catalog navigation scrolling changes --- .../views/navigation/CatalogNavigationItemView.tsx | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/components/catalog/views/navigation/CatalogNavigationItemView.tsx b/src/components/catalog/views/navigation/CatalogNavigationItemView.tsx index b855caa6..9179edba 100644 --- a/src/components/catalog/views/navigation/CatalogNavigationItemView.tsx +++ b/src/components/catalog/views/navigation/CatalogNavigationItemView.tsx @@ -1,5 +1,5 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { FC, useRef } from 'react'; +import { FC } from 'react'; import { ICatalogNode } from '../../../../api'; import { Base, LayoutGridItem, Text } from '../../../../common'; import { useCatalog } from '../../../../hooks'; @@ -16,18 +16,10 @@ export const CatalogNavigationItemView: FC = pro { const { node = null, child = false } = props; const { activateNode = null } = useCatalog(); - const elementRef = useRef(); - - const selectNode = () => - { - if(node.isBranch && !node.isActive) elementRef?.current?.scrollIntoView(); - - activateNode(node); - } return ( - - + + activateNode(node) } className={ child ? 'inset' : '' }> { node.localization } { node.isBranch && From 166ca6ef018ffea94832267815bc75eb56baa0f2 Mon Sep 17 00:00:00 2001 From: Bill Date: Thu, 18 Aug 2022 12:30:03 -0400 Subject: [PATCH 57/58] Fix input in marketplace post offer --- .../marketplace/MarketplacePostOfferView.tsx | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/components/catalog/views/page/layout/marketplace/MarketplacePostOfferView.tsx b/src/components/catalog/views/page/layout/marketplace/MarketplacePostOfferView.tsx index f9f614d5..9c649fe0 100644 --- a/src/components/catalog/views/page/layout/marketplace/MarketplacePostOfferView.tsx +++ b/src/components/catalog/views/page/layout/marketplace/MarketplacePostOfferView.tsx @@ -9,10 +9,22 @@ export const MarketplacePostOfferView : FC<{}> = props => { const [ item, setItem ] = useState(null); const [ askingPrice, setAskingPrice ] = useState(0); + const [ tempAskingPrice, setTempAskingPrice ] = useState('0'); const { catalogOptions = null, setCatalogOptions = null } = useCatalog(); const { marketplaceConfiguration = null } = catalogOptions; const { showConfirm = null } = useNotification(); + const updateAskingPrice = (price: string) => + { + setTempAskingPrice(price); + + const newValue = parseInt(price); + + if(isNaN(newValue) || (newValue === askingPrice)) return; + + setAskingPrice(parseInt(price)); + } + useMessageEvent(MarketplaceConfigurationEvent, event => { const parser = event.getParser(); @@ -64,7 +76,7 @@ export const MarketplacePostOfferView : FC<{}> = props => setItem(null) }, null, null, LocalizeText('inventory.marketplace.confirm_offer.title')); } - + return ( setItem(null) } /> @@ -83,7 +95,7 @@ export const MarketplacePostOfferView : FC<{}> = props => { LocalizeText('inventory.marketplace.make_offer.expiration_info', [ 'time' ], [ marketplaceConfiguration.offerTime.toString() ]) }
- setAskingPrice(parseInt(event.target.value)) } placeholder={ LocalizeText('inventory.marketplace.make_offer.price_request') } /> + updateAskingPrice(event.target.value) } placeholder={ LocalizeText('inventory.marketplace.make_offer.price_request') } /> { ((askingPrice < marketplaceConfiguration.minimumPrice) || isNaN(askingPrice)) && { LocalizeText('inventory.marketplace.make_offer.min_price', [ 'minprice' ], [ marketplaceConfiguration.minimumPrice.toString() ]) } From 45037875fba77960819a6c48738d6479b99ef6dc Mon Sep 17 00:00:00 2001 From: Bill Date: Thu, 18 Aug 2022 12:30:51 -0400 Subject: [PATCH 58/58] Bump version 2.1.1 --- package.json | 2 +- src/api/GetUIVersion.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 9b5a435b..cb577f5f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nitro-react", - "version": "2.1.0", + "version": "2.1.1", "homepage": ".", "private": true, "scripts": { diff --git a/src/api/GetUIVersion.ts b/src/api/GetUIVersion.ts index 881eea94..cf8d5a5d 100644 --- a/src/api/GetUIVersion.ts +++ b/src/api/GetUIVersion.ts @@ -1 +1 @@ -export const GetUIVersion = () => '2.1.0'; +export const GetUIVersion = () => '2.1.1';