diff --git a/src/views/friends/FriendsView.scss b/src/views/friends/FriendsView.scss index 35888832..6bfa3033 100644 --- a/src/views/friends/FriendsView.scss +++ b/src/views/friends/FriendsView.scss @@ -1,6 +1,95 @@ +.nitro-friends-spritesheet { + background: url('../../assets/images/friends/friends-spritesheet.png') transparent no-repeat; + + &.icon-friendbar-visit { + width: 21px; height: 21px; + background-position: -38px -5px; + } + + &.icon-heart { + width: 16px; height: 14px; + background-position: -5px -67px; + } + + &.icon-new-message { + width: 14px; height: 14px; + background-position: -96px -53px; + } + + &.icon-none { + width: 16px; height: 14px; + background-position: -31px -67px; + } + + &.icon-profile { + width: 21px; height: 21px; + background-position: -5px -36px; + } + + &.icon-profile-sm { + width: 13px; height: 11px; + background-position: -51px -91px; + + &:hover { + width: 13px; height: 11px; + background-position: -74px -91px; + } + } + + &.icon-smile { + width: 16px; height: 14px; + background-position: -57px -67px; + } + + &.icon-warning { + width: 23px; height: 21px; + background-position: -5px -5px; + } + + &.icon-accept { + width: 13px; height: 14px; + background-position: -5px -91px; + } + + &.icon-add { + width: 16px; height: 15px; + background-position: -69px -31px; + } + + &.icon-bobba { + width: 16px; height: 14px; + background-position: -96px -5px; + } + + &.icon-chat { + width: 17px; height: 16px; + background-position: -69px -5px; + } + + &.icon-deny { + width: 13px; height: 14px; + background-position: -28px -91px; + } + + &.icon-follow { + width: 16px; height: 14px; + background-position: -96px -29px; + } + + &.icon-friendbar-chat { + width: 20px; height: 21px; + background-position: -36px -36px; + } +} + .nitro-friends { width: $friends-list-width; height: $friends-list-height; + + .search-input { + border: 0; + border-bottom: 1px solid rgba($black, 0.2); + } } @import "./views/friend-bar/FriendBarView"; diff --git a/src/views/friends/FriendsView.tsx b/src/views/friends/FriendsView.tsx index fedb706f..768698c2 100644 --- a/src/views/friends/FriendsView.tsx +++ b/src/views/friends/FriendsView.tsx @@ -344,7 +344,7 @@ export const FriendsView: FC<{}> = props => }, [ requests ]); return ( - + { isReady && createPortal(, document.getElementById('toolbar-friend-bar-container')) } { isVisible && diff --git a/src/views/friends/context/FriendsContext.tsx b/src/views/friends/context/FriendsContext.tsx index a93a2f43..a86f130d 100644 --- a/src/views/friends/context/FriendsContext.tsx +++ b/src/views/friends/context/FriendsContext.tsx @@ -5,6 +5,8 @@ const FriendsContext = createContext({ friends: null, requests: null, settings: null, + canRequestFriend: null, + requestFriend: null, acceptFriend: null, declineFriend: null }); diff --git a/src/views/friends/context/FriendsContext.type.ts b/src/views/friends/context/FriendsContext.type.ts index 2eaf79a9..772372d3 100644 --- a/src/views/friends/context/FriendsContext.type.ts +++ b/src/views/friends/context/FriendsContext.type.ts @@ -8,6 +8,8 @@ export interface IFriendsContext friends: MessengerFriend[]; requests: MessengerRequest[]; settings: MessengerSettings; + canRequestFriend: (userId: number) => boolean; + requestFriend: (userId: number, userName: string) => void; acceptFriend: (userId: number) => void; declineFriend: (userId: number, declineAll?: boolean) => void; } diff --git a/src/views/friends/views/friend-bar-item/FriendBarItemView.tsx b/src/views/friends/views/friend-bar-item/FriendBarItemView.tsx index 36079517..045edf63 100644 --- a/src/views/friends/views/friend-bar-item/FriendBarItemView.tsx +++ b/src/views/friends/views/friend-bar-item/FriendBarItemView.tsx @@ -2,6 +2,7 @@ import { FollowFriendMessageComposer, MouseEventType } from '@nitrots/nitro-rend import { FC, useCallback, useEffect, useRef, useState } from 'react'; import { GetUserProfile, LocalizeText, OpenMessengerChat } from '../../../../api'; import { SendMessageHook } from '../../../../hooks/messages'; +import { NitroLayoutBase } from '../../../../layout/base'; import { AvatarImageView } from '../../../shared/avatar-image/AvatarImageView'; import { FriendBarItemViewProps } from './FriendBarItemView.types'; @@ -63,9 +64,10 @@ export const FriendBarItemView: FC = props =>
{ friend.name }
{ isVisible &&
- - { friend.followingAllowed && } - GetUserProfile(friend.id) } className="icon icon-fb-profile cursor-pointer" /> + + { friend.followingAllowed && + } + GetUserProfile(friend.id) } />
} ); diff --git a/src/views/friends/views/friend-bar/FriendBarView.tsx b/src/views/friends/views/friend-bar/FriendBarView.tsx index a0347c94..aaff2555 100644 --- a/src/views/friends/views/friend-bar/FriendBarView.tsx +++ b/src/views/friends/views/friend-bar/FriendBarView.tsx @@ -1,4 +1,6 @@ import { FC, useMemo, useState } from 'react'; +import { NitroLayoutButton, NitroLayoutFlex } from '../../../../layout'; +import { NitroLayoutBase } from '../../../../layout/base'; import { FriendBarItemView } from '../friend-bar-item/FriendBarItemView'; import { FriendBarViewProps } from './FriendBarView.types'; @@ -24,10 +26,10 @@ export const FriendBarView: FC = props => }, [ maxDisplayCount, indexOffset, onlineFriends ]); return ( -
- + + setIndexOffset(indexOffset - 1) }> + + { Array.from(Array(maxDisplayCount), (e, i) => { return ; @@ -35,6 +37,6 @@ export const FriendBarView: FC = props => -
+ ); } diff --git a/src/views/friends/views/friends-group-item/FriendsGroupItemView.tsx b/src/views/friends/views/friends-group-item/FriendsGroupItemView.tsx index 60b2066a..1c7b2932 100644 --- a/src/views/friends/views/friends-group-item/FriendsGroupItemView.tsx +++ b/src/views/friends/views/friends-group-item/FriendsGroupItemView.tsx @@ -2,7 +2,8 @@ import { FollowFriendMessageComposer, SetRelationshipStatusComposer } from '@nit import { FC, useCallback, useState } from 'react'; import { LocalizeText, OpenMessengerChat } from '../../../../api'; import { SendMessageHook } from '../../../../hooks'; -import { UserProfileIconView } from '../../../shared/user-profile-icon/UserProfileIconView'; +import { NitroLayoutFlex, UserProfileIconView } from '../../../../layout'; +import { NitroLayoutBase } from '../../../../layout/base'; import { MessengerFriend } from '../../common/MessengerFriend'; import { FriendsGroupItemViewProps } from './FriendsGroupItemView.types'; @@ -52,19 +53,23 @@ export const FriendsGroupItemView: FC = props =>
{ friend.name }
-
- { !isExpanded && <> - { friend.followingAllowed && } - { friend.online && } - setIsExpanded(true) } title={ LocalizeText('infostand.link.relationship') } /> + + { !isExpanded && + <> + { friend.followingAllowed && + } + { friend.online && + } + setIsExpanded(true) } title={ LocalizeText('infostand.link.relationship') } /> } - { isExpanded && <> - updateRelationship(MessengerFriend.RELATIONSHIP_HEART) } /> - updateRelationship(MessengerFriend.RELATIONSHIP_SMILE) } /> - updateRelationship(MessengerFriend.RELATIONSHIP_BOBBA) } /> - updateRelationship(MessengerFriend.RELATIONSHIP_NONE) } /> - } -
+ { isExpanded && + <> + updateRelationship(MessengerFriend.RELATIONSHIP_HEART) } /> + updateRelationship(MessengerFriend.RELATIONSHIP_SMILE) } /> + updateRelationship(MessengerFriend.RELATIONSHIP_BOBBA) } /> + updateRelationship(MessengerFriend.RELATIONSHIP_NONE) } /> + } +
); } diff --git a/src/views/friends/views/friends-list/FriendsListView.tsx b/src/views/friends/views/friends-list/FriendsListView.tsx index f706d334..fcf0c9c5 100644 --- a/src/views/friends/views/friends-list/FriendsListView.tsx +++ b/src/views/friends/views/friends-list/FriendsListView.tsx @@ -3,6 +3,7 @@ import { LocalizeText } from '../../../../api'; import { NitroCardAccordionSetView, NitroCardAccordionView, NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../../../layout'; import { FriendsGroupView } from '../friends-group/FriendsGroupView'; import { FriendsRequestView } from '../friends-request/FriendsRequestView'; +import { FriendsSearchView } from '../friends-search/FriendsSearchView'; import { FriendsListViewProps } from './FriendsListView.types'; const MODE_FRIENDS: number = 0; @@ -15,7 +16,7 @@ export const FriendsListView: FC = props => const [ mode, setMode ] = useState(0); return ( - + setMode(MODE_FRIENDS) }> @@ -34,13 +35,10 @@ export const FriendsListView: FC = props => - - } { (mode === MODE_SEARCH) && - <> - } + } ); diff --git a/src/views/friends/views/friends-request-item/FriendsRequestItemView.tsx b/src/views/friends/views/friends-request-item/FriendsRequestItemView.tsx index e0929968..f5ae26d9 100644 --- a/src/views/friends/views/friends-request-item/FriendsRequestItemView.tsx +++ b/src/views/friends/views/friends-request-item/FriendsRequestItemView.tsx @@ -1,6 +1,6 @@ import { FC } from 'react'; -import { NitroCardAccordionItemView } from '../../../../layout'; -import { UserProfileIconView } from '../../../shared/user-profile-icon/UserProfileIconView'; +import { NitroCardAccordionItemView, NitroLayoutFlex, UserProfileIconView } from '../../../../layout'; +import { NitroLayoutBase } from '../../../../layout/base'; import { useFriendsContext } from '../../context/FriendsContext'; import { FriendsRequestItemViewProps } from './FriendsRequestItemView.types'; @@ -14,11 +14,11 @@ export const FriendsRequestItemView: FC = props => return ( -
{ request.name }
-
- acceptFriend(request.requesterUserId) } /> - declineFriend(request.requesterUserId) } /> -
+ { request.name } + + acceptFriend(request.requesterUserId) } /> + declineFriend(request.requesterUserId) } /> +
); }; diff --git a/src/views/friends/views/friends-search/FriendsSearchView.tsx b/src/views/friends/views/friends-search/FriendsSearchView.tsx new file mode 100644 index 00000000..891038ba --- /dev/null +++ b/src/views/friends/views/friends-search/FriendsSearchView.tsx @@ -0,0 +1,80 @@ +import { HabboSearchComposer, HabboSearchResultData, HabboSearchResultEvent } from '@nitrots/nitro-renderer'; +import { FC, useCallback, useEffect, useState } from 'react'; +import { LocalizeText, OpenMessengerChat } from '../../../../api'; +import { BatchUpdates, CreateMessageHook, SendMessageHook } from '../../../../hooks'; +import { NitroCardAccordionItemView, NitroCardAccordionSetView, NitroCardAccordionView, NitroLayoutFlex, UserProfileIconView } from '../../../../layout'; +import { NitroLayoutBase } from '../../../../layout/base'; +import { useFriendsContext } from '../../context/FriendsContext'; + +export const FriendsSearchView: FC<{}> = props => +{ + const [ searchValue, setSearchValue ] = useState(''); + const [ friendResults, setFriendResults ] = useState([]); + const [ otherResults, setOtherResults ] = useState([]); + const { canRequestFriend = null, requestFriend = null } = useFriendsContext(); + + const onHabboSearchResultEvent = useCallback((event: HabboSearchResultEvent) => + { + const parser = event.getParser(); + + BatchUpdates(() => + { + setFriendResults(parser.friends); + setOtherResults(parser.others); + }); + }, []); + + CreateMessageHook(HabboSearchResultEvent, onHabboSearchResultEvent); + + useEffect(() => + { + if(!searchValue || !searchValue.length) return; + + const timeout = setTimeout(() => + { + if(!searchValue || !searchValue.length) return; + + SendMessageHook(new HabboSearchComposer(searchValue)); + }, 500); + + return () => clearTimeout(timeout); + }, [ searchValue ]); + + return ( + <> + setSearchValue(event.target.value) } /> + + + { (friendResults.length > 0) && friendResults.map(result => + { + return ( + + + { result.avatarName } + + { result.isAvatarOnline && + OpenMessengerChat(result.avatarId) } title={ LocalizeText('friendlist.tip.im') } /> } + + + ); + }) } + + + { (otherResults.length > 0) && otherResults.map(result => + { + return ( + + + { result.avatarName } + + { canRequestFriend(result.avatarId) && + requestFriend(result.avatarId, result.avatarName) } title={ LocalizeText('friendlist.tip.addfriend') } /> } + + + ); + }) } + + + + ); +} diff --git a/src/views/friends/views/messenger-thread-group/FriendsMessengerThreadGroup.tsx b/src/views/friends/views/messenger-thread-group/FriendsMessengerThreadGroup.tsx index b0d30ea7..47ce9415 100644 --- a/src/views/friends/views/messenger-thread-group/FriendsMessengerThreadGroup.tsx +++ b/src/views/friends/views/messenger-thread-group/FriendsMessengerThreadGroup.tsx @@ -1,5 +1,7 @@ import { FC } from 'react'; import { GetSessionDataManager } from '../../../../api'; +import { NitroLayoutFlex } from '../../../../layout'; +import { NitroLayoutBase } from '../../../../layout/base'; import { AvatarImageView } from '../../../shared/avatar-image/AvatarImageView'; import { MessengerThreadChat } from '../../common/MessengerThreadChat'; import { FriendsMessengerThreadGroupProps } from './FriendsMessengerThreadGroup.types'; @@ -17,13 +19,13 @@ export const FriendsMessengerThreadGroup: FC = { group.chats.map((chat, index) => { return ( -
+ { chat.type === MessengerThreadChat.SECURITY_NOTIFICATION && -
- -
{ chat.message }
-
} -
+ + + { chat.message } + } + ); }) } @@ -31,18 +33,18 @@ export const FriendsMessengerThreadGroup: FC = } return ( -
+ { (group.userId > 0) && -
+ -
} -
- { group.chats.map((chat, index) =>
{ chat.message }
) } -
+ } + + { group.chats.map((chat, index) => { chat.message }) } + { (group.userId === 0) && -
+ -
} -
+ } + ); } diff --git a/src/views/friends/views/messenger/FriendsMessengerView.tsx b/src/views/friends/views/messenger/FriendsMessengerView.tsx index 115d7d55..7faec597 100644 --- a/src/views/friends/views/messenger/FriendsMessengerView.tsx +++ b/src/views/friends/views/messenger/FriendsMessengerView.tsx @@ -3,7 +3,8 @@ import { FC, KeyboardEvent, useCallback, useEffect, useMemo, useRef, useState } import { AddEventLinkTracker, GetUserProfile, LocalizeText, RemoveLinkEventTracker } from '../../../../api'; import { FriendsMessengerIconEvent } from '../../../../events'; import { BatchUpdates, CreateMessageHook, dispatchUiEvent, SendMessageHook } from '../../../../hooks'; -import { NitroCardContentView, NitroCardHeaderView, NitroCardView, NitroLayoutFlex } from '../../../../layout'; +import { NitroCardContentView, NitroCardHeaderView, NitroCardView, NitroLayoutButton, NitroLayoutButtonGroup, NitroLayoutFlex, NitroLayoutFlexColumn } from '../../../../layout'; +import { NitroLayoutBase } from '../../../../layout/base'; import { AvatarImageView } from '../../../shared/avatar-image/AvatarImageView'; import { MessengerThread } from '../../common/MessengerThread'; import { MessengerThreadChat } from '../../common/MessengerThreadChat'; @@ -232,7 +233,7 @@ export const FriendsMessengerView: FC<{}> = props => if(!isVisible) return null; return ( - + setIsVisible(false) } /> @@ -241,8 +242,9 @@ export const FriendsMessengerView: FC<{}> = props => const messageThreadIndex = messageThreads.indexOf(thread); return ( -
setActiveThreadIndex(messageThreadIndex) }> - { thread.unread && } +
setActiveThreadIndex(messageThreadIndex) }> + { thread.unread && + }
); @@ -250,32 +252,38 @@ export const FriendsMessengerView: FC<{}> = props => { (activeThreadIndex >= 0) && -
+ { LocalizeText('messenger.window.separator', [ 'FRIEND_NAME' ], [ messageThreads[activeThreadIndex].participant.name ]) } -
} + }
{ (activeThreadIndex >= 0) && <> -
-
- - -
- - -
-
+ + + + + + + + + + + { LocalizeText('messenger.window.button.report') } + + closeThread(activeThreadIndex) }> + + + + -
-
+ + setMessageText(event.target.value) } onKeyDown={ onKeyDown } /> - -
+ + { LocalizeText('widgets.chatinput.say') } + + } diff --git a/src/views/friends/views/request-item/FriendsRequestItemView.tsx b/src/views/friends/views/request-item/FriendsRequestItemView.tsx index f25c42f9..50c7d243 100644 --- a/src/views/friends/views/request-item/FriendsRequestItemView.tsx +++ b/src/views/friends/views/request-item/FriendsRequestItemView.tsx @@ -1,7 +1,7 @@ import { AcceptFriendMessageComposer, DeclineFriendMessageComposer } from '@nitrots/nitro-renderer'; import { FC, useCallback } from 'react'; -import { SendMessageHook } from '../../../../hooks/messages/message-event'; -import { UserProfileIconView } from '../../../shared/user-profile-icon/UserProfileIconView'; +import { SendMessageHook } from '../../../../hooks'; +import { UserProfileIconView } from '../../../../layout'; import { FriendsRequestItemViewProps } from './FriendsRequestItemView.types'; export const FriendsRequestItemView: FC = props =>