mirror of
https://github.com/billsonnn/nitro-react.git
synced 2024-11-30 00:50:50 +01:00
Merge branch '@fix/fixes' into 'fix-monsterplant-info-like-habbo'
# Conflicts: # src/components/room/widgets/avatar-info/infostand/InfoStandWidgetPetView.tsx
This commit is contained in:
commit
79b29944f9
@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "nitro-react",
|
"name": "nitro-react",
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
|
"homepage": ".",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "cross-env SKIP_PREFLIGHT_CHECK=true BROWSER=none IMAGE_INLINE_SIZE_LIMIT=100000 craco --openssl-legacy-provider start",
|
"start": "cross-env SKIP_PREFLIGHT_CHECK=true BROWSER=none IMAGE_INLINE_SIZE_LIMIT=100000 craco --openssl-legacy-provider start",
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
<meta name="theme-color" content="#000000" />
|
<meta name="theme-color" content="#000000" />
|
||||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
||||||
|
<base href="./">
|
||||||
<title>Nitro</title>
|
<title>Nitro</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
@ -16,6 +16,11 @@
|
|||||||
"badge.descriptions.enabled": true,
|
"badge.descriptions.enabled": true,
|
||||||
"motto.max.length": 38,
|
"motto.max.length": 38,
|
||||||
"bot.name.max.length": 15,
|
"bot.name.max.length": 15,
|
||||||
|
"wired.action.bot.talk.to.avatar.max.length": 64,
|
||||||
|
"wired.action.bot.talk.max.length": 64,
|
||||||
|
"wired.action.chat.max.length": 100,
|
||||||
|
"wired.action.kick.from.room.max.length": 100,
|
||||||
|
"wired.action.mute.user.max.length": 100,
|
||||||
"navigator.room.models": [
|
"navigator.room.models": [
|
||||||
{ "clubLevel": 0, "tileSize": 104, "name": "a" },
|
{ "clubLevel": 0, "tileSize": 104, "name": "a" },
|
||||||
{ "clubLevel": 0, "tileSize": 94, "name": "b" },
|
{ "clubLevel": 0, "tileSize": 94, "name": "b" },
|
||||||
|
BIN
src/assets/images/room-widgets/stickie-widget/stickie-dreams.png
Normal file
BIN
src/assets/images/room-widgets/stickie-widget/stickie-dreams.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
BIN
src/assets/images/room-widgets/stickie-widget/stickie-heart.png
Normal file
BIN
src/assets/images/room-widgets/stickie-widget/stickie-heart.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 945 B |
Binary file not shown.
After Width: | Height: | Size: 28 KiB |
Binary file not shown.
After Width: | Height: | Size: 4.9 KiB |
@ -53,7 +53,7 @@
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
width: 110px;
|
width: 110px;
|
||||||
height: 110px;
|
height: 110px;
|
||||||
margin-top: 38px;
|
margin-top: 30px;
|
||||||
margin-left: 3px;
|
margin-left: 3px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -110,8 +110,7 @@
|
|||||||
.gift-incognito {
|
.gift-incognito {
|
||||||
width: 37px;
|
width: 37px;
|
||||||
height: 48px;
|
height: 48px;
|
||||||
background: url("../assets/images/gift/incognito.png") center
|
background: url("../assets/images/gift/incognito.png") center no-repeat;
|
||||||
no-repeat;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.gift-avatar {
|
.gift-avatar {
|
||||||
@ -168,23 +167,27 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@-webkit-keyframes sk-bouncedelay {
|
@-webkit-keyframes sk-bouncedelay {
|
||||||
|
|
||||||
0%,
|
0%,
|
||||||
80%,
|
80%,
|
||||||
100% {
|
100% {
|
||||||
-webkit-transform: scale(0);
|
-webkit-transform: scale(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
40% {
|
40% {
|
||||||
-webkit-transform: scale(1);
|
-webkit-transform: scale(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes sk-bouncedelay {
|
@keyframes sk-bouncedelay {
|
||||||
|
|
||||||
0%,
|
0%,
|
||||||
80%,
|
80%,
|
||||||
100% {
|
100% {
|
||||||
-webkit-transform: scale(0);
|
-webkit-transform: scale(0);
|
||||||
transform: scale(0);
|
transform: scale(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
40% {
|
40% {
|
||||||
-webkit-transform: scale(1);
|
-webkit-transform: scale(1);
|
||||||
transform: scale(1);
|
transform: scale(1);
|
||||||
@ -195,8 +198,7 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
width: 110px;
|
width: 110px;
|
||||||
height: 110px;
|
height: 110px;
|
||||||
background: url("../assets/images/navigator/thumbnail_placeholder.png")
|
background: url("../assets/images/navigator/thumbnail_placeholder.png") no-repeat center;
|
||||||
no-repeat center;
|
|
||||||
background-color: rgba($black, 0.125);
|
background-color: rgba($black, 0.125);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -388,15 +390,13 @@
|
|||||||
content: "";
|
content: "";
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background: url("../assets/images/unique/grid-bg-glass.png") center
|
background: url("../assets/images/unique/grid-bg-glass.png") center no-repeat;
|
||||||
no-repeat;
|
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
z-index: 4;
|
z-index: 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.sold-out:after {
|
&.sold-out:after {
|
||||||
background: url("../assets/images/unique/grid-bg-sold-out.png") center
|
background: url("../assets/images/unique/grid-bg-sold-out.png") center no-repeat,
|
||||||
no-repeat,
|
|
||||||
url("../assets/images/unique/grid-bg-glass.png") center no-repeat;
|
url("../assets/images/unique/grid-bg-glass.png") center no-repeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -408,8 +408,7 @@
|
|||||||
bottom: 1px;
|
bottom: 1px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 9px;
|
height: 9px;
|
||||||
background: url("../assets/images/unique/grid-count-bg.png") center
|
background: url("../assets/images/unique/grid-count-bg.png") center no-repeat;
|
||||||
no-repeat;
|
|
||||||
z-index: 3;
|
z-index: 3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -451,8 +450,7 @@
|
|||||||
.unique-complete-plate {
|
.unique-complete-plate {
|
||||||
width: 170px;
|
width: 170px;
|
||||||
height: 29px;
|
height: 29px;
|
||||||
background: url("../assets/images/unique/catalog-info-amount-bg.png")
|
background: url("../assets/images/unique/catalog-info-amount-bg.png") no-repeat center;
|
||||||
no-repeat center;
|
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
padding-top: 3px;
|
padding-top: 3px;
|
||||||
|
|
||||||
@ -548,12 +546,10 @@
|
|||||||
z-index: 1;
|
z-index: 1;
|
||||||
transition: all 1s;
|
transition: all 1s;
|
||||||
border-radius: calc(#{$border-radius} / 2);
|
border-radius: calc(#{$border-radius} / 2);
|
||||||
background: repeating-linear-gradient(
|
background: repeating-linear-gradient($tertiary,
|
||||||
$tertiary,
|
|
||||||
$tertiary 50%,
|
$tertiary 50%,
|
||||||
$quaternary 50%,
|
$quaternary 50%,
|
||||||
$quaternary 100%
|
$quaternary 100%);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.nitro-progress-bar-text {
|
.nitro-progress-bar-text {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { FC, useCallback, useEffect, useState } from 'react';
|
import { FC, useEffect, useState } from 'react';
|
||||||
import { AvatarEditorGridPartItem, GetConfiguration } from '../../../../api';
|
import { AvatarEditorGridPartItem, GetConfiguration } from '../../../../api';
|
||||||
import { LayoutCurrencyIcon, LayoutGridItem, LayoutGridItemProps } from '../../../../common';
|
import { LayoutCurrencyIcon, LayoutGridItem, LayoutGridItemProps } from '../../../../common';
|
||||||
import { AvatarEditorIcon } from '../AvatarEditorIcon';
|
import { AvatarEditorIcon } from '../AvatarEditorIcon';
|
||||||
@ -15,20 +15,14 @@ export const AvatarEditorFigureSetItemView: FC<AvatarEditorFigureSetItemViewProp
|
|||||||
|
|
||||||
const hcDisabled = GetConfiguration<boolean>('hc.disabled', false);
|
const hcDisabled = GetConfiguration<boolean>('hc.disabled', false);
|
||||||
|
|
||||||
const rerender = useCallback(() =>
|
|
||||||
{
|
|
||||||
setUpdateId(prevValue => (prevValue + 1));
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
|
const rerender = () => setUpdateId(prevValue => (prevValue + 1));
|
||||||
|
|
||||||
partItem.notify = rerender;
|
partItem.notify = rerender;
|
||||||
|
|
||||||
return () =>
|
return () => partItem.notify = null;
|
||||||
{
|
}, [ partItem ]);
|
||||||
partItem.notify = null;
|
|
||||||
}
|
|
||||||
}, [ partItem, rerender ]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LayoutGridItem itemImage={ (partItem.isClear ? undefined : partItem.imageUrl) } itemActive={ partItem.isSelected } { ...rest }>
|
<LayoutGridItem itemImage={ (partItem.isClear ? undefined : partItem.imageUrl) } itemActive={ partItem.isSelected } { ...rest }>
|
||||||
|
@ -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 { AvatarEditorGridPartItem, CategoryData, IAvatarEditorCategoryModel } from '../../../../api';
|
||||||
import { AutoGrid } from '../../../../common';
|
import { AutoGrid } from '../../../../common';
|
||||||
import { AvatarEditorFigureSetItemView } from './AvatarEditorFigureSetItemView';
|
import { AvatarEditorFigureSetItemView } from './AvatarEditorFigureSetItemView';
|
||||||
@ -13,6 +13,7 @@ export interface AvatarEditorFigureSetViewProps
|
|||||||
export const AvatarEditorFigureSetView: FC<AvatarEditorFigureSetViewProps> = props =>
|
export const AvatarEditorFigureSetView: FC<AvatarEditorFigureSetViewProps> = props =>
|
||||||
{
|
{
|
||||||
const { model = null, category = null, setMaxPaletteCount = null } = props;
|
const { model = null, category = null, setMaxPaletteCount = null } = props;
|
||||||
|
const elementRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const selectPart = useCallback((item: AvatarEditorGridPartItem) =>
|
const selectPart = useCallback((item: AvatarEditorGridPartItem) =>
|
||||||
{
|
{
|
||||||
@ -27,8 +28,15 @@ export const AvatarEditorFigureSetView: FC<AvatarEditorFigureSetViewProps> = pro
|
|||||||
setMaxPaletteCount(partItem.maxColorIndex || 1);
|
setMaxPaletteCount(partItem.maxColorIndex || 1);
|
||||||
}, [ model, category, setMaxPaletteCount ]);
|
}, [ model, category, setMaxPaletteCount ]);
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
if(!model || !category || !elementRef || !elementRef.current) return;
|
||||||
|
|
||||||
|
elementRef.current.scrollTop = 0;
|
||||||
|
}, [ model, category ]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AutoGrid columnCount={ 3 } columnMinHeight={ 50 }>
|
<AutoGrid innerRef={ elementRef } columnCount={ 3 } columnMinHeight={ 50 }>
|
||||||
{ (category.parts.length > 0) && category.parts.map((item, index) =>
|
{ (category.parts.length > 0) && category.parts.map((item, index) =>
|
||||||
<AvatarEditorFigureSetItemView key={ index } partItem={ item } onClick={ event => selectPart(item) } />) }
|
<AvatarEditorFigureSetItemView key={ index } partItem={ item } onClick={ event => selectPart(item) } />) }
|
||||||
</AutoGrid>
|
</AutoGrid>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { FC, useCallback, useEffect, useState } from 'react';
|
import { FC, useEffect, useState } from 'react';
|
||||||
import { AvatarEditorGridColorItem, GetConfiguration } from '../../../../api';
|
import { AvatarEditorGridColorItem, GetConfiguration } from '../../../../api';
|
||||||
import { LayoutCurrencyIcon, LayoutGridItem, LayoutGridItemProps } from '../../../../common';
|
import { LayoutCurrencyIcon, LayoutGridItem, LayoutGridItemProps } from '../../../../common';
|
||||||
|
|
||||||
@ -14,17 +14,14 @@ export const AvatarEditorPaletteSetItem: FC<AvatarEditorPaletteSetItemProps> = p
|
|||||||
|
|
||||||
const hcDisabled = GetConfiguration<boolean>('hc.disabled', false);
|
const hcDisabled = GetConfiguration<boolean>('hc.disabled', false);
|
||||||
|
|
||||||
const rerender = useCallback(() =>
|
|
||||||
{
|
|
||||||
setUpdateId(prevValue => (prevValue + 1));
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
|
const rerender = () => setUpdateId(prevValue => (prevValue + 1));
|
||||||
|
|
||||||
colorItem.notify = rerender;
|
colorItem.notify = rerender;
|
||||||
|
|
||||||
return () => colorItem.notify = null;
|
return () => colorItem.notify = null;
|
||||||
});
|
}, [ colorItem ]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LayoutGridItem itemHighlight itemColor={ colorItem.color } itemActive={ colorItem.isSelected } className="clear-bg" { ...rest }>
|
<LayoutGridItem itemHighlight itemColor={ colorItem.color } itemActive={ colorItem.isSelected } className="clear-bg" { ...rest }>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { FC, useCallback } from 'react';
|
import { FC, useCallback, useEffect, useRef } from 'react';
|
||||||
import { AvatarEditorGridColorItem, CategoryData, IAvatarEditorCategoryModel } from '../../../../api';
|
import { AvatarEditorGridColorItem, CategoryData, IAvatarEditorCategoryModel } from '../../../../api';
|
||||||
import { AutoGrid } from '../../../../common';
|
import { AutoGrid } from '../../../../common';
|
||||||
import { AvatarEditorPaletteSetItem } from './AvatarEditorPaletteSetItemView';
|
import { AvatarEditorPaletteSetItem } from './AvatarEditorPaletteSetItemView';
|
||||||
@ -14,6 +14,7 @@ export interface AvatarEditorPaletteSetViewProps
|
|||||||
export const AvatarEditorPaletteSetView: FC<AvatarEditorPaletteSetViewProps> = props =>
|
export const AvatarEditorPaletteSetView: FC<AvatarEditorPaletteSetViewProps> = props =>
|
||||||
{
|
{
|
||||||
const { model = null, category = null, paletteSet = [], paletteIndex = -1 } = props;
|
const { model = null, category = null, paletteSet = [], paletteIndex = -1 } = props;
|
||||||
|
const elementRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const selectColor = useCallback((item: AvatarEditorGridColorItem) =>
|
const selectColor = useCallback((item: AvatarEditorGridColorItem) =>
|
||||||
{
|
{
|
||||||
@ -24,8 +25,15 @@ export const AvatarEditorPaletteSetView: FC<AvatarEditorPaletteSetViewProps> = p
|
|||||||
model.selectColor(category.name, index, paletteIndex);
|
model.selectColor(category.name, index, paletteIndex);
|
||||||
}, [ model, category, paletteSet, paletteIndex ]);
|
}, [ model, category, paletteSet, paletteIndex ]);
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
if(!model || !category || !elementRef || !elementRef.current) return;
|
||||||
|
|
||||||
|
elementRef.current.scrollTop = 0;
|
||||||
|
}, [ model, category ]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AutoGrid gap={ 1 } columnCount={ 5 } columnMinWidth={ 30 }>
|
<AutoGrid innerRef={ elementRef } gap={ 1 } columnCount={ 5 } columnMinWidth={ 30 }>
|
||||||
{ (paletteSet.length > 0) && paletteSet.map((item, index) =>
|
{ (paletteSet.length > 0) && paletteSet.map((item, index) =>
|
||||||
<AvatarEditorPaletteSetItem key={ index } colorItem={ item } onClick={ event => selectColor(item) } />) }
|
<AvatarEditorPaletteSetItem key={ index } colorItem={ item } onClick={ event => selectColor(item) } />) }
|
||||||
</AutoGrid>
|
</AutoGrid>
|
||||||
|
@ -103,11 +103,7 @@ export const CatalogPurchaseWidgetView: FC<CatalogPurchaseWidgetViewProps> = pro
|
|||||||
{
|
{
|
||||||
if(!currentOffer) return;
|
if(!currentOffer) return;
|
||||||
|
|
||||||
return () =>
|
|
||||||
{
|
|
||||||
setPurchaseState(CatalogPurchaseState.NONE);
|
setPurchaseState(CatalogPurchaseState.NONE);
|
||||||
setPurchaseOptions({ quantity: 1, extraData: null, extraParamRequired: false, previewStuffData: null });
|
|
||||||
}
|
|
||||||
}, [ currentOffer, setPurchaseOptions ]);
|
}, [ currentOffer, setPurchaseOptions ]);
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { GuideSessionGetRequesterRoomMessageComposer, GuideSessionInviteRequesterMessageComposer, GuideSessionMessageMessageComposer, GuideSessionRequesterRoomMessageEvent, GuideSessionResolvedMessageComposer } from '@nitrots/nitro-renderer';
|
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 { GetSessionDataManager, GuideToolMessageGroup, LocalizeText, SendMessageComposer, TryVisitRoom } from '../../../api';
|
||||||
import { Base, Button, ButtonGroup, Column, Flex, LayoutAvatarImageView, Text } from '../../../common';
|
import { Base, Button, ButtonGroup, Column, Flex, LayoutAvatarImageView, Text } from '../../../common';
|
||||||
import { useMessageEvent } from '../../../hooks';
|
import { useMessageEvent } from '../../../hooks';
|
||||||
@ -16,10 +16,18 @@ interface GuideToolOngoingViewProps
|
|||||||
|
|
||||||
export const GuideToolOngoingView: FC<GuideToolOngoingViewProps> = props =>
|
export const GuideToolOngoingView: FC<GuideToolOngoingViewProps> = props =>
|
||||||
{
|
{
|
||||||
|
const scrollDiv = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const { isGuide = false, userId = 0, userName = null, userFigure = null, isTyping = false, messageGroups = [] } = props;
|
const { isGuide = false, userId = 0, userName = null, userFigure = null, isTyping = false, messageGroups = [] } = props;
|
||||||
|
|
||||||
const [ messageText, setMessageText ] = useState<string>('');
|
const [ messageText, setMessageText ] = useState<string>('');
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
scrollDiv.current?.scrollIntoView({ block: 'end', behavior: 'smooth' });
|
||||||
|
|
||||||
|
}, [ messageGroups ]);
|
||||||
|
|
||||||
const visit = useCallback(() =>
|
const visit = useCallback(() =>
|
||||||
{
|
{
|
||||||
SendMessageComposer(new GuideSessionGetRequesterRoomMessageComposer());
|
SendMessageComposer(new GuideSessionGetRequesterRoomMessageComposer());
|
||||||
@ -101,6 +109,7 @@ export const GuideToolOngoingView: FC<GuideToolOngoingViewProps> = props =>
|
|||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
}) }
|
}) }
|
||||||
|
<div ref={ scrollDiv } />
|
||||||
</Column>
|
</Column>
|
||||||
</Column>
|
</Column>
|
||||||
<Column gap={ 1 }>
|
<Column gap={ 1 }>
|
||||||
|
@ -71,8 +71,6 @@ export const HelpView: FC<{}> = props =>
|
|||||||
setIsVisible(true);
|
setIsVisible(true);
|
||||||
}, [ activeReport ]);
|
}, [ activeReport ]);
|
||||||
|
|
||||||
if(!isVisible && !activeReport) return null;
|
|
||||||
|
|
||||||
const CurrentStepView = () =>
|
const CurrentStepView = () =>
|
||||||
{
|
{
|
||||||
if(activeReport)
|
if(activeReport)
|
||||||
@ -97,6 +95,7 @@ export const HelpView: FC<{}> = props =>
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
{ isVisible &&
|
||||||
<NitroCardView className="nitro-help" theme="primary-slim">
|
<NitroCardView className="nitro-help" theme="primary-slim">
|
||||||
<NitroCardHeaderView headerText={ LocalizeText('help.button.cfh') } onCloseClick={ onClose } />
|
<NitroCardHeaderView headerText={ LocalizeText('help.button.cfh') } onCloseClick={ onClose } />
|
||||||
<NitroCardContentView className="text-black">
|
<NitroCardContentView className="text-black">
|
||||||
@ -109,7 +108,7 @@ export const HelpView: FC<{}> = props =>
|
|||||||
</Column>
|
</Column>
|
||||||
</Grid>
|
</Grid>
|
||||||
</NitroCardContentView>
|
</NitroCardContentView>
|
||||||
</NitroCardView>
|
</NitroCardView> }
|
||||||
<SanctionSatusView />
|
<SanctionSatusView />
|
||||||
<NameChangeView />
|
<NameChangeView />
|
||||||
</>
|
</>
|
||||||
|
@ -21,6 +21,7 @@ export const SelectReportedChatsView: FC<{}> = props =>
|
|||||||
return messengerHistory.filter(chat => (chat.entityId === activeReport.reportedUserId) && (chat.type === ChatEntryType.TYPE_IM));
|
return messengerHistory.filter(chat => (chat.entityId === activeReport.reportedUserId) && (chat.type === ChatEntryType.TYPE_IM));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
}, [ activeReport, chatHistory, messengerHistory ]);
|
}, [ activeReport, chatHistory, messengerHistory ]);
|
||||||
|
|
||||||
const selectChat = (chatEntry: IChatEntry) =>
|
const selectChat = (chatEntry: IChatEntry) =>
|
||||||
@ -62,7 +63,7 @@ export const SelectReportedChatsView: FC<{}> = props =>
|
|||||||
<Text>{ LocalizeText('help.emergency.chat_report.description') }</Text>
|
<Text>{ LocalizeText('help.emergency.chat_report.description') }</Text>
|
||||||
</Column>
|
</Column>
|
||||||
<Column gap={ 1 } overflow="hidden">
|
<Column gap={ 1 } overflow="hidden">
|
||||||
{ !!!userChats.length &&
|
{ !userChats || !userChats.length &&
|
||||||
<Text>{ LocalizeText('help.cfh.error.no_user_data') }</Text> }
|
<Text>{ LocalizeText('help.cfh.error.no_user_data') }</Text> }
|
||||||
{ (userChats.length > 0) &&
|
{ (userChats.length > 0) &&
|
||||||
<AutoGrid gap={ 1 } columnCount={ 1 } columnMinHeight={ 25 } overflow="auto">
|
<AutoGrid gap={ 1 } columnCount={ 1 } columnMinHeight={ 25 } overflow="auto">
|
||||||
|
@ -17,13 +17,11 @@ export const NameChangeView:FC<{}> = props =>
|
|||||||
const [ layout, setLayout ] = useState<string>(INIT);
|
const [ layout, setLayout ] = useState<string>(INIT);
|
||||||
const [ newUsername, setNewUsername ] = useState<string>('');
|
const [ newUsername, setNewUsername ] = useState<string>('');
|
||||||
|
|
||||||
const onHelpNameChangeEvent = useCallback((event: HelpNameChangeEvent) =>
|
useUiEvent<HelpNameChangeEvent>(HelpNameChangeEvent.INIT, event =>
|
||||||
{
|
{
|
||||||
setLayout(INIT);
|
setLayout(INIT);
|
||||||
setIsVisible(true);
|
setIsVisible(true);
|
||||||
}, []);
|
});
|
||||||
|
|
||||||
useUiEvent(HelpNameChangeEvent.INIT, onHelpNameChangeEvent);
|
|
||||||
|
|
||||||
const onAction = useCallback((action: string, value?: string) =>
|
const onAction = useCallback((action: string, value?: string) =>
|
||||||
{
|
{
|
||||||
|
@ -6,12 +6,12 @@ import { useInventoryBadges, useInventoryUnseenTracker } from '../../../../hooks
|
|||||||
export const InventoryBadgeItemView: FC<PropsWithChildren<{ badgeCode: string }>> = props =>
|
export const InventoryBadgeItemView: FC<PropsWithChildren<{ badgeCode: string }>> = props =>
|
||||||
{
|
{
|
||||||
const { badgeCode = null, children = null, ...rest } = 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 { isUnseen = null } = useInventoryUnseenTracker();
|
||||||
const unseen = isUnseen(UnseenItemCategory.BADGE, getBadgeId(badgeCode));
|
const unseen = isUnseen(UnseenItemCategory.BADGE, getBadgeId(badgeCode));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LayoutGridItem itemActive={ (selectedBadgeCode === badgeCode) } itemUnseen={ unseen } onMouseDown={ event => setSelectedBadgeCode(badgeCode) } { ...rest }>
|
<LayoutGridItem itemActive={ (selectedBadgeCode === badgeCode) } itemUnseen={ unseen } onMouseDown={ event => setSelectedBadgeCode(badgeCode) } onDoubleClick={ event => toggleBadge(selectedBadgeCode) } { ...rest }>
|
||||||
<LayoutBadgeImageView badgeCode={ badgeCode } />
|
<LayoutBadgeImageView badgeCode={ badgeCode } />
|
||||||
{ children }
|
{ children }
|
||||||
</LayoutGridItem>
|
</LayoutGridItem>
|
||||||
|
@ -26,13 +26,16 @@ export const InventoryBotItemView: FC<PropsWithChildren<{ botItem: IBotItem }>>
|
|||||||
case MouseEventType.ROLL_OUT:
|
case MouseEventType.ROLL_OUT:
|
||||||
if(!isMouseDown || (selectedBot !== botItem)) return;
|
if(!isMouseDown || (selectedBot !== botItem)) return;
|
||||||
|
|
||||||
|
attemptBotPlacement(botItem);
|
||||||
|
return;
|
||||||
|
case 'dblclick':
|
||||||
attemptBotPlacement(botItem);
|
attemptBotPlacement(botItem);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LayoutGridItem itemActive={ (selectedBot === botItem) } itemUnseen={ unseen } onMouseDown={ onMouseEvent } onMouseUp={ onMouseEvent } onMouseOut={ onMouseEvent } { ...rest }>
|
<LayoutGridItem itemActive={ (selectedBot === botItem) } itemUnseen={ unseen } onMouseDown={ onMouseEvent } onMouseUp={ onMouseEvent } onMouseOut={ onMouseEvent } onDoubleClick={ onMouseEvent } { ...rest }>
|
||||||
<LayoutAvatarImageView figure={ botItem.botData.figure } direction={ 3 } headOnly={ true } />
|
<LayoutAvatarImageView figure={ botItem.botData.figure } direction={ 3 } headOnly={ true } />
|
||||||
{ children }
|
{ children }
|
||||||
</LayoutGridItem>
|
</LayoutGridItem>
|
||||||
|
@ -24,6 +24,9 @@ export const InventoryFurnitureItemView: FC<{ groupItem: GroupItem }> = props =>
|
|||||||
case MouseEventType.ROLL_OUT:
|
case MouseEventType.ROLL_OUT:
|
||||||
if(!isMouseDown || !(groupItem === selectedItem)) return;
|
if(!isMouseDown || !(groupItem === selectedItem)) return;
|
||||||
|
|
||||||
|
attemptItemPlacement(groupItem);
|
||||||
|
return;
|
||||||
|
case 'dblclick':
|
||||||
attemptItemPlacement(groupItem);
|
attemptItemPlacement(groupItem);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -31,5 +34,5 @@ export const InventoryFurnitureItemView: FC<{ groupItem: GroupItem }> = props =>
|
|||||||
|
|
||||||
const count = groupItem.getUnlockedCount();
|
const count = groupItem.getUnlockedCount();
|
||||||
|
|
||||||
return <LayoutGridItem className={ !count ? 'opacity-0-5 ' : '' } itemImage={ groupItem.iconUrl } itemCount={ groupItem.getUnlockedCount() } itemActive={ (groupItem === selectedItem) } itemUniqueNumber={ groupItem.stuffData.uniqueNumber } itemUnseen={ groupItem.hasUnseenItems } onMouseDown={ onMouseEvent } onMouseUp={ onMouseEvent } onMouseOut={ onMouseEvent } { ...rest } />;
|
return <LayoutGridItem className={ !count ? 'opacity-0-5 ' : '' } itemImage={ groupItem.iconUrl } itemCount={ groupItem.getUnlockedCount() } itemActive={ (groupItem === selectedItem) } itemUniqueNumber={ groupItem.stuffData.uniqueNumber } itemUnseen={ groupItem.hasUnseenItems } onMouseDown={ onMouseEvent } onMouseUp={ onMouseEvent } onMouseOut={ onMouseEvent } onDoubleClick={ onMouseEvent } { ...rest } />;
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ export const InventoryTradeView: FC<InventoryTradeViewProps> = props =>
|
|||||||
const [ otherGroupItem, setOtherGroupItem ] = useState<GroupItem>(null);
|
const [ otherGroupItem, setOtherGroupItem ] = useState<GroupItem>(null);
|
||||||
const [ filteredGroupItems, setFilteredGroupItems ] = useState<GroupItem[]>(null);
|
const [ filteredGroupItems, setFilteredGroupItems ] = useState<GroupItem[]>(null);
|
||||||
const [ countdownTick, setCountdownTick ] = useState(3);
|
const [ countdownTick, setCountdownTick ] = useState(3);
|
||||||
|
const [ quantity, setQuantity ] = useState<number>(1);
|
||||||
const { ownUser = null, otherUser = null, groupItems = [], tradeState = TradeState.TRADING_STATE_READY, progressTrade = null, removeItem = null, setTradeState = null } = useInventoryTrade();
|
const { ownUser = null, otherUser = null, groupItems = [], tradeState = TradeState.TRADING_STATE_READY, progressTrade = null, removeItem = null, setTradeState = null } = useInventoryTrade();
|
||||||
const { simpleAlert = null } = useNotification();
|
const { simpleAlert = null } = useNotification();
|
||||||
|
|
||||||
@ -118,6 +119,29 @@ export const InventoryTradeView: FC<InventoryTradeViewProps> = props =>
|
|||||||
return <FontAwesomeIcon icon={ iconName } className={ 'text-' + textColor } />
|
return <FontAwesomeIcon icon={ iconName } className={ 'text-' + textColor } />
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const updateQuantity = (value: number, totalItemCount: number) =>
|
||||||
|
{
|
||||||
|
if(isNaN(Number(value)) || Number(value) < 0 || !value) value = 1;
|
||||||
|
|
||||||
|
value = Math.max(Number(value), 1);
|
||||||
|
value = Math.min(Number(value), totalItemCount);
|
||||||
|
|
||||||
|
if(value === quantity) return;
|
||||||
|
|
||||||
|
setQuantity(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
const changeCount = (totalItemCount: number) =>
|
||||||
|
{
|
||||||
|
updateQuantity(quantity, totalItemCount);
|
||||||
|
attemptItemOffer(quantity);
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
setQuantity(1);
|
||||||
|
}, [ groupItem ]);
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
if(tradeState !== TradeState.TRADING_STATE_COUNTDOWN) return;
|
if(tradeState !== TradeState.TRADING_STATE_COUNTDOWN) return;
|
||||||
@ -159,18 +183,29 @@ export const InventoryTradeView: FC<InventoryTradeViewProps> = props =>
|
|||||||
const count = item.getUnlockedCount();
|
const count = item.getUnlockedCount();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LayoutGridItem key={ index } className={ !count ? 'opacity-0-5 ' : '' } itemImage={ item.iconUrl } itemCount={ count } itemActive={ (groupItem === item) } itemUniqueNumber={ item.stuffData.uniqueNumber } onClick={ event => (count && setGroupItem(item)) }>
|
<LayoutGridItem key={ index } className={ !count ? 'opacity-0-5 ' : '' } itemImage={ item.iconUrl } itemCount={ count } itemActive={ (groupItem === item) } itemUniqueNumber={ item.stuffData.uniqueNumber } onClick={ event => (count && setGroupItem(item)) } onDoubleClick={ event => attemptItemOffer(1) }>
|
||||||
{ ((count > 0) && (groupItem === item)) &&
|
{ ((count > 0) && (groupItem === item)) &&
|
||||||
<Button position="absolute" variant="success" className="trade-button bottom-1 end-1" onClick={ event => attemptItemOffer(1) }>
|
<Button position="absolute" variant="success" className="trade-button bottom-1 end-1" onClick={ event => attemptItemOffer(1) }>
|
||||||
<FontAwesomeIcon icon="chevron-right" />
|
<FontAwesomeIcon icon="chevron-right" />
|
||||||
</Button> }
|
</Button>
|
||||||
|
}
|
||||||
</LayoutGridItem>
|
</LayoutGridItem>
|
||||||
);
|
);
|
||||||
}) }
|
}) }
|
||||||
</AutoGrid>
|
</AutoGrid>
|
||||||
|
<Column gap={ 1 } alignItems="end">
|
||||||
|
<Grid overflow="hidden">
|
||||||
|
<Column size={ 6 } overflow="hidden">
|
||||||
|
<input type="number" className="form-control form-control-sm quantity-input" placeholder={ LocalizeText('catalog.bundlewidget.spinner.select.amount') } disabled={ !groupItem } value={ quantity } onChange={ event => setQuantity(event.target.valueAsNumber) } />
|
||||||
|
</Column>
|
||||||
|
<Column size={ 6 } overflow="hidden">
|
||||||
|
<Button variant="secondary" disabled={ !groupItem } onClick={ event => changeCount(groupItem.getUnlockedCount()) }>{ LocalizeText('inventory.trading.areoffering') }</Button>
|
||||||
|
</Column>
|
||||||
|
</Grid>
|
||||||
<Base fullWidth className="badge bg-muted">
|
<Base fullWidth className="badge bg-muted">
|
||||||
{ groupItem ? groupItem.name : LocalizeText('catalog_selectproduct') }
|
{ groupItem ? groupItem.name : LocalizeText('catalog_selectproduct') }
|
||||||
</Base>
|
</Base>
|
||||||
|
</Column>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Column>
|
</Column>
|
||||||
<Column size={ 8 } overflow="hidden">
|
<Column size={ 8 } overflow="hidden">
|
||||||
@ -188,7 +223,7 @@ export const InventoryTradeView: FC<InventoryTradeViewProps> = props =>
|
|||||||
if(!item) return <LayoutGridItem key={ i } />;
|
if(!item) return <LayoutGridItem key={ i } />;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LayoutGridItem key={ i } itemActive={ (ownGroupItem === item) } itemImage={ item.iconUrl } itemCount={ item.getTotalCount() } itemUniqueNumber={ item.stuffData.uniqueNumber } onClick={ event => setOwnGroupItem(item) }>
|
<LayoutGridItem key={ i } itemActive={ (ownGroupItem === item) } itemImage={ item.iconUrl } itemCount={ item.getTotalCount() } itemUniqueNumber={ item.stuffData.uniqueNumber } onClick={ event => setOwnGroupItem(item) } onDoubleClick={ event => removeItem(item) }>
|
||||||
{ (ownGroupItem === item) &&
|
{ (ownGroupItem === item) &&
|
||||||
<Button position="absolute" variant="danger" className="trade-button bottom-1 start-1" onClick={ event => removeItem(item) }>
|
<Button position="absolute" variant="danger" className="trade-button bottom-1 start-1" onClick={ event => removeItem(item) }>
|
||||||
<FontAwesomeIcon icon="chevron-left" />
|
<FontAwesomeIcon icon="chevron-left" />
|
||||||
|
@ -26,13 +26,16 @@ export const InventoryPetItemView: FC<PropsWithChildren<{ petItem: IPetItem }>>
|
|||||||
case MouseEventType.ROLL_OUT:
|
case MouseEventType.ROLL_OUT:
|
||||||
if(!isMouseDown || !(petItem === selectedPet)) return;
|
if(!isMouseDown || !(petItem === selectedPet)) return;
|
||||||
|
|
||||||
|
attemptPetPlacement(petItem);
|
||||||
|
return;
|
||||||
|
case 'dblclick':
|
||||||
attemptPetPlacement(petItem);
|
attemptPetPlacement(petItem);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LayoutGridItem itemActive={ (petItem === selectedPet) } itemUnseen={ unseen } onMouseDown={ onMouseEvent } onMouseUp={ onMouseEvent } onMouseOut={ onMouseEvent } { ...rest }>
|
<LayoutGridItem itemActive={ (petItem === selectedPet) } itemUnseen={ unseen } onMouseDown={ onMouseEvent } onMouseUp={ onMouseEvent } onMouseOut={ onMouseEvent } onDoubleClick={ onMouseEvent } { ...rest }>
|
||||||
<LayoutPetImageView figure={ petItem.petData.figureData.figuredata } direction={ 3 } headOnly={ true } />
|
<LayoutPetImageView figure={ petItem.petData.figureData.figuredata } direction={ 3 } headOnly={ true } />
|
||||||
{ children }
|
{ children }
|
||||||
</LayoutGridItem>
|
</LayoutGridItem>
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { PetRespectComposer, PetType } from '@nitrots/nitro-renderer';
|
import { PetRespectComposer, PetType } from '@nitrots/nitro-renderer';
|
||||||
import { FC, useEffect, useState } from 'react';
|
import { FC, useEffect, useState } from 'react';
|
||||||
import { AvatarInfoPet, ConvertSeconds, CreateLinkEvent, GetConfiguration, GetSessionDataManager, LocalizeText, SendMessageComposer } from '../../../../../api';
|
import { AvatarInfoPet, CreateLinkEvent, GetConfiguration, LocalizeText, SendMessageComposer, ConvertSeconds } from '../../../../../api';
|
||||||
import { Base, Button, Column, Flex, LayoutCounterTimeView, LayoutPetImageView, LayoutRarityLevelView, Text, UserProfileIconView } from '../../../../../common';
|
import { Base, Button, Column, Flex, LayoutPetImageView, LayoutRarityLevelView, Text, UserProfileIconView, LayoutCounterTimeView } from '../../../../../common';
|
||||||
import { usePets, useRoom } from '../../../../../hooks';
|
import { useRoom, useSessionInfo } from '../../../../../hooks';
|
||||||
|
|
||||||
interface InfoStandWidgetPetViewProps
|
interface InfoStandWidgetPetViewProps
|
||||||
{
|
{
|
||||||
@ -14,21 +14,32 @@ interface InfoStandWidgetPetViewProps
|
|||||||
export const InfoStandWidgetPetView: FC<InfoStandWidgetPetViewProps> = props =>
|
export const InfoStandWidgetPetView: FC<InfoStandWidgetPetViewProps> = props =>
|
||||||
{
|
{
|
||||||
const { avatarInfo = null, onClose = null } = props;
|
const { avatarInfo = null, onClose = null } = props;
|
||||||
const { roomSession = null } = useRoom();
|
|
||||||
const { petRespect, changePetRespect } = usePets();
|
|
||||||
const [ remainingGrowTime, setRemainingGrowTime ] = useState(0);
|
const [ remainingGrowTime, setRemainingGrowTime ] = useState(0);
|
||||||
const [ remainingTimeToLive, setRemainingTimeToLive ] = useState(0);
|
const [ remainingTimeToLive, setRemainingTimeToLive ] = useState(0);
|
||||||
|
const { roomSession = null } = useRoom();
|
||||||
if(!avatarInfo) return null;
|
const { petRespectRemaining = 0, respectPet = null } = useSessionInfo();
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
changePetRespect(avatarInfo.respectsPetLeft);
|
|
||||||
setRemainingGrowTime(avatarInfo.remainingGrowTime);
|
setRemainingGrowTime(avatarInfo.remainingGrowTime);
|
||||||
setRemainingTimeToLive(avatarInfo.remainingTimeToLive);
|
setRemainingTimeToLive(avatarInfo.remainingTimeToLive);
|
||||||
|
|
||||||
}, [ avatarInfo ]);
|
}, [ avatarInfo ]);
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
if((avatarInfo.petType !== PetType.MONSTERPLANT) || avatarInfo.dead) return;
|
||||||
|
|
||||||
|
const interval = setInterval(() =>
|
||||||
|
{
|
||||||
|
setRemainingGrowTime(prevValue => (prevValue - 1));
|
||||||
|
setRemainingTimeToLive(prevValue => (prevValue - 1));
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
return () => clearInterval(interval);
|
||||||
|
}, [ avatarInfo ]);
|
||||||
|
|
||||||
|
if(!avatarInfo) return null;
|
||||||
|
|
||||||
const processButtonAction = (action: string) =>
|
const processButtonAction = (action: string) =>
|
||||||
{
|
{
|
||||||
let hideMenu = true;
|
let hideMenu = true;
|
||||||
@ -38,17 +49,9 @@ export const InfoStandWidgetPetView: FC<InfoStandWidgetPetViewProps> = props =>
|
|||||||
switch (action)
|
switch (action)
|
||||||
{
|
{
|
||||||
case 'respect':
|
case 'respect':
|
||||||
let newRespectsLeftChange = 0;
|
respectPet(avatarInfo.id);
|
||||||
|
|
||||||
changePetRespect(prevValue =>
|
if((petRespectRemaining - 1) >= 1) hideMenu = false;
|
||||||
{
|
|
||||||
newRespectsLeftChange = (prevValue - 1);
|
|
||||||
|
|
||||||
return newRespectsLeftChange;
|
|
||||||
});
|
|
||||||
|
|
||||||
GetSessionDataManager().givePetRespect(avatarInfo.id);
|
|
||||||
if(newRespectsLeftChange > 0) hideMenu = false;
|
|
||||||
break;
|
break;
|
||||||
case 'buyfood':
|
case 'buyfood':
|
||||||
CreateLinkEvent('catalog/open/' + GetConfiguration('catalog.links')['pets.buy_saddle']);
|
CreateLinkEvent('catalog/open/' + GetConfiguration('catalog.links')['pets.buy_saddle']);
|
||||||
@ -70,46 +73,6 @@ export const InfoStandWidgetPetView: FC<InfoStandWidgetPetViewProps> = props =>
|
|||||||
if(hideMenu) onClose();
|
if(hideMenu) onClose();
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() =>
|
|
||||||
{
|
|
||||||
changePetRespect(avatarInfo.respectsPetLeft);
|
|
||||||
setRemainingGrowTime(avatarInfo.remainingGrowTime);
|
|
||||||
setRemainingTimeToLive(avatarInfo.remainingTimeToLive);
|
|
||||||
|
|
||||||
}, [ avatarInfo ]);
|
|
||||||
|
|
||||||
useEffect(() =>
|
|
||||||
{
|
|
||||||
if (avatarInfo.petType === PetType.MONSTERPLANT && !avatarInfo.dead)
|
|
||||||
{
|
|
||||||
const interval = setInterval(() =>
|
|
||||||
{
|
|
||||||
let newRemaingGrowTime = 0;
|
|
||||||
let newRemaingLiveTime = 0;
|
|
||||||
|
|
||||||
setRemainingGrowTime(prevValue =>
|
|
||||||
{
|
|
||||||
newRemaingGrowTime = (prevValue - 1);
|
|
||||||
|
|
||||||
return newRemaingGrowTime;
|
|
||||||
});
|
|
||||||
|
|
||||||
setRemainingTimeToLive(prevValue =>
|
|
||||||
{
|
|
||||||
newRemaingLiveTime = (prevValue - 1);
|
|
||||||
|
|
||||||
return newRemaingLiveTime;
|
|
||||||
});
|
|
||||||
|
|
||||||
}, 1000);
|
|
||||||
|
|
||||||
return () => clearInterval(interval);
|
|
||||||
}
|
|
||||||
|
|
||||||
}, [ avatarInfo ]);
|
|
||||||
|
|
||||||
const InfoStandNormalPet = () =>
|
|
||||||
{
|
|
||||||
return (
|
return (
|
||||||
<Column gap={ 1 } alignItems="end">
|
<Column gap={ 1 } alignItems="end">
|
||||||
<Column className="nitro-infostand rounded">
|
<Column className="nitro-infostand rounded">
|
||||||
@ -122,6 +85,50 @@ export const InfoStandWidgetPetView: FC<InfoStandWidgetPetViewProps> = props =>
|
|||||||
<Text variant="white" small wrap>{ LocalizeText(`pet.breed.${ avatarInfo.petType }.${ avatarInfo.petBreed }`) }</Text>
|
<Text variant="white" small wrap>{ LocalizeText(`pet.breed.${ avatarInfo.petType }.${ avatarInfo.petBreed }`) }</Text>
|
||||||
<hr className="m-0" />
|
<hr className="m-0" />
|
||||||
</Column>
|
</Column>
|
||||||
|
{ (avatarInfo.petType === PetType.MONSTERPLANT) &&
|
||||||
|
<>
|
||||||
|
<Column gap={ 1 }>
|
||||||
|
<Flex gap={ 1 }>
|
||||||
|
<Column fullWidth overflow="hidden" className="body-image-plant pet p-1">
|
||||||
|
<LayoutPetImageView figure={ avatarInfo.petFigure } posture={ avatarInfo.posture } direction={ 4 } />
|
||||||
|
</Column>
|
||||||
|
{ !avatarInfo.dead &&
|
||||||
|
<Column grow gap={ 1 }>
|
||||||
|
<Text variant="white" center small wrap>{ LocalizeText('pet.level', [ 'level', 'maxlevel' ], [ avatarInfo.level.toString(), avatarInfo.maximumLevel.toString() ]) }</Text>
|
||||||
|
</Column> }
|
||||||
|
</Flex>
|
||||||
|
<hr className="m-0" />
|
||||||
|
</Column>
|
||||||
|
<Column gap={ 1 }>
|
||||||
|
<Column alignItems="center" gap={ 1 }>
|
||||||
|
<Text variant="white" small truncate>{ LocalizeText('infostand.pet.text.wellbeing') }</Text>
|
||||||
|
<Base fullWidth overflow="hidden" position="relative" className="bg-light-dark rounded">
|
||||||
|
<Flex fit center position="absolute">
|
||||||
|
<Text variant="white" small>{ 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] }</Text>
|
||||||
|
</Flex>
|
||||||
|
<Base className="bg-success rounded pet-stats" style={ { width: avatarInfo.dead ? '0' : Math.round((avatarInfo.maximumTimeToLive * 100) / (remainingTimeToLive)).toString() } } />
|
||||||
|
</Base>
|
||||||
|
</Column>
|
||||||
|
<br /><br />
|
||||||
|
<br /><br />
|
||||||
|
{ remainingGrowTime != 0 && remainingGrowTime > 0 &&
|
||||||
|
<Column alignItems="center" gap={ 1 }>
|
||||||
|
<Text variant="white" small truncate>{ LocalizeText('infostand.pet.text.growth') }</Text> <br />
|
||||||
|
<LayoutCounterTimeView className="top-2 end-2" day={ ConvertSeconds(remainingGrowTime).split(':')[0] } hour={ ConvertSeconds(remainingGrowTime).split(':')[1] } minutes={ ConvertSeconds(remainingGrowTime).split(':')[2] } seconds={ ConvertSeconds(remainingGrowTime).split(':')[3] } />
|
||||||
|
</Column> }
|
||||||
|
<br /><br />
|
||||||
|
<br /><br />
|
||||||
|
<Column alignItems="center" gap={ 1 }>
|
||||||
|
<Text variant="white" small truncate>{ LocalizeText('Nivel de rareza:') }</Text>
|
||||||
|
<LayoutRarityLevelView className="top-2 end-2" level={ avatarInfo.rarityLevel } />
|
||||||
|
</Column>
|
||||||
|
<br /><br />
|
||||||
|
<Text variant="white" small wrap>{ LocalizeText('pet.age', [ 'age' ], [ avatarInfo.age.toString() ]) }</Text>
|
||||||
|
<hr className="m-0" />
|
||||||
|
</Column>
|
||||||
|
</> }
|
||||||
|
{ (avatarInfo.petType !== PetType.MONSTERPLANT) &&
|
||||||
|
<>
|
||||||
<Column gap={ 1 }>
|
<Column gap={ 1 }>
|
||||||
<Flex gap={ 1 }>
|
<Flex gap={ 1 }>
|
||||||
<Column fullWidth overflow="hidden" className="body-image pet p-1">
|
<Column fullWidth overflow="hidden" className="body-image pet p-1">
|
||||||
@ -161,9 +168,12 @@ export const InfoStandWidgetPetView: FC<InfoStandWidgetPetViewProps> = props =>
|
|||||||
<hr className="m-0" />
|
<hr className="m-0" />
|
||||||
</Column>
|
</Column>
|
||||||
<Column gap={ 1 }>
|
<Column gap={ 1 }>
|
||||||
|
{ (avatarInfo.petType !== PetType.MONSTERPLANT) &&
|
||||||
|
<Text variant="white" small wrap>{ LocalizeText('infostand.text.petrespect', [ 'count' ], [ avatarInfo.respect.toString() ]) }</Text> }
|
||||||
<Text variant="white" small wrap>{ LocalizeText('pet.age', [ 'age' ], [ avatarInfo.age.toString() ]) }</Text>
|
<Text variant="white" small wrap>{ LocalizeText('pet.age', [ 'age' ], [ avatarInfo.age.toString() ]) }</Text>
|
||||||
<hr className="m-0" />
|
<hr className="m-0" />
|
||||||
</Column>
|
</Column>
|
||||||
|
</> }
|
||||||
<Column gap={ 1 }>
|
<Column gap={ 1 }>
|
||||||
<Flex alignItems="center" gap={ 1 }>
|
<Flex alignItems="center" gap={ 1 }>
|
||||||
<UserProfileIconView userId={ avatarInfo.ownerId } />
|
<UserProfileIconView userId={ avatarInfo.ownerId } />
|
||||||
@ -175,124 +185,31 @@ export const InfoStandWidgetPetView: FC<InfoStandWidgetPetViewProps> = props =>
|
|||||||
</Column>
|
</Column>
|
||||||
</Column>
|
</Column>
|
||||||
<Flex gap={ 1 } justifyContent="end">
|
<Flex gap={ 1 } justifyContent="end">
|
||||||
|
{ (avatarInfo.petType !== PetType.MONSTERPLANT) &&
|
||||||
<Button variant="dark" onClick={ event => processButtonAction('buyfood') }>
|
<Button variant="dark" onClick={ event => processButtonAction('buyfood') }>
|
||||||
{ LocalizeText('infostand.button.buyfood') }
|
{ LocalizeText('infostand.button.buyfood') }
|
||||||
</Button>
|
</Button> }
|
||||||
{ avatarInfo.isOwner &&
|
{ avatarInfo.isOwner && (avatarInfo.petType !== PetType.MONSTERPLANT) &&
|
||||||
<Button variant="dark" onClick={ event => processButtonAction('train') }>
|
<Button variant="dark" onClick={ event => processButtonAction('train') }>
|
||||||
{ LocalizeText('infostand.button.train') }
|
{ LocalizeText('infostand.button.train') }
|
||||||
</Button>
|
</Button> }
|
||||||
}
|
{ !avatarInfo.dead && ((avatarInfo.energy / avatarInfo.maximumEnergy) < 0.98) && (avatarInfo.petType === PetType.MONSTERPLANT) &&
|
||||||
{ avatarInfo.isOwner &&
|
|
||||||
<Button variant="dark" onClick={ event => processButtonAction('pick_up') }>
|
|
||||||
{ LocalizeText('inventory.pets.pickup') }
|
|
||||||
</Button>
|
|
||||||
}
|
|
||||||
{ (petRespect > 0) &&
|
|
||||||
<Button variant="dark" onClick={ event => processButtonAction('respect') }>
|
|
||||||
{ LocalizeText('infostand.button.petrespect', [ 'count' ], [ petRespect.toString() ]) }
|
|
||||||
</Button>
|
|
||||||
}
|
|
||||||
</Flex>
|
|
||||||
</Column>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const InfoStandMonsterplantPet = () =>
|
|
||||||
{
|
|
||||||
return (
|
|
||||||
<Column gap={ 1 } alignItems="end">
|
|
||||||
<Column className="nitro-infostand rounded">
|
|
||||||
<Column overflow="visible" className="container-fluid content-area" gap={ 1 }>
|
|
||||||
<Column gap={ 1 }>
|
|
||||||
<Flex alignItems="center" justifyContent="between" gap={ 1 }>
|
|
||||||
<Text variant="white" small wrap>{ avatarInfo.name }</Text>
|
|
||||||
<FontAwesomeIcon icon="times" className="cursor-pointer" onClick={ onClose } />
|
|
||||||
</Flex>
|
|
||||||
<Text variant="white" small wrap>{ LocalizeText(`pet.breed.${ avatarInfo.petType }.${ avatarInfo.petBreed }`) }</Text>
|
|
||||||
<hr className="m-0" />
|
|
||||||
</Column>
|
|
||||||
<Column gap={ 1 }>
|
|
||||||
<Flex gap={ 1 }>
|
|
||||||
<Column fullWidth overflow="hidden" className="body-image-plant pet p-1">
|
|
||||||
<LayoutPetImageView figure={ avatarInfo.petFigure } posture={ avatarInfo.posture } direction={ 4 } />
|
|
||||||
</Column>
|
|
||||||
{ !avatarInfo.dead &&
|
|
||||||
<Column grow gap={ 1 }>
|
|
||||||
<Text variant="white" center small wrap>{ LocalizeText('pet.level', [ 'level', 'maxlevel' ], [ avatarInfo.level.toString(), avatarInfo.maximumLevel.toString() ]) }</Text>
|
|
||||||
</Column>
|
|
||||||
}
|
|
||||||
</Flex>
|
|
||||||
<hr className="m-0" />
|
|
||||||
</Column>
|
|
||||||
<br /><br />
|
|
||||||
<Column gap={ 1 }>
|
|
||||||
<Column alignItems="center" gap={ 1 }>
|
|
||||||
<Text variant="white" small truncate>{ LocalizeText('infostand.pet.text.wellbeing') }</Text>
|
|
||||||
<Base fullWidth overflow="hidden" position="relative" className="bg-light-dark rounded">
|
|
||||||
<Flex fit center position="absolute">
|
|
||||||
<Text variant="white" small>{ 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] }</Text>
|
|
||||||
</Flex>
|
|
||||||
<Base className="bg-success rounded pet-stats" style={ { width: avatarInfo.dead ? '0' : Math.round((avatarInfo.maximumTimeToLive * 100) / (remainingTimeToLive)).toString() } } />
|
|
||||||
</Base>
|
|
||||||
</Column>
|
|
||||||
<br /><br />
|
|
||||||
<br /><br />
|
|
||||||
{ remainingGrowTime != 0 && remainingGrowTime > 0 &&
|
|
||||||
<Column alignItems="center" gap={ 1 }>
|
|
||||||
<Text variant="white" small truncate>{ LocalizeText('infostand.pet.text.growth') }</Text> <br />
|
|
||||||
<LayoutCounterTimeView className="top-2 end-2" day={ ConvertSeconds(remainingGrowTime).split(':')[0] } hour={ ConvertSeconds(remainingGrowTime).split(':')[1] } minutes={ ConvertSeconds(remainingGrowTime).split(':')[2] } seconds={ ConvertSeconds(remainingGrowTime).split(':')[3] } />
|
|
||||||
</Column>
|
|
||||||
}
|
|
||||||
<br /><br />
|
|
||||||
<br /><br />
|
|
||||||
<Column alignItems="center" gap={ 1 }>
|
|
||||||
<Text variant="white" small truncate>{ LocalizeText('Nivel de rareza:') }</Text>
|
|
||||||
<LayoutRarityLevelView className="top-2 end-2" level={ avatarInfo.rarityLevel } />
|
|
||||||
</Column>
|
|
||||||
<br /><br />
|
|
||||||
<Text variant="white" small wrap>{ LocalizeText('pet.age', [ 'age' ], [ avatarInfo.age.toString() ]) }</Text>
|
|
||||||
<hr className="m-0" />
|
|
||||||
</Column>
|
|
||||||
<Column gap={ 1 }>
|
|
||||||
<Flex alignItems="center" gap={ 1 }>
|
|
||||||
<UserProfileIconView userId={ avatarInfo.ownerId } />
|
|
||||||
<Text variant="white" small wrap>
|
|
||||||
{ LocalizeText('infostand.text.petowner', [ 'name' ], [ avatarInfo.ownerName ]) }
|
|
||||||
</Text>
|
|
||||||
</Flex>
|
|
||||||
</Column>
|
|
||||||
</Column>
|
|
||||||
</Column>
|
|
||||||
<Flex gap={ 1 } justifyContent="end">
|
|
||||||
{ !avatarInfo.dead && ((avatarInfo.energy / avatarInfo.maximumEnergy) < 0.98) &&
|
|
||||||
<Button variant="dark" onClick={ event => processButtonAction('treat') }>
|
<Button variant="dark" onClick={ event => processButtonAction('treat') }>
|
||||||
{ LocalizeText('infostand.button.pettreat') }
|
{ LocalizeText('infostand.button.pettreat') }
|
||||||
</Button>
|
</Button> }
|
||||||
}
|
{ roomSession?.isRoomOwner && (avatarInfo.petType === PetType.MONSTERPLANT) &&
|
||||||
{ roomSession?.isRoomOwner &&
|
|
||||||
<Button variant="dark" onClick={ event => processButtonAction('compost') }>
|
<Button variant="dark" onClick={ event => processButtonAction('compost') }>
|
||||||
{ LocalizeText('infostand.button.compost') }
|
{ LocalizeText('infostand.button.compost') }
|
||||||
</Button>
|
</Button> }
|
||||||
}
|
|
||||||
{ avatarInfo.isOwner &&
|
{ avatarInfo.isOwner &&
|
||||||
<Button variant="dark" onClick={ event => processButtonAction('pick_up') }>
|
<Button variant="dark" onClick={ event => processButtonAction('pick_up') }>
|
||||||
{ LocalizeText('inventory.pets.pickup') }
|
{ LocalizeText('inventory.pets.pickup') }
|
||||||
</Button>
|
</Button> }
|
||||||
}
|
{ (petRespectRemaining > 0) && (avatarInfo.petType !== PetType.MONSTERPLANT) &&
|
||||||
|
<Button variant="dark" onClick={ event => processButtonAction('respect') }>
|
||||||
|
{ LocalizeText('infostand.button.petrespect', [ 'count' ], [ petRespectRemaining.toString() ]) }
|
||||||
|
</Button> }
|
||||||
</Flex>
|
</Flex>
|
||||||
</Column>
|
</Column>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{ avatarInfo.petType !== PetType.MONSTERPLANT &&
|
|
||||||
<InfoStandNormalPet />
|
|
||||||
}
|
|
||||||
{ avatarInfo.petType === PetType.MONSTERPLANT &&
|
|
||||||
<InfoStandMonsterplantPet />
|
|
||||||
}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
@ -3,7 +3,7 @@ import { RoomControllerLevel, RoomObjectCategory, RoomObjectVariable, RoomUnitGi
|
|||||||
import { FC, useEffect, useMemo, useState } from 'react';
|
import { FC, useEffect, useMemo, useState } from 'react';
|
||||||
import { AvatarInfoUser, CreateLinkEvent, DispatchUiEvent, GetOwnRoomObject, GetSessionDataManager, GetUserProfile, LocalizeText, MessengerFriend, ReportType, RoomWidgetUpdateChatInputContentEvent, SendMessageComposer } from '../../../../../api';
|
import { AvatarInfoUser, CreateLinkEvent, DispatchUiEvent, GetOwnRoomObject, GetSessionDataManager, GetUserProfile, LocalizeText, MessengerFriend, ReportType, RoomWidgetUpdateChatInputContentEvent, SendMessageComposer } from '../../../../../api';
|
||||||
import { Base, Flex } from '../../../../../common';
|
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 { ContextMenuHeaderView } from '../../context-menu/ContextMenuHeaderView';
|
||||||
import { ContextMenuListItemView } from '../../context-menu/ContextMenuListItemView';
|
import { ContextMenuListItemView } from '../../context-menu/ContextMenuListItemView';
|
||||||
import { ContextMenuView } from '../../context-menu/ContextMenuView';
|
import { ContextMenuView } from '../../context-menu/ContextMenuView';
|
||||||
@ -26,10 +26,10 @@ export const AvatarInfoWidgetAvatarView: FC<AvatarInfoWidgetAvatarViewProps> = p
|
|||||||
{
|
{
|
||||||
const { avatarInfo = null, onClose = null } = props;
|
const { avatarInfo = null, onClose = null } = props;
|
||||||
const [ mode, setMode ] = useState(MODE_NORMAL);
|
const [ mode, setMode ] = useState(MODE_NORMAL);
|
||||||
const [ respectsLeft, setRespectsLeft ] = useState(0);
|
|
||||||
const { canRequestFriend = null } = useFriends();
|
const { canRequestFriend = null } = useFriends();
|
||||||
const { report = null } = useHelp();
|
const { report = null } = useHelp();
|
||||||
const { roomSession = null } = useRoom();
|
const { roomSession = null } = useRoom();
|
||||||
|
const { userRespectRemaining = 0, respectUser = null } = useSessionInfo();
|
||||||
|
|
||||||
const isShowGiveRights = useMemo(() =>
|
const isShowGiveRights = useMemo(() =>
|
||||||
{
|
{
|
||||||
@ -113,13 +113,9 @@ export const AvatarInfoWidgetAvatarView: FC<AvatarInfoWidgetAvatarViewProps> = p
|
|||||||
setMode(MODE_RELATIONSHIP);
|
setMode(MODE_RELATIONSHIP);
|
||||||
break;
|
break;
|
||||||
case 'respect': {
|
case 'respect': {
|
||||||
let newRespectsLeft = (respectsLeft - 1);
|
respectUser(avatarInfo.webID);
|
||||||
|
|
||||||
setRespectsLeft(newRespectsLeft);
|
if((userRespectRemaining - 1) >= 1) hideMenu = false;
|
||||||
|
|
||||||
GetSessionDataManager().giveRespect(avatarInfo.webID);
|
|
||||||
|
|
||||||
if(newRespectsLeft > 0) hideMenu = false;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'ignore':
|
case 'ignore':
|
||||||
@ -203,7 +199,6 @@ export const AvatarInfoWidgetAvatarView: FC<AvatarInfoWidgetAvatarViewProps> = p
|
|||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
setMode(MODE_NORMAL);
|
setMode(MODE_NORMAL);
|
||||||
setRespectsLeft(avatarInfo.respectLeft);
|
|
||||||
}, [ avatarInfo ]);
|
}, [ avatarInfo ]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -223,9 +218,9 @@ export const AvatarInfoWidgetAvatarView: FC<AvatarInfoWidgetAvatarViewProps> = p
|
|||||||
<ContextMenuListItemView onClick={ event => processAction('whisper') }>
|
<ContextMenuListItemView onClick={ event => processAction('whisper') }>
|
||||||
{ LocalizeText('infostand.button.whisper') }
|
{ LocalizeText('infostand.button.whisper') }
|
||||||
</ContextMenuListItemView>
|
</ContextMenuListItemView>
|
||||||
{ (respectsLeft > 0) &&
|
{ (userRespectRemaining > 0) &&
|
||||||
<ContextMenuListItemView onClick={ event => processAction('respect') }>
|
<ContextMenuListItemView onClick={ event => processAction('respect') }>
|
||||||
{ LocalizeText('infostand.button.respect', [ 'count' ], [ respectsLeft.toString() ]) }
|
{ LocalizeText('infostand.button.respect', [ 'count' ], [ userRespectRemaining.toString() ]) }
|
||||||
</ContextMenuListItemView> }
|
</ContextMenuListItemView> }
|
||||||
{ !canRequestFriend(avatarInfo.webID) &&
|
{ !canRequestFriend(avatarInfo.webID) &&
|
||||||
<ContextMenuListItemView onClick={ event => processAction('relationship') }>
|
<ContextMenuListItemView onClick={ event => processAction('relationship') }>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { PetRespectComposer, PetType, RoomObjectCategory, RoomObjectType, RoomObjectVariable, RoomUnitGiveHandItemPetComposer } from '@nitrots/nitro-renderer';
|
import { PetRespectComposer, PetType, RoomObjectCategory, RoomObjectType, RoomObjectVariable, RoomUnitGiveHandItemPetComposer } from '@nitrots/nitro-renderer';
|
||||||
import { FC, useEffect, useMemo, useState } from 'react';
|
import { FC, useEffect, useMemo, useState } from 'react';
|
||||||
import { AvatarInfoPet, CreateLinkEvent, GetConfiguration, GetOwnRoomObject, GetSessionDataManager, LocalizeText, SendMessageComposer } from '../../../../../api';
|
import { AvatarInfoPet, CreateLinkEvent, GetConfiguration, GetOwnRoomObject, LocalizeText, SendMessageComposer } from '../../../../../api';
|
||||||
import { useRoom } from '../../../../../hooks';
|
import { useRoom, useSessionInfo } from '../../../../../hooks';
|
||||||
import { ContextMenuHeaderView } from '../../context-menu/ContextMenuHeaderView';
|
import { ContextMenuHeaderView } from '../../context-menu/ContextMenuHeaderView';
|
||||||
import { ContextMenuListItemView } from '../../context-menu/ContextMenuListItemView';
|
import { ContextMenuListItemView } from '../../context-menu/ContextMenuListItemView';
|
||||||
import { ContextMenuView } from '../../context-menu/ContextMenuView';
|
import { ContextMenuView } from '../../context-menu/ContextMenuView';
|
||||||
@ -21,8 +21,8 @@ export const AvatarInfoWidgetOwnPetView: FC<AvatarInfoWidgetOwnPetViewProps> = p
|
|||||||
{
|
{
|
||||||
const { avatarInfo = null, onClose = null } = props;
|
const { avatarInfo = null, onClose = null } = props;
|
||||||
const [ mode, setMode ] = useState(MODE_NORMAL);
|
const [ mode, setMode ] = useState(MODE_NORMAL);
|
||||||
const [ respectsLeft, setRespectsLeft ] = useState(0);
|
|
||||||
const { roomSession = null } = useRoom();
|
const { roomSession = null } = useRoom();
|
||||||
|
const { petRespectRemaining = 0, respectPet = null } = useSessionInfo();
|
||||||
|
|
||||||
const canGiveHandItem = useMemo(() =>
|
const canGiveHandItem = useMemo(() =>
|
||||||
{
|
{
|
||||||
@ -49,18 +49,9 @@ export const AvatarInfoWidgetOwnPetView: FC<AvatarInfoWidgetOwnPetViewProps> = p
|
|||||||
switch(name)
|
switch(name)
|
||||||
{
|
{
|
||||||
case 'respect':
|
case 'respect':
|
||||||
let newRespectsLeft = 0;
|
respectPet(avatarInfo.id);
|
||||||
|
|
||||||
setRespectsLeft(prevValue =>
|
if((petRespectRemaining - 1) >= 1) hideMenu = false;
|
||||||
{
|
|
||||||
newRespectsLeft = (prevValue - 1);
|
|
||||||
|
|
||||||
return newRespectsLeft;
|
|
||||||
});
|
|
||||||
|
|
||||||
GetSessionDataManager().givePetRespect(avatarInfo.id);
|
|
||||||
|
|
||||||
if(newRespectsLeft > 0) hideMenu = false;
|
|
||||||
break;
|
break;
|
||||||
case 'treat':
|
case 'treat':
|
||||||
SendMessageComposer(new PetRespectComposer(avatarInfo.id));
|
SendMessageComposer(new PetRespectComposer(avatarInfo.id));
|
||||||
@ -131,8 +122,6 @@ export const AvatarInfoWidgetOwnPetView: FC<AvatarInfoWidgetOwnPetViewProps> = p
|
|||||||
|
|
||||||
return MODE_NORMAL;
|
return MODE_NORMAL;
|
||||||
});
|
});
|
||||||
|
|
||||||
setRespectsLeft(avatarInfo.respectsPetLeft);
|
|
||||||
}, [ avatarInfo ]);
|
}, [ avatarInfo ]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -142,9 +131,9 @@ export const AvatarInfoWidgetOwnPetView: FC<AvatarInfoWidgetOwnPetViewProps> = p
|
|||||||
</ContextMenuHeaderView>
|
</ContextMenuHeaderView>
|
||||||
{ (mode === MODE_NORMAL) &&
|
{ (mode === MODE_NORMAL) &&
|
||||||
<>
|
<>
|
||||||
{ (respectsLeft > 0) &&
|
{ (petRespectRemaining > 0) &&
|
||||||
<ContextMenuListItemView onClick={ event => processAction('respect') }>
|
<ContextMenuListItemView onClick={ event => processAction('respect') }>
|
||||||
{ LocalizeText('infostand.button.petrespect', [ 'count' ], [ respectsLeft.toString() ]) }
|
{ LocalizeText('infostand.button.petrespect', [ 'count' ], [ petRespectRemaining.toString() ]) }
|
||||||
</ContextMenuListItemView> }
|
</ContextMenuListItemView> }
|
||||||
<ContextMenuListItemView onClick={ event => processAction('train') }>
|
<ContextMenuListItemView onClick={ event => processAction('train') }>
|
||||||
{ LocalizeText('infostand.button.train') }
|
{ LocalizeText('infostand.button.train') }
|
||||||
@ -170,9 +159,9 @@ export const AvatarInfoWidgetOwnPetView: FC<AvatarInfoWidgetOwnPetViewProps> = p
|
|||||||
<input type="checkbox" checked={ !!avatarInfo.publiclyRideable } readOnly={ true } />
|
<input type="checkbox" checked={ !!avatarInfo.publiclyRideable } readOnly={ true } />
|
||||||
{ LocalizeText('infostand.button.toggle_riding_permission') }
|
{ LocalizeText('infostand.button.toggle_riding_permission') }
|
||||||
</ContextMenuListItemView>
|
</ContextMenuListItemView>
|
||||||
{ (respectsLeft > 0) &&
|
{ (petRespectRemaining > 0) &&
|
||||||
<ContextMenuListItemView onClick={ event => processAction('respect') }>
|
<ContextMenuListItemView onClick={ event => processAction('respect') }>
|
||||||
{ LocalizeText('infostand.button.petrespect', [ 'count' ], [ respectsLeft.toString() ]) }
|
{ LocalizeText('infostand.button.petrespect', [ 'count' ], [ petRespectRemaining.toString() ]) }
|
||||||
</ContextMenuListItemView> }
|
</ContextMenuListItemView> }
|
||||||
<ContextMenuListItemView onClick={ event => processAction('train') }>
|
<ContextMenuListItemView onClick={ event => processAction('train') }>
|
||||||
{ LocalizeText('infostand.button.train') }
|
{ LocalizeText('infostand.button.train') }
|
||||||
@ -189,9 +178,9 @@ export const AvatarInfoWidgetOwnPetView: FC<AvatarInfoWidgetOwnPetViewProps> = p
|
|||||||
<ContextMenuListItemView onClick={ event => processAction('dismount') }>
|
<ContextMenuListItemView onClick={ event => processAction('dismount') }>
|
||||||
{ LocalizeText('infostand.button.dismount') }
|
{ LocalizeText('infostand.button.dismount') }
|
||||||
</ContextMenuListItemView>
|
</ContextMenuListItemView>
|
||||||
{ (respectsLeft > 0) &&
|
{ (petRespectRemaining > 0) &&
|
||||||
<ContextMenuListItemView onClick={ event => processAction('respect') }>
|
<ContextMenuListItemView onClick={ event => processAction('respect') }>
|
||||||
{ LocalizeText('infostand.button.petrespect', [ 'count' ], [ respectsLeft.toString() ]) }
|
{ LocalizeText('infostand.button.petrespect', [ 'count' ], [ petRespectRemaining.toString() ]) }
|
||||||
</ContextMenuListItemView> }
|
</ContextMenuListItemView> }
|
||||||
</> }
|
</> }
|
||||||
{ (mode === MODE_MONSTER_PLANT) &&
|
{ (mode === MODE_MONSTER_PLANT) &&
|
||||||
@ -209,7 +198,7 @@ export const AvatarInfoWidgetOwnPetView: FC<AvatarInfoWidgetOwnPetViewProps> = p
|
|||||||
</ContextMenuListItemView> }
|
</ContextMenuListItemView> }
|
||||||
{ !avatarInfo.dead && ((avatarInfo.energy / avatarInfo.maximumEnergy) < 0.98) &&
|
{ !avatarInfo.dead && ((avatarInfo.energy / avatarInfo.maximumEnergy) < 0.98) &&
|
||||||
<ContextMenuListItemView onClick={ event => processAction('treat') }>
|
<ContextMenuListItemView onClick={ event => processAction('treat') }>
|
||||||
{ LocalizeText('infostand.button.treat') }
|
{ LocalizeText('infostand.button.pettreat') }
|
||||||
</ContextMenuListItemView> }
|
</ContextMenuListItemView> }
|
||||||
{ !avatarInfo.dead && (avatarInfo.level === avatarInfo.maximumLevel) && avatarInfo.breedable &&
|
{ !avatarInfo.dead && (avatarInfo.level === avatarInfo.maximumLevel) && avatarInfo.breedable &&
|
||||||
<>
|
<>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { PetRespectComposer, PetType, RoomControllerLevel, RoomObjectCategory, RoomObjectType, RoomObjectVariable, RoomUnitGiveHandItemPetComposer } from '@nitrots/nitro-renderer';
|
import { PetRespectComposer, PetType, RoomControllerLevel, RoomObjectCategory, RoomObjectType, RoomObjectVariable, RoomUnitGiveHandItemPetComposer } from '@nitrots/nitro-renderer';
|
||||||
import { FC, useEffect, useMemo, useState } from 'react';
|
import { FC, useEffect, useMemo, useState } from 'react';
|
||||||
import { AvatarInfoPet, GetOwnRoomObject, GetSessionDataManager, LocalizeText, SendMessageComposer } from '../../../../../api';
|
import { AvatarInfoPet, GetOwnRoomObject, GetSessionDataManager, LocalizeText, SendMessageComposer } from '../../../../../api';
|
||||||
import { useRoom } from '../../../../../hooks';
|
import { useRoom, useSessionInfo } from '../../../../../hooks';
|
||||||
import { ContextMenuHeaderView } from '../../context-menu/ContextMenuHeaderView';
|
import { ContextMenuHeaderView } from '../../context-menu/ContextMenuHeaderView';
|
||||||
import { ContextMenuListItemView } from '../../context-menu/ContextMenuListItemView';
|
import { ContextMenuListItemView } from '../../context-menu/ContextMenuListItemView';
|
||||||
import { ContextMenuView } from '../../context-menu/ContextMenuView';
|
import { ContextMenuView } from '../../context-menu/ContextMenuView';
|
||||||
@ -21,8 +21,8 @@ export const AvatarInfoWidgetPetView: FC<AvatarInfoWidgetPetViewProps> = props =
|
|||||||
{
|
{
|
||||||
const { avatarInfo = null, onClose = null } = props;
|
const { avatarInfo = null, onClose = null } = props;
|
||||||
const [ mode, setMode ] = useState(MODE_NORMAL);
|
const [ mode, setMode ] = useState(MODE_NORMAL);
|
||||||
const [ respectsLeft, setRespectsLeft ] = useState(0);
|
|
||||||
const { roomSession = null } = useRoom();
|
const { roomSession = null } = useRoom();
|
||||||
|
const { petRespectRemaining = 0, respectPet = null } = useSessionInfo();
|
||||||
|
|
||||||
const canPickUp = useMemo(() =>
|
const canPickUp = useMemo(() =>
|
||||||
{
|
{
|
||||||
@ -54,18 +54,9 @@ export const AvatarInfoWidgetPetView: FC<AvatarInfoWidgetPetViewProps> = props =
|
|||||||
switch(name)
|
switch(name)
|
||||||
{
|
{
|
||||||
case 'respect':
|
case 'respect':
|
||||||
let newRespectsLeft = 0;
|
respectPet(avatarInfo.id);
|
||||||
|
|
||||||
setRespectsLeft(prevValue =>
|
if((petRespectRemaining - 1) >= 1) hideMenu = false;
|
||||||
{
|
|
||||||
newRespectsLeft = (prevValue - 1);
|
|
||||||
|
|
||||||
return newRespectsLeft;
|
|
||||||
});
|
|
||||||
|
|
||||||
GetSessionDataManager().givePetRespect(avatarInfo.id);
|
|
||||||
|
|
||||||
if(newRespectsLeft > 0) hideMenu = false;
|
|
||||||
break;
|
break;
|
||||||
case 'treat':
|
case 'treat':
|
||||||
SendMessageComposer(new PetRespectComposer(avatarInfo.id));
|
SendMessageComposer(new PetRespectComposer(avatarInfo.id));
|
||||||
@ -98,8 +89,6 @@ export const AvatarInfoWidgetPetView: FC<AvatarInfoWidgetPetViewProps> = props =
|
|||||||
|
|
||||||
return MODE_NORMAL;
|
return MODE_NORMAL;
|
||||||
});
|
});
|
||||||
|
|
||||||
setRespectsLeft(avatarInfo.respectsPetLeft);
|
|
||||||
}, [ avatarInfo ]);
|
}, [ avatarInfo ]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -107,9 +96,9 @@ export const AvatarInfoWidgetPetView: FC<AvatarInfoWidgetPetViewProps> = props =
|
|||||||
<ContextMenuHeaderView>
|
<ContextMenuHeaderView>
|
||||||
{ avatarInfo.name }
|
{ avatarInfo.name }
|
||||||
</ContextMenuHeaderView>
|
</ContextMenuHeaderView>
|
||||||
{ (mode === MODE_NORMAL) && (respectsLeft > 0) &&
|
{ (mode === MODE_NORMAL) && (petRespectRemaining > 0) &&
|
||||||
<ContextMenuListItemView onClick={ event => processAction('respect') }>
|
<ContextMenuListItemView onClick={ event => processAction('respect') }>
|
||||||
{ LocalizeText('infostand.button.petrespect', [ 'count' ], [ respectsLeft.toString() ]) }
|
{ LocalizeText('infostand.button.petrespect', [ 'count' ], [ petRespectRemaining.toString() ]) }
|
||||||
</ContextMenuListItemView> }
|
</ContextMenuListItemView> }
|
||||||
{ (mode === MODE_SADDLED_UP) &&
|
{ (mode === MODE_SADDLED_UP) &&
|
||||||
<>
|
<>
|
||||||
@ -117,9 +106,9 @@ export const AvatarInfoWidgetPetView: FC<AvatarInfoWidgetPetViewProps> = props =
|
|||||||
<ContextMenuListItemView onClick={ event => processAction('mount') }>
|
<ContextMenuListItemView onClick={ event => processAction('mount') }>
|
||||||
{ LocalizeText('infostand.button.mount') }
|
{ LocalizeText('infostand.button.mount') }
|
||||||
</ContextMenuListItemView> }
|
</ContextMenuListItemView> }
|
||||||
{ (respectsLeft > 0) &&
|
{ (petRespectRemaining > 0) &&
|
||||||
<ContextMenuListItemView onClick={ event => processAction('respect') }>
|
<ContextMenuListItemView onClick={ event => processAction('respect') }>
|
||||||
{ LocalizeText('infostand.button.petrespect', [ 'count' ], [ respectsLeft.toString() ]) }
|
{ LocalizeText('infostand.button.petrespect', [ 'count' ], [ petRespectRemaining.toString() ]) }
|
||||||
</ContextMenuListItemView> }
|
</ContextMenuListItemView> }
|
||||||
</> }
|
</> }
|
||||||
{ (mode === MODE_RIDING) &&
|
{ (mode === MODE_RIDING) &&
|
||||||
@ -127,14 +116,14 @@ export const AvatarInfoWidgetPetView: FC<AvatarInfoWidgetPetViewProps> = props =
|
|||||||
<ContextMenuListItemView onClick={ event => processAction('dismount') }>
|
<ContextMenuListItemView onClick={ event => processAction('dismount') }>
|
||||||
{ LocalizeText('infostand.button.dismount') }
|
{ LocalizeText('infostand.button.dismount') }
|
||||||
</ContextMenuListItemView>
|
</ContextMenuListItemView>
|
||||||
{ (respectsLeft > 0) &&
|
{ (petRespectRemaining > 0) &&
|
||||||
<ContextMenuListItemView onClick={ event => processAction('respect') }>
|
<ContextMenuListItemView onClick={ event => processAction('respect') }>
|
||||||
{ LocalizeText('infostand.button.petrespect', [ 'count' ], [ respectsLeft.toString() ]) }
|
{ LocalizeText('infostand.button.petrespect', [ 'count' ], [ petRespectRemaining.toString() ]) }
|
||||||
</ContextMenuListItemView> }
|
</ContextMenuListItemView> }
|
||||||
</> }
|
</> }
|
||||||
{ (mode === MODE_MONSTER_PLANT) && !avatarInfo.dead && ((avatarInfo.energy / avatarInfo.maximumEnergy) < 0.98) &&
|
{ (mode === MODE_MONSTER_PLANT) && !avatarInfo.dead && ((avatarInfo.energy / avatarInfo.maximumEnergy) < 0.98) &&
|
||||||
<ContextMenuListItemView onClick={ event => processAction('treat') }>
|
<ContextMenuListItemView onClick={ event => processAction('treat') }>
|
||||||
{ LocalizeText('infostand.button.treat') }
|
{ LocalizeText('infostand.button.pettreat') }
|
||||||
</ContextMenuListItemView> }
|
</ContextMenuListItemView> }
|
||||||
{ canPickUp &&
|
{ canPickUp &&
|
||||||
<ContextMenuListItemView onClick={ event => processAction('pick_up') }>
|
<ContextMenuListItemView onClick={ event => processAction('pick_up') }>
|
||||||
|
@ -88,10 +88,17 @@ export const ChatInputView: FC<{}> = props =>
|
|||||||
setIsIdle(false);
|
setIsIdle(false);
|
||||||
|
|
||||||
if(text.length <= maxChatLength)
|
if(text.length <= maxChatLength)
|
||||||
|
{
|
||||||
|
if(/%CC%/g.test(encodeURIComponent(text)))
|
||||||
|
{
|
||||||
|
setChatValue('');
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
setChatValue('');
|
setChatValue('');
|
||||||
sendChat(text, chatType, recipientName, chatStyleId);
|
sendChat(text, chatType, recipientName, chatStyleId);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setChatValue(append);
|
setChatValue(append);
|
||||||
}, [ chatModeIdWhisper, chatModeIdShout, chatModeIdSpeak, maxChatLength, chatStyleId, setIsTyping, setIsIdle, sendChat ]);
|
}, [ chatModeIdWhisper, chatModeIdShout, chatModeIdSpeak, maxChatLength, chatStyleId, setIsTyping, setIsIdle, sendChat ]);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { FurnitureStackHeightComposer } from '@nitrots/nitro-renderer';
|
import { FurnitureStackHeightComposer } from '@nitrots/nitro-renderer';
|
||||||
import { FC } from 'react';
|
import { FC, useEffect, useState } from 'react';
|
||||||
import ReactSlider from 'react-slider';
|
import ReactSlider from 'react-slider';
|
||||||
import { LocalizeText, SendMessageComposer } from '../../../../api';
|
import { LocalizeText, SendMessageComposer } from '../../../../api';
|
||||||
import { Button, Column, Flex, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../../common';
|
import { Button, Column, Flex, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../../common';
|
||||||
@ -8,6 +8,23 @@ import { useFurnitureStackHeightWidget } from '../../../../hooks';
|
|||||||
export const FurnitureStackHeightView: FC<{}> = props =>
|
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, 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;
|
if(objectId === -1) return null;
|
||||||
|
|
||||||
@ -25,7 +42,7 @@ export const FurnitureStackHeightView: FC<{}> = props =>
|
|||||||
value={ height }
|
value={ height }
|
||||||
onChange={ event => updateHeight(event) }
|
onChange={ event => updateHeight(event) }
|
||||||
renderThumb={ (props, state) => <div { ...props }>{ state.valueNow }</div> } />
|
renderThumb={ (props, state) => <div { ...props }>{ state.valueNow }</div> } />
|
||||||
<input className="show-number-arrows" type="number" min={ 0 } max={ maxHeight } value={ height } onChange={ event => updateHeight(parseFloat(event.target.value)) } />
|
<input className="show-number-arrows" style={ { width: 50 } } type="number" min={ 0 } max={ maxHeight } value={ tempHeight } onChange={ event => updateTempHeight(event.target.value) } />
|
||||||
</Flex>
|
</Flex>
|
||||||
<Column gap={ 1 }>
|
<Column gap={ 1 }>
|
||||||
<Button onClick={ event => SendMessageComposer(new FurnitureStackHeightComposer(objectId, -100)) }>
|
<Button onClick={ event => SendMessageComposer(new FurnitureStackHeightComposer(objectId, -100)) }>
|
||||||
|
@ -5,6 +5,8 @@ import { useFurnitureStickieWidget } from '../../../../hooks';
|
|||||||
|
|
||||||
const STICKIE_COLORS = [ '9CCEFF','FF9CFF', '9CFF9C','FFFF33' ];
|
const STICKIE_COLORS = [ '9CCEFF','FF9CFF', '9CFF9C','FFFF33' ];
|
||||||
const STICKIE_COLOR_NAMES = [ 'blue', 'pink', 'green', 'yellow' ];
|
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) =>
|
const getStickieColorName = (color: string) =>
|
||||||
{
|
{
|
||||||
@ -15,31 +17,43 @@ const getStickieColorName = (color: string) =>
|
|||||||
return STICKIE_COLOR_NAMES[index];
|
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 =>
|
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);
|
const [ isEditing, setIsEditing ] = useState(false);
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
setIsEditing(false);
|
setIsEditing(false);
|
||||||
}, [ objectId, color, text ]);
|
}, [ objectId, color, text, type ]);
|
||||||
|
|
||||||
if(objectId === -1) return null;
|
if(objectId === -1) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DraggableWindow handleSelector=".drag-handler" windowPosition={ DraggableWindowPosition.TOP_LEFT }>
|
<DraggableWindow handleSelector=".drag-handler" windowPosition={ DraggableWindowPosition.TOP_LEFT }>
|
||||||
<div className={ 'nitro-stickie nitro-stickie-image stickie-' + getStickieColorName(color) }>
|
<div className={ 'nitro-stickie nitro-stickie-image stickie-' + (type == 'post_it' ? getStickieColorName(color) : getStickieTypeName(type)) }>
|
||||||
<div className="d-flex align-items-center stickie-header drag-handler">
|
<div className="d-flex align-items-center stickie-header drag-handler">
|
||||||
<div className="d-flex align-items-center flex-grow-1 h-100">
|
<div className="d-flex align-items-center flex-grow-1 h-100">
|
||||||
{ canModify &&
|
{ canModify &&
|
||||||
<>
|
<>
|
||||||
<div className="nitro-stickie-image stickie-trash header-trash" onClick={ trash }></div>
|
<div className="nitro-stickie-image stickie-trash header-trash" onClick={ trash }></div>
|
||||||
|
{ type == 'post_it' &&
|
||||||
|
<>
|
||||||
{ STICKIE_COLORS.map(color =>
|
{ STICKIE_COLORS.map(color =>
|
||||||
{
|
{
|
||||||
return <div key={ color } className="stickie-color ms-1" onClick={ event => updateColor(color) } style={ { backgroundColor: ColorUtils.makeColorHex(color) } } />
|
return <div key={ color } className="stickie-color ms-1" onClick={ event => updateColor(color) } style={ { backgroundColor: ColorUtils.makeColorHex(color) } } />
|
||||||
}) }
|
}) }
|
||||||
</> }
|
</> }
|
||||||
|
</> }
|
||||||
</div>
|
</div>
|
||||||
<div className="d-flex align-items-center nitro-stickie-image stickie-close header-close" onClick={ onClose }></div>
|
<div className="d-flex align-items-center nitro-stickie-image stickie-close header-close" onClick={ onClose }></div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -161,6 +161,26 @@
|
|||||||
background-position: -2px -184px;
|
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 {
|
&.stickie-close {
|
||||||
width: 10px;
|
width: 10px;
|
||||||
height: 10px;
|
height: 10px;
|
||||||
|
@ -19,7 +19,7 @@ export const WiredBaseView: FC<PropsWithChildren<WiredBaseViewProps>> = props =>
|
|||||||
const [ wiredName, setWiredName ] = useState<string>(null);
|
const [ wiredName, setWiredName ] = useState<string>(null);
|
||||||
const [ wiredDescription, setWiredDescription ] = useState<string>(null);
|
const [ wiredDescription, setWiredDescription ] = useState<string>(null);
|
||||||
const [ needsSave, setNeedsSave ] = useState<boolean>(false);
|
const [ needsSave, setNeedsSave ] = useState<boolean>(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);
|
const onClose = () => setTrigger(null);
|
||||||
|
|
||||||
@ -83,6 +83,11 @@ export const WiredBaseView: FC<PropsWithChildren<WiredBaseViewProps>> = props =>
|
|||||||
}
|
}
|
||||||
}, [ trigger, hasSpecialInput, requiresFurni, setIntParams, setStringParam, setFurniIds ]);
|
}, [ trigger, hasSpecialInput, requiresFurni, setIntParams, setStringParam, setFurniIds ]);
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
setAllowsFurni(requiresFurni);
|
||||||
|
}, [ requiresFurni, setAllowsFurni ]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NitroCardView uniqueKey="nitro-wired" className="nitro-wired" theme="primary-slim">
|
<NitroCardView uniqueKey="nitro-wired" className="nitro-wired" theme="primary-slim">
|
||||||
<NitroCardHeaderView headerText={ LocalizeText('wiredfurni.title') } onCloseClick={ onClose } />
|
<NitroCardHeaderView headerText={ LocalizeText('wiredfurni.title') } onCloseClick={ onClose } />
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { FC, useEffect, useState } from 'react';
|
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 { Column, Flex, Text } from '../../../../common';
|
||||||
import { useWired } from '../../../../hooks';
|
import { useWired } from '../../../../hooks';
|
||||||
import { WiredActionBaseView } from './WiredActionBaseView';
|
import { WiredActionBaseView } from './WiredActionBaseView';
|
||||||
@ -35,7 +35,7 @@ export const WiredActionBotTalkToAvatarView: FC<{}> = props =>
|
|||||||
</Column>
|
</Column>
|
||||||
<Column gap={ 1 }>
|
<Column gap={ 1 }>
|
||||||
<Text bold>{ LocalizeText('wiredfurni.params.message') }</Text>
|
<Text bold>{ LocalizeText('wiredfurni.params.message') }</Text>
|
||||||
<input type="text" className="form-control form-control-sm" maxLength={ 64 } value={ message } onChange={ event => setMessage(event.target.value) } />
|
<input type="text" className="form-control form-control-sm" maxLength={ GetConfiguration<number>('wired.action.bot.talk.to.avatar.max.length', 64) } value={ message } onChange={ event => setMessage(event.target.value) } />
|
||||||
</Column>
|
</Column>
|
||||||
<Column gap={ 1 }>
|
<Column gap={ 1 }>
|
||||||
<Flex alignItems="center" gap={ 1 }>
|
<Flex alignItems="center" gap={ 1 }>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { FC, useEffect, useState } from 'react';
|
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 { Column, Flex, Text } from '../../../../common';
|
||||||
import { useWired } from '../../../../hooks';
|
import { useWired } from '../../../../hooks';
|
||||||
import { WiredActionBaseView } from './WiredActionBaseView';
|
import { WiredActionBaseView } from './WiredActionBaseView';
|
||||||
@ -35,7 +35,7 @@ export const WiredActionBotTalkView: FC<{}> = props =>
|
|||||||
</Column>
|
</Column>
|
||||||
<Column gap={ 1 }>
|
<Column gap={ 1 }>
|
||||||
<Text bold>{ LocalizeText('wiredfurni.params.message') }</Text>
|
<Text bold>{ LocalizeText('wiredfurni.params.message') }</Text>
|
||||||
<input type="text" className="form-control form-control-sm" maxLength={ 64 } value={ message } onChange={ event => setMessage(event.target.value) } />
|
<input type="text" className="form-control form-control-sm" maxLength={ GetConfiguration<number>('wired.action.bot.talk.max.length', 64) } value={ message } onChange={ event => setMessage(event.target.value) } />
|
||||||
</Column>
|
</Column>
|
||||||
<Column gap={ 1 }>
|
<Column gap={ 1 }>
|
||||||
<Flex alignItems="center" gap={ 1 }>
|
<Flex alignItems="center" gap={ 1 }>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { FC, useEffect, useState } from 'react';
|
import { FC, useEffect, useState } from 'react';
|
||||||
import { LocalizeText, WiredFurniType } from '../../../../api';
|
import { GetConfiguration, LocalizeText, WiredFurniType } from '../../../../api';
|
||||||
import { Column, Text } from '../../../../common';
|
import { Column, Text } from '../../../../common';
|
||||||
import { useWired } from '../../../../hooks';
|
import { useWired } from '../../../../hooks';
|
||||||
import { WiredActionBaseView } from './WiredActionBaseView';
|
import { WiredActionBaseView } from './WiredActionBaseView';
|
||||||
@ -20,7 +20,7 @@ export const WiredActionChatView: FC<{}> = props =>
|
|||||||
<WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } hasSpecialInput={ true } save={ save }>
|
<WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } hasSpecialInput={ true } save={ save }>
|
||||||
<Column gap={ 1 }>
|
<Column gap={ 1 }>
|
||||||
<Text bold>{ LocalizeText('wiredfurni.params.message') }</Text>
|
<Text bold>{ LocalizeText('wiredfurni.params.message') }</Text>
|
||||||
<input type="text" className="form-control form-control-sm" value={ message } onChange={ event => setMessage(event.target.value) } maxLength={ 100 } />
|
<input type="text" className="form-control form-control-sm" value={ message } onChange={ event => setMessage(event.target.value) } maxLength={ GetConfiguration<number>('wired.action.chat.max.length', 100) } />
|
||||||
</Column>
|
</Column>
|
||||||
</WiredActionBaseView>
|
</WiredActionBaseView>
|
||||||
);
|
);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { FC, useEffect, useState } from 'react';
|
import { FC, useEffect, useState } from 'react';
|
||||||
import { LocalizeText, WiredFurniType } from '../../../../api';
|
import { GetConfiguration, LocalizeText, WiredFurniType } from '../../../../api';
|
||||||
import { Column, Text } from '../../../../common';
|
import { Column, Text } from '../../../../common';
|
||||||
import { useWired } from '../../../../hooks';
|
import { useWired } from '../../../../hooks';
|
||||||
import { WiredActionBaseView } from './WiredActionBaseView';
|
import { WiredActionBaseView } from './WiredActionBaseView';
|
||||||
@ -20,7 +20,7 @@ export const WiredActionKickFromRoomView: FC<{}> = props =>
|
|||||||
<WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } hasSpecialInput={ true } save={ save }>
|
<WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } hasSpecialInput={ true } save={ save }>
|
||||||
<Column gap={ 1 }>
|
<Column gap={ 1 }>
|
||||||
<Text bold>{ LocalizeText('wiredfurni.params.message') }</Text>
|
<Text bold>{ LocalizeText('wiredfurni.params.message') }</Text>
|
||||||
<input type="text" className="form-control form-control-sm" value={ message } onChange={ event => setMessage(event.target.value) } maxLength={ 100 } />
|
<input type="text" className="form-control form-control-sm" value={ message } onChange={ event => setMessage(event.target.value) } maxLength={ GetConfiguration<number>('wired.action.kick.from.room.max.length', 100) } />
|
||||||
</Column>
|
</Column>
|
||||||
</WiredActionBaseView>
|
</WiredActionBaseView>
|
||||||
);
|
);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { FC, useEffect, useState } from 'react';
|
import { FC, useEffect, useState } from 'react';
|
||||||
import ReactSlider from 'react-slider';
|
import ReactSlider from 'react-slider';
|
||||||
import { LocalizeText, WiredFurniType } from '../../../../api';
|
import { GetConfiguration, LocalizeText, WiredFurniType } from '../../../../api';
|
||||||
import { Column, Text } from '../../../../common';
|
import { Column, Text } from '../../../../common';
|
||||||
import { useWired } from '../../../../hooks';
|
import { useWired } from '../../../../hooks';
|
||||||
import { WiredActionBaseView } from './WiredActionBaseView';
|
import { WiredActionBaseView } from './WiredActionBaseView';
|
||||||
@ -36,7 +36,7 @@ export const WiredActionMuteUserView: FC<{}> = props =>
|
|||||||
</Column>
|
</Column>
|
||||||
<Column gap={ 1 }>
|
<Column gap={ 1 }>
|
||||||
<Text bold>{ LocalizeText('wiredfurni.params.message') }</Text>
|
<Text bold>{ LocalizeText('wiredfurni.params.message') }</Text>
|
||||||
<input type="text" className="form-control form-control-sm" value={ message } onChange={ event => setMessage(event.target.value) } maxLength={ 100 } />
|
<input type="text" className="form-control form-control-sm" value={ message } onChange={ event => setMessage(event.target.value) } maxLength={ GetConfiguration<number>('wired.action.mute.user.max.length', 100) } />
|
||||||
</Column>
|
</Column>
|
||||||
</WiredActionBaseView>
|
</WiredActionBaseView>
|
||||||
);
|
);
|
||||||
|
@ -875,6 +875,13 @@ const useCatalogState = () =>
|
|||||||
if(!searchResult && currentPage && (currentPage.pageId === -1)) openPageById(previousPageId);
|
if(!searchResult && currentPage && (currentPage.pageId === -1)) openPageById(previousPageId);
|
||||||
}, [ searchResult, currentPage, previousPageId, openPageById ]);
|
}, [ searchResult, currentPage, previousPageId, openPageById ]);
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
if(!currentOffer) return;
|
||||||
|
|
||||||
|
setPurchaseOptions({ quantity: 1, extraData: null, extraParamRequired: false, previewStuffData: null });
|
||||||
|
}, [ currentOffer ]);
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
if(!isVisible || rootNode) return;
|
if(!isVisible || rootNode) return;
|
||||||
|
@ -10,6 +10,7 @@ const useFurnitureStickieWidgetState = () =>
|
|||||||
const [ category, setCategory ] = useState(-1);
|
const [ category, setCategory ] = useState(-1);
|
||||||
const [ color, setColor ] = useState('0');
|
const [ color, setColor ] = useState('0');
|
||||||
const [ text, setText ] = useState('');
|
const [ text, setText ] = useState('');
|
||||||
|
const [ type, setType ] = useState('');
|
||||||
const [ canModify, setCanModify ] = useState(false);
|
const [ canModify, setCanModify ] = useState(false);
|
||||||
|
|
||||||
const onClose = () =>
|
const onClose = () =>
|
||||||
@ -18,6 +19,7 @@ const useFurnitureStickieWidgetState = () =>
|
|||||||
setCategory(-1);
|
setCategory(-1);
|
||||||
setColor('0');
|
setColor('0');
|
||||||
setText('');
|
setText('');
|
||||||
|
setType('');
|
||||||
setCanModify(false);
|
setCanModify(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,6 +68,7 @@ const useFurnitureStickieWidgetState = () =>
|
|||||||
setCategory(event.category);
|
setCategory(event.category);
|
||||||
setColor(color || '0');
|
setColor(color || '0');
|
||||||
setText(text || '');
|
setText(text || '');
|
||||||
|
setType(roomObject.type || 'post_it');
|
||||||
setCanModify(GetRoomSession().isRoomOwner || GetSessionDataManager().isModerator || IsOwnerOfFurniture(roomObject));
|
setCanModify(GetRoomSession().isRoomOwner || GetSessionDataManager().isModerator || IsOwnerOfFurniture(roomObject));
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -76,7 +79,7 @@ const useFurnitureStickieWidgetState = () =>
|
|||||||
onClose();
|
onClose();
|
||||||
});
|
});
|
||||||
|
|
||||||
return { objectId, color, text, canModify, updateColor, updateText, trash, onClose };
|
return { objectId, color, text, type, canModify, updateColor, updateText, trash, onClose };
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useFurnitureStickieWidget = useFurnitureStickieWidgetState;
|
export const useFurnitureStickieWidget = useFurnitureStickieWidgetState;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { FigureUpdateEvent, RoomUnitChatStyleComposer, UserInfoDataParser, UserInfoEvent, UserSettingsEvent } from '@nitrots/nitro-renderer';
|
import { FigureUpdateEvent, RoomUnitChatStyleComposer, UserInfoDataParser, UserInfoEvent, UserSettingsEvent } from '@nitrots/nitro-renderer';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useBetween } from 'use-between';
|
import { useBetween } from 'use-between';
|
||||||
import { SendMessageComposer } from '../../api';
|
import { GetSessionDataManager, SendMessageComposer } from '../../api';
|
||||||
import { useMessageEvent } from '../events';
|
import { useMessageEvent } from '../events';
|
||||||
|
|
||||||
const useSessionInfoState = () =>
|
const useSessionInfoState = () =>
|
||||||
@ -9,6 +9,8 @@ const useSessionInfoState = () =>
|
|||||||
const [ userInfo, setUserInfo ] = useState<UserInfoDataParser>(null);
|
const [ userInfo, setUserInfo ] = useState<UserInfoDataParser>(null);
|
||||||
const [ userFigure, setUserFigure ] = useState<string>(null);
|
const [ userFigure, setUserFigure ] = useState<string>(null);
|
||||||
const [ chatStyleId, setChatStyleId ] = useState<number>(0);
|
const [ chatStyleId, setChatStyleId ] = useState<number>(0);
|
||||||
|
const [ userRespectRemaining, setUserRespectRemaining ] = useState<number>(0);
|
||||||
|
const [ petRespectRemaining, setPetRespectRemaining ] = useState<number>(0);
|
||||||
|
|
||||||
const updateChatStyleId = (styleId: number) =>
|
const updateChatStyleId = (styleId: number) =>
|
||||||
{
|
{
|
||||||
@ -17,12 +19,28 @@ const useSessionInfoState = () =>
|
|||||||
SendMessageComposer(new RoomUnitChatStyleComposer(styleId));
|
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>(UserInfoEvent, event =>
|
useMessageEvent<UserInfoEvent>(UserInfoEvent, event =>
|
||||||
{
|
{
|
||||||
const parser = event.getParser();
|
const parser = event.getParser();
|
||||||
|
|
||||||
setUserInfo(parser.userInfo);
|
setUserInfo(parser.userInfo);
|
||||||
setUserFigure(parser.userInfo.figure);
|
setUserFigure(parser.userInfo.figure);
|
||||||
|
setUserRespectRemaining(parser.userInfo.respectsRemaining);
|
||||||
|
setPetRespectRemaining(parser.userInfo.respectsPetRemaining);
|
||||||
});
|
});
|
||||||
|
|
||||||
useMessageEvent<FigureUpdateEvent>(FigureUpdateEvent, event =>
|
useMessageEvent<FigureUpdateEvent>(FigureUpdateEvent, event =>
|
||||||
@ -39,7 +57,7 @@ const useSessionInfoState = () =>
|
|||||||
setChatStyleId(parser.chatType);
|
setChatStyleId(parser.chatType);
|
||||||
});
|
});
|
||||||
|
|
||||||
return { userInfo, userFigure, chatStyleId, updateChatStyleId };
|
return { userInfo, userFigure, chatStyleId, userRespectRemaining, petRespectRemaining, respectUser, respectPet, updateChatStyleId };
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useSessionInfo = () => useBetween(useSessionInfoState);
|
export const useSessionInfo = () => useBetween(useSessionInfoState);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { ConditionDefinition, Triggerable, TriggerDefinition, UpdateActionMessageComposer, UpdateConditionMessageComposer, UpdateTriggerMessageComposer, WiredActionDefinition, WiredFurniActionEvent, WiredFurniConditionEvent, WiredFurniTriggerEvent, WiredSaveSuccessEvent } from '@nitrots/nitro-renderer';
|
import { ConditionDefinition, Triggerable, TriggerDefinition, UpdateActionMessageComposer, UpdateConditionMessageComposer, UpdateTriggerMessageComposer, WiredActionDefinition, WiredFurniActionEvent, WiredFurniConditionEvent, WiredFurniTriggerEvent, WiredSaveSuccessEvent } from '@nitrots/nitro-renderer';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { useBetween } from 'use-between';
|
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 { useMessageEvent } from '../events';
|
||||||
import { useNotification } from '../notification';
|
import { useNotification } from '../notification';
|
||||||
|
|
||||||
@ -12,6 +12,7 @@ const useWiredState = () =>
|
|||||||
const [ stringParam, setStringParam ] = useState<string>('');
|
const [ stringParam, setStringParam ] = useState<string>('');
|
||||||
const [ furniIds, setFurniIds ] = useState<number[]>([]);
|
const [ furniIds, setFurniIds ] = useState<number[]>([]);
|
||||||
const [ actionDelay, setActionDelay ] = useState<number>(0);
|
const [ actionDelay, setActionDelay ] = useState<number>(0);
|
||||||
|
const [ allowsFurni, setAllowsFurni ] = useState<number>(WiredFurniType.STUFF_SELECTION_OPTION_NONE);
|
||||||
const { showConfirm = null } = useNotification();
|
const { showConfirm = null } = useNotification();
|
||||||
|
|
||||||
const saveWired = () =>
|
const saveWired = () =>
|
||||||
@ -51,7 +52,7 @@ const useWiredState = () =>
|
|||||||
|
|
||||||
const selectObjectForWired = (objectId: number, category: number) =>
|
const selectObjectForWired = (objectId: number, category: number) =>
|
||||||
{
|
{
|
||||||
if(!trigger) return;
|
if(!trigger || !allowsFurni) return;
|
||||||
|
|
||||||
if(objectId <= 0) return;
|
if(objectId <= 0) return;
|
||||||
|
|
||||||
@ -122,10 +123,11 @@ const useWiredState = () =>
|
|||||||
|
|
||||||
return [];
|
return [];
|
||||||
});
|
});
|
||||||
|
setAllowsFurni(WiredFurniType.STUFF_SELECTION_OPTION_NONE);
|
||||||
}
|
}
|
||||||
}, [ trigger ]);
|
}, [ 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);
|
export const useWired = () => useBetween(useWiredState);
|
||||||
|
Loading…
Reference in New Issue
Block a user