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", "socket.url": "wss://ws.nitrots.co:2096",
"asset.url": "https://nitro.nitrots.co", "asset.url": "https://nitro.nitrots.co",
"image.library.url": "https://swf.nitrots.co/c_images/", "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", "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", "image.library.notifications.url": "${image.library.url}notifications/%image%.png",
"achievements.images.url": "${image.library.url}Quests/%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.addedFriends) processUpdate(friend); for(const friend of update.updatedFriends) processUpdate(friend);
for(const removedFriendId of update.removedFriendIds) for(const removedFriendId of update.removedFriendIds)
{ {

View File

@ -1,5 +1,6 @@
import { FollowFriendComposer, MouseEventType, Nitro } from 'nitro-renderer'; import { FollowFriendComposer, MouseEventType } from 'nitro-renderer';
import { FC, useEffect, useRef, useState } from 'react'; import { FC, useCallback, useEffect, useRef, useState } from 'react';
import { GetConnection } from '../../../../api';
import { LocalizeText } from '../../../../utils/LocalizeText'; import { LocalizeText } from '../../../../utils/LocalizeText';
import { AvatarImageView } from '../../../shared/avatar-image/AvatarImageView'; import { AvatarImageView } from '../../../shared/avatar-image/AvatarImageView';
import { FriendBarItemViewProps } from './FriendBarItemView.types'; import { FriendBarItemViewProps } from './FriendBarItemView.types';
@ -8,14 +9,14 @@ export const FriendBarItemView: FC<FriendBarItemViewProps> = props =>
{ {
const { friend = null } = props; const { friend = null } = props;
const [ isVisible, setVisible ] = useState(false); const [ isVisible, setVisible ] = useState(false);
const toggleVisible = () => setVisible(prevCheck => !prevCheck);
const elementRef = useRef<HTMLDivElement>(); 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; const element = elementRef.current;
@ -23,22 +24,17 @@ export const FriendBarItemView: FC<FriendBarItemViewProps> = props =>
{ {
setVisible(false); setVisible(false);
} }
} }, []);
useEffect(() =>
{
document.addEventListener(MouseEventType.MOUSE_CLICK, onClick); document.addEventListener(MouseEventType.MOUSE_CLICK, onClick);
return () => return () =>
{ {
document.removeEventListener(MouseEventType.MOUSE_CLICK, onClick); document.removeEventListener(MouseEventType.MOUSE_CLICK, onClick);
} }
}, [ elementRef, setVisible ]); }, [ onClick ]);
const followFriend = () =>
{
Nitro.instance.communication.connection.send(new FollowFriendComposer(friend.id));
}
if(!friend) if(!friend)
{ {
@ -51,14 +47,15 @@ export const FriendBarItemView: FC<FriendBarItemViewProps> = props =>
} }
return ( 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"> <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>
<div className="text-truncate">{ friend.name }</div> <div className="text-truncate">{ friend.name }</div>
{isVisible && <div className="d-flex justify-content-between"> { isVisible &&
<div className="d-flex justify-content-between">
<i className="icon icon-fb-chat cursor-pointer" /> <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" /> <i className="icon icon-fb-profile cursor-pointer" />
</div> } </div> }
</div> </div>

View File

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

View File

@ -8,9 +8,9 @@ export const InventoryActiveBadgeResultsView: FC<InventoryActiveBadgeResultsView
return ( return (
<div className="row row-cols-3 align-content-start g-0"> <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> </div>
); );

View File

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

View File

@ -9,9 +9,9 @@ export const InventoryBotResultsView: FC<InventoryBotResultsViewProps> = props =
return ( return (
<div className="h-100 overflow-hidden"> <div className="h-100 overflow-hidden">
<div className="row row-cols-5 align-content-start g-0 w-100 h-100 overflow-auto"> <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>
</div> </div>

View File

@ -9,9 +9,9 @@ export const InventoryPetResultsView: FC<InventoryPetResultsViewProps> = props =
return ( return (
<div className="h-100 overflow-hidden"> <div className="h-100 overflow-hidden">
<div className="row row-cols-5 align-content-start g-0 w-100 h-100 overflow-auto"> <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>
</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 { FC, useCallback } from 'react';
import { CreateMessageHook } from '../../hooks/messages/message-event'; import { CreateMessageHook } from '../../hooks/messages/message-event';
import { Currency } from './common/Currency'; import { Currency } from './common/Currency';
@ -48,9 +48,27 @@ export const PurseMessageHandler: FC<PurseMessageHandlerProps> = props =>
}); });
}, [ dispatchPurseState ]); }, [ 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(UserCreditsEvent, onUserCreditsEvent);
CreateMessageHook(UserCurrencyEvent, onUserCurrencyEvent); CreateMessageHook(UserCurrencyEvent, onUserCurrencyEvent);
CreateMessageHook(UserCurrencyUpdateEvent, onUserCurrencyUpdateEvent); CreateMessageHook(UserCurrencyUpdateEvent, onUserCurrencyUpdateEvent);
CreateMessageHook(UserSubscriptionEvent, onUserSubscriptionEvent);
return null; return null;
} }

View File

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

View File

@ -122,9 +122,9 @@ export const FurnitureStickieView: FC<FurnitureStickieViewProps> = props =>
{ stickieData.canModify && { stickieData.canModify &&
<> <>
<div className="nitro-stickie-image stickie-trash header-trash" onClick={ event => processAction('trash') }></div> <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> </div>

View File

@ -24,9 +24,9 @@ export const InfoStandWidgetBotView: FC<InfoStandWidgetBotViewProps> = props =>
<AvatarImageView figure={ botData.figure } direction={ 4 } /> <AvatarImageView figure={ botData.figure } direction={ 4 } />
</div> </div>
<div className="w-100 d-flex justify-content-center align-items-center"> <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>
</div> </div>

View File

@ -36,9 +36,9 @@ export const InfoStandWidgetRentableBotView: FC<InfoStandWidgetRentableBotViewPr
<AvatarImageView figure={ rentableBotData.figure } direction={ 4 } /> <AvatarImageView figure={ rentableBotData.figure } direction={ 4 } />
</div> </div>
<div className="w-100 d-flex justify-content-center align-items-center"> <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>
</div> </div>

View File

@ -26,9 +26,9 @@ export const WiredConditionActorHasHandItemView: FC<{}> = props =>
<div className="form-group"> <div className="form-group">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.handitem') }</label> <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)) }> <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> </select>
</div> </div>

View File

@ -25,10 +25,10 @@ export const WiredConditionActorIsTeamMemberView: FC<{}> = props =>
<WiredConditionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }> <WiredConditionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }>
<div className="form-group"> <div className="form-group">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.team') }</label> <label className="fw-bold">{ LocalizeText('wiredfurni.params.team') }</label>
{ teamIds.map((value, index) => { teamIds.map(value =>
{ {
return ( 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) } /> <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 }` }> <label className="form-check-label" htmlFor={ `selectedTeam${ value }` }>
{ LocalizeText(`wiredfurni.params.team.${ value }`) } { LocalizeText(`wiredfurni.params.team.${ value }`) }