Merge remote-tracking branch 'origin/dev' into @feature/room-tools

This commit is contained in:
MyNameIsBatman 2021-07-04 16:53:51 -03:00
commit 5403b176e2
15 changed files with 95 additions and 62 deletions

View File

@ -2,6 +2,7 @@
"socket.url": "wss://ws.nitrots.co:2096",
"asset.url": "https://nitro.nitrots.co",
"image.library.url": "https://swf.nitrots.co/c_images/",
"internal.samples.url": "",
"external.samples.url": "https://swf.nitrots.co/dcr/hof_furni/mp3/sound_machine_sample_%sample%.mp3",
"image.library.notifications.url": "${image.library.url}notifications/%image%.png",
"achievements.images.url": "${image.library.url}Quests/%image%.png",

View File

@ -103,7 +103,7 @@ export const FriendListReducer: Reducer<IFriendListState, IFriendListAction> = (
for(const friend of update.addedFriends) processUpdate(friend);
for(const friend of update.addedFriends) processUpdate(friend);
for(const friend of update.updatedFriends) processUpdate(friend);
for(const removedFriendId of update.removedFriendIds)
{

View File

@ -1,5 +1,6 @@
import { FollowFriendComposer, MouseEventType, Nitro } from 'nitro-renderer';
import { FC, useEffect, useRef, useState } from 'react';
import { FollowFriendComposer, MouseEventType } from 'nitro-renderer';
import { FC, useCallback, useEffect, useRef, useState } from 'react';
import { GetConnection } from '../../../../api';
import { LocalizeText } from '../../../../utils/LocalizeText';
import { AvatarImageView } from '../../../shared/avatar-image/AvatarImageView';
import { FriendBarItemViewProps } from './FriendBarItemView.types';
@ -7,15 +8,15 @@ import { FriendBarItemViewProps } from './FriendBarItemView.types';
export const FriendBarItemView: FC<FriendBarItemViewProps> = props =>
{
const { friend = null } = props;
const [isVisible, setVisible] = useState(false);
const toggleVisible = () => setVisible(prevCheck => !prevCheck);
const [ isVisible, setVisible ] = useState(false);
const elementRef = useRef<HTMLDivElement>();
useEffect(() =>
const followFriend = useCallback(() =>
{
function onClick(event: MouseEvent): void
GetConnection().send(new FollowFriendComposer(friend.id));
}, [ friend ]);
const onClick = useCallback((event: MouseEvent) =>
{
const element = elementRef.current;
@ -23,22 +24,17 @@ export const FriendBarItemView: FC<FriendBarItemViewProps> = props =>
{
setVisible(false);
}
}
}, []);
useEffect(() =>
{
document.addEventListener(MouseEventType.MOUSE_CLICK, onClick);
return () =>
{
document.removeEventListener(MouseEventType.MOUSE_CLICK, onClick);
}
}, [ elementRef, setVisible ]);
const followFriend = () =>
{
Nitro.instance.communication.connection.send(new FollowFriendComposer(friend.id));
}
}, [ onClick ]);
if(!friend)
{
@ -51,16 +47,17 @@ export const FriendBarItemView: FC<FriendBarItemViewProps> = props =>
}
return (
<div ref={ elementRef } className={"btn btn-success friend-bar-item " + (isVisible ? "friend-bar-item-active" : "")} onClick={ event => toggleVisible()}>
<div ref={ elementRef } className={"btn btn-success friend-bar-item " + (isVisible ? "friend-bar-item-active" : "")} onClick={ event => setVisible(prevValue => !prevValue) }>
<div className="friend-bar-item-head position-absolute">
<AvatarImageView headOnly={true} figure={friend.figure} direction={2} />
<AvatarImageView headOnly={ true } figure={ friend.figure } direction={ 2 } />
</div>
<div className="text-truncate">{friend.name}</div>
{isVisible && <div className="d-flex justify-content-between">
<div className="text-truncate">{ friend.name }</div>
{ isVisible &&
<div className="d-flex justify-content-between">
<i className="icon icon-fb-chat cursor-pointer" />
{friend.followingAllowed && <i onClick={ event => followFriend() } className="icon icon-fb-visit cursor-pointer" />}
{ friend.followingAllowed && <i onClick={ followFriend } className="icon icon-fb-visit cursor-pointer" /> }
<i className="icon icon-fb-profile cursor-pointer" />
</div>}
</div> }
</div>
);
}

View File

@ -8,6 +8,12 @@ export const FriendBarView: FC<FriendBarViewProps> = props =>
const { friendListState = null } = useFriendListContext();
const { friends = null } = friendListState;
const [ indexOffset, setIndexOffset ] = useState(0);
const [ maxDisplayCount, setMaxDisplayCount ] = useState(3);
const onlineFriends = useMemo(() =>
{
return friends.filter(friend => friend.online);
}, [ friends ]);
const canDecreaseIndex = useMemo(() =>
{
@ -18,20 +24,21 @@ export const FriendBarView: FC<FriendBarViewProps> = props =>
const canIncreaseIndex = useMemo(() =>
{
if(indexOffset === (friends.length - 1)) return false;
if((onlineFriends.length <= maxDisplayCount) || (indexOffset === (onlineFriends.length - 1))) return false;
return true;
}, [ indexOffset, friends ]);
}, [ maxDisplayCount, indexOffset, onlineFriends ]);
return (
<div className="d-flex friend-bar align-items-center">
<button type="button" className="btn btn-sm btn-black align-self-center friend-bar-button" disabled={!canDecreaseIndex} onClick={event => setIndexOffset(indexOffset - 1)}>
<button type="button" className="btn btn-sm btn-black align-self-center friend-bar-button" disabled={ !canDecreaseIndex } onClick={ event => setIndexOffset(indexOffset - 1) }>
<i className="fas fa-chevron-left" />
</button>
<FriendBarItemView friend={ (friends[ indexOffset ] || null) } />
<FriendBarItemView friend={ (friends[ indexOffset + 1 ] || null) } />
<FriendBarItemView friend={ (friends[ indexOffset + 2 ] || null) } />
<button type="button" className="btn btn-sm btn-black align-self-center friend-bar-button" disabled={!canIncreaseIndex} onClick={event => setIndexOffset(indexOffset + 1)}>
{ Array.from(Array(maxDisplayCount), (e, i) =>
{
return <FriendBarItemView friend={ (onlineFriends[ indexOffset + i ] || null) } />;
}) }
<button type="button" className="btn btn-sm btn-black align-self-center friend-bar-button" disabled={ !canIncreaseIndex } onClick={ event => setIndexOffset(indexOffset + 1) }>
<i className="fas fa-chevron-right" />
</button>
</div>

View File

@ -8,9 +8,9 @@ export const InventoryActiveBadgeResultsView: FC<InventoryActiveBadgeResultsView
return (
<div className="row row-cols-3 align-content-start g-0">
{ badges && (badges.length > 0) && badges.map((code, index) =>
{ badges && (badges.length > 0) && badges.map(code =>
{
return <InventoryBadgeItemView key={ index } badge={ code } />
return <InventoryBadgeItemView key={ code } badge={ code } />
}) }
</div>
);

View File

@ -9,11 +9,11 @@ export const InventoryBadgeResultsView: FC<InventoryBadgeResultsViewProps> = pro
return (
<div className="h-100 overflow-hidden">
<div className="row row-cols-5 align-content-start g-0 w-100 h-100 overflow-auto">
{ badges && (badges.length > 0) && badges.map((code, index) =>
{ badges && (badges.length > 0) && badges.map(code =>
{
if(activeBadges.indexOf(code) >= 0) return null;
return <InventoryBadgeItemView key={ index } badge={ code } />
return <InventoryBadgeItemView key={ code } badge={ code } />
}) }
</div>
</div>

View File

@ -9,9 +9,9 @@ export const InventoryBotResultsView: FC<InventoryBotResultsViewProps> = props =
return (
<div className="h-100 overflow-hidden">
<div className="row row-cols-5 align-content-start g-0 w-100 h-100 overflow-auto">
{ botItems && (botItems.length > 0) && botItems.map((item, index) =>
{ botItems && (botItems.length > 0) && botItems.map(item =>
{
return <InventoryBotItemView key={ index } botItem={ item } />
return <InventoryBotItemView key={ item.id } botItem={ item } />
}) }
</div>
</div>

View File

@ -9,9 +9,9 @@ export const InventoryPetResultsView: FC<InventoryPetResultsViewProps> = props =
return (
<div className="h-100 overflow-hidden">
<div className="row row-cols-5 align-content-start g-0 w-100 h-100 overflow-auto">
{ petItems && (petItems.length > 0) && petItems.map((item, index) =>
{ petItems && (petItems.length > 0) && petItems.map(item =>
{
return <InventoryPetItemView key={ index } petItem={ item } />
return <InventoryPetItemView key={ item.id } petItem={ item } />
}) }
</div>
</div>

View File

@ -1,4 +1,4 @@
import { UserCreditsEvent, UserCurrencyEvent, UserCurrencyUpdateEvent } from 'nitro-renderer';
import { UserCreditsEvent, UserCurrencyEvent, UserCurrencyUpdateEvent, UserSubscriptionEvent } from 'nitro-renderer';
import { FC, useCallback } from 'react';
import { CreateMessageHook } from '../../hooks/messages/message-event';
import { Currency } from './common/Currency';
@ -48,9 +48,27 @@ export const PurseMessageHandler: FC<PurseMessageHandlerProps> = props =>
});
}, [ dispatchPurseState ]);
const onUserSubscriptionEvent = useCallback((event: UserSubscriptionEvent) =>
{
const parser = event.getParser();
switch(parser.name)
{
case 'habbo_club':
dispatchPurseState({
type: PurseActions.SET_CLUB_SUBSCRIPTION,
payload: {
clubSubscription: parser
}
});
return;
}
}, [ dispatchPurseState ]);
CreateMessageHook(UserCreditsEvent, onUserCreditsEvent);
CreateMessageHook(UserCurrencyEvent, onUserCurrencyEvent);
CreateMessageHook(UserCurrencyUpdateEvent, onUserCurrencyUpdateEvent);
CreateMessageHook(UserSubscriptionEvent, onUserSubscriptionEvent);
return null;
}

View File

@ -1,9 +1,11 @@
import { UserSubscriptionParser } from 'nitro-renderer';
import { Reducer } from 'react';
import { Currency } from '../common/Currency';
export interface IPurseState
{
currencies: Currency[];
clubSubscription: UserSubscriptionParser;
}
export interface IPurseAction
@ -12,6 +14,7 @@ export interface IPurseAction
payload: {
currency?: Currency;
currencies?: Currency[];
clubSubscription?: UserSubscriptionParser;
}
}
@ -19,10 +22,12 @@ export class PurseActions
{
public static SET_CURRENCY: string = 'PA_SET_CURRENCY';
public static SET_CURRENCIES: string = 'PA_SET_CURRENCIES';
public static SET_CLUB_SUBSCRIPTION: string = 'PA_SET_CLUB_SUBSCRIPTION';
}
export const initialPurse: IPurseState = {
currencies: []
currencies: [],
clubSubscription: null
}
export const PurseReducer: Reducer<IPurseState, IPurseAction> = (state, action) =>
@ -34,7 +39,7 @@ export const PurseReducer: Reducer<IPurseState, IPurseAction> = (state, action)
let didSet = false;
const currencies = state.currencies.map((existing, index) =>
const currencies = state.currencies.map(existing =>
{
if(existing.type !== updated.type) return existing;
@ -50,7 +55,7 @@ export const PurseReducer: Reducer<IPurseState, IPurseAction> = (state, action)
case PurseActions.SET_CURRENCIES: {
const updated = action.payload.currencies;
const currencies = state.currencies.filter((existing, index) =>
const currencies = state.currencies.filter(existing =>
{
if(existing.type !== -1) return null;
@ -61,6 +66,11 @@ export const PurseReducer: Reducer<IPurseState, IPurseAction> = (state, action)
return { ...state, currencies };
}
case PurseActions.SET_CLUB_SUBSCRIPTION: {
const clubSubscription = action.payload.clubSubscription;
return { ...state, clubSubscription };
}
default:
return state;
}

View File

@ -122,9 +122,9 @@ export const FurnitureStickieView: FC<FurnitureStickieViewProps> = props =>
{ stickieData.canModify &&
<>
<div className="nitro-stickie-image stickie-trash header-trash" onClick={ event => processAction('trash') }></div>
{ STICKIE_COLORS.map((color, index) =>
{ STICKIE_COLORS.map(color =>
{
return <div className="stickie-color ms-1" key={ index } onClick={ event => processAction('changeColor', color) } style={ {backgroundColor: ColorUtils.makeColorHex(color) } } />
return <div key={ color } className="stickie-color ms-1" onClick={ event => processAction('changeColor', color) } style={ {backgroundColor: ColorUtils.makeColorHex(color) } } />
})}
</> }
</div>

View File

@ -24,9 +24,9 @@ export const InfoStandWidgetBotView: FC<InfoStandWidgetBotViewProps> = props =>
<AvatarImageView figure={ botData.figure } direction={ 4 } />
</div>
<div className="w-100 d-flex justify-content-center align-items-center">
{ (botData.badges.length > 0) && botData.badges.map((result, index) =>
{ (botData.badges.length > 0) && botData.badges.map(result =>
{
return <BadgeImageView key={ index } badgeCode={ result } />;
return <BadgeImageView key={ result } badgeCode={ result } />;
}) }
</div>
</div>

View File

@ -36,9 +36,9 @@ export const InfoStandWidgetRentableBotView: FC<InfoStandWidgetRentableBotViewPr
<AvatarImageView figure={ rentableBotData.figure } direction={ 4 } />
</div>
<div className="w-100 d-flex justify-content-center align-items-center">
{ (rentableBotData.badges.length > 0) && rentableBotData.badges.map((result, index) =>
{ (rentableBotData.badges.length > 0) && rentableBotData.badges.map(result =>
{
return <BadgeImageView key={ index } badgeCode={ result } />;
return <BadgeImageView key={ result } badgeCode={ result } />;
}) }
</div>
</div>

View File

@ -26,9 +26,9 @@ export const WiredConditionActorHasHandItemView: FC<{}> = props =>
<div className="form-group">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.handitem') }</label>
<select className="form-select form-select-sm" value={ handItemId } onChange={ event => setHandItemId(parseInt(event.target.value)) }>
{ allowedHanditemIds.map((value, index) =>
{ allowedHanditemIds.map(value =>
{
return <option key={ index } value={ value }>{ LocalizeText(`handitem${ value }`) }</option>
return <option key={ value } value={ value }>{ LocalizeText(`handitem${ value }`) }</option>
}) }
</select>
</div>

View File

@ -25,10 +25,10 @@ export const WiredConditionActorIsTeamMemberView: FC<{}> = props =>
<WiredConditionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }>
<div className="form-group">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.team') }</label>
{ teamIds.map((value, index) =>
{ teamIds.map(value =>
{
return (
<div key={ index } className="form-check">
<div key={ value } className="form-check">
<input className="form-check-input" type="radio" name="selectedTeam" id={ `selectedTeam${ value }` } checked={ (selectedTeam === value) } onChange={ event => setSelectedTeam(value) } />
<label className="form-check-label" htmlFor={ `selectedTeam${ value }` }>
{ LocalizeText(`wiredfurni.params.team.${ value }`) }