Friend List
BIN
src/assets/images/friendlist/icons/icon_chat.png
Normal file
After Width: | Height: | Size: 199 B |
BIN
src/assets/images/friendlist/icons/icon_follow.png
Normal file
After Width: | Height: | Size: 162 B |
BIN
src/assets/images/friendlist/icons/icon_relationship_none.png
Normal file
After Width: | Height: | Size: 177 B |
Before Width: | Height: | Size: 174 B After Width: | Height: | Size: 174 B |
Before Width: | Height: | Size: 173 B After Width: | Height: | Size: 173 B |
BIN
src/assets/images/icons/icon_cog.png
Normal file
After Width: | Height: | Size: 218 B |
@ -119,6 +119,12 @@
|
||||
height: 34px;
|
||||
}
|
||||
|
||||
&.icon-cog {
|
||||
background: url('../images/icons/icon_cog.png');
|
||||
width: 14px;
|
||||
height: 15px;
|
||||
}
|
||||
|
||||
&.icon-joinroom {
|
||||
background-image: url('../images/toolbar/icons/joinroom.png');
|
||||
width: 21px;
|
||||
@ -147,6 +153,18 @@
|
||||
}
|
||||
}
|
||||
|
||||
&.icon-deny {
|
||||
background: url('../images/icons/deny.png');
|
||||
width: 13px;
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
&.icon-accept {
|
||||
background: url('../images/icons/accept.png');
|
||||
width: 13px;
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
&.icon-wired-trigger {
|
||||
background-image: url('../images/wired/icon_trigger.png');
|
||||
width: 13px;
|
||||
@ -531,6 +549,12 @@
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
&.icon-relationship-none {
|
||||
background: url('../images/friendlist/icons/icon_relationship_none.png');
|
||||
width: 16px;
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
&.icon-relationship-heart {
|
||||
background: url('../images/profile/icons/heart.png');
|
||||
width: 16px;
|
||||
@ -615,18 +639,6 @@
|
||||
height: 13px;
|
||||
}
|
||||
|
||||
&.icon-group-remove-member {
|
||||
background: url('../images/groups/icons/group_icon_remove_member.png');
|
||||
width: 13px;
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
&.icon-group-accept-member {
|
||||
background: url('../images/groups/icons/group_icon_accept_member.png');
|
||||
width: 13px;
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
&.icon-group-small-owner {
|
||||
background: url('../images/groups/icons/group_icon_small_owner.png');
|
||||
width: 13px;
|
||||
@ -663,6 +675,18 @@
|
||||
height: 11px;
|
||||
}
|
||||
|
||||
&.icon-friendlist-follow {
|
||||
background: url('../images/friendlist/icons/icon_follow.png');
|
||||
width: 16px;
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
&.icon-friendlist-chat {
|
||||
background: url('../images/friendlist/icons/icon_chat.png');
|
||||
width: 17px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
&.spin {
|
||||
animation: rotating 1s linear infinite;
|
||||
}
|
||||
|
@ -3,13 +3,7 @@
|
||||
border-bottom: 1px solid rgba($black, 0.2);
|
||||
}
|
||||
|
||||
&.active {
|
||||
> .nitro-card-accordion-item-header {
|
||||
background: rgba($white, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
.nitro-card-accordion-item-content {
|
||||
background: rgba($black, 0.1);
|
||||
background: rgba($white, 0.5);
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { FriendListFragmentEvent, FriendListUpdateEvent, GetFriendRequestsComposer, MessengerInitEvent } from '@nitrots/nitro-renderer';
|
||||
import { FriendListFragmentEvent, FriendListUpdateEvent, FriendRequestsEvent, GetFriendRequestsComposer, MessengerInitEvent } from '@nitrots/nitro-renderer';
|
||||
import { FC, useCallback } from 'react';
|
||||
import { CreateMessageHook, SendMessageHook } from '../../hooks/messages/message-event';
|
||||
import { MessengerSettings } from './common/MessengerSettings';
|
||||
@ -52,9 +52,22 @@ export const FriendListMessageHandler: FC<FriendListMessageHandlerProps> = props
|
||||
});
|
||||
}, [ dispatchFriendListState ]);
|
||||
|
||||
const onFriendRequestsEvent = useCallback((event: FriendRequestsEvent) =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
|
||||
dispatchFriendListState({
|
||||
type: FriendListActions.PROCESS_REQUESTS,
|
||||
payload: {
|
||||
requests: parser.requests
|
||||
}
|
||||
});
|
||||
}, [ dispatchFriendListState ]);
|
||||
|
||||
CreateMessageHook(MessengerInitEvent, onMessengerInitEvent);
|
||||
CreateMessageHook(FriendListFragmentEvent, onFriendListFragmentEvent);
|
||||
CreateMessageHook(FriendListUpdateEvent, onFriendListUpdateEvent);
|
||||
CreateMessageHook(FriendRequestsEvent, onFriendRequestsEvent);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { MessengerInitComposer, RoomEngineObjectEvent, RoomObjectCategory, RoomObjectUserType } from '@nitrots/nitro-renderer';
|
||||
import { FC, useCallback, useEffect, useReducer, useState } from 'react';
|
||||
import { FC, useCallback, useEffect, useMemo, useReducer, useState } from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
import { GetRoomSession, LocalizeText } from '../../api';
|
||||
import { FriendEnteredRoomEvent, FriendListEvent } from '../../events';
|
||||
@ -8,20 +8,25 @@ import { FriendListSendFriendRequestEvent } from '../../events/friend-list/Frien
|
||||
import { useRoomEngineEvent } from '../../hooks/events';
|
||||
import { dispatchUiEvent, useUiEvent } from '../../hooks/events/ui/ui-event';
|
||||
import { SendMessageHook } from '../../hooks/messages/message-event';
|
||||
import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../layout';
|
||||
import { NitroCardAccordionItemView, NitroCardAccordionView, NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../layout';
|
||||
import { FriendListContextProvider } from './context/FriendListContext';
|
||||
import { FriendListMessageHandler } from './FriendListMessageHandler';
|
||||
import { FriendListViewProps } from './FriendListView.types';
|
||||
import { FriendListReducer, initialFriendList } from './reducers/FriendListReducer';
|
||||
import { FriendBarView } from './views/friend-bar/FriendBarView';
|
||||
import { FriendListFriendsView } from './views/friends/FriendListFriendsView';
|
||||
import { FriendListRequestsView } from './views/requests/FriendListRequestsView';
|
||||
|
||||
const TABS: string[] = ['friendlist.friends', 'generic.search'];
|
||||
|
||||
export const FriendListView: FC<FriendListViewProps> = props =>
|
||||
{
|
||||
const [ friendListState, dispatchFriendListState ] = useReducer(FriendListReducer, initialFriendList);
|
||||
const { friends = null, requests = null, settings = null } = friendListState;
|
||||
|
||||
const [ isVisible, setIsVisible ] = useState(false);
|
||||
const [ isReady, setIsReady ] = useState(false);
|
||||
const [ friendListState, dispatchFriendListState ] = useReducer(FriendListReducer, initialFriendList);
|
||||
const { settings = null } = friendListState;
|
||||
const [ currentTab, setCurrentTab ] = useState<number>(0);
|
||||
|
||||
const onFriendListEvent = useCallback((event: FriendListEvent) =>
|
||||
{
|
||||
@ -37,7 +42,6 @@ export const FriendListView: FC<FriendListViewProps> = props =>
|
||||
const requestEvent = (event as FriendListSendFriendRequestEvent);
|
||||
return;
|
||||
case FriendListEvent.REQUEST_FRIEND_LIST:
|
||||
console.log('requested');
|
||||
dispatchUiEvent(new FriendListContentEvent(friendListState.friends));
|
||||
return;
|
||||
}
|
||||
@ -84,20 +88,49 @@ export const FriendListView: FC<FriendListViewProps> = props =>
|
||||
SendMessageHook(new MessengerInitComposer());
|
||||
}, []);
|
||||
|
||||
const onlineFriends = useMemo(() =>
|
||||
{
|
||||
if(!friends) return [];
|
||||
|
||||
return friends.filter(f => f.online);
|
||||
}, [ friends ]);
|
||||
|
||||
const offlineFriends = useMemo(() =>
|
||||
{
|
||||
if(!friends) return [];
|
||||
|
||||
return friends.filter(f => !f.online);
|
||||
}, [ friends ]);
|
||||
|
||||
return (
|
||||
<FriendListContextProvider value={ { friendListState, dispatchFriendListState } }>
|
||||
<FriendListMessageHandler />
|
||||
{ isReady && createPortal(<FriendBarView />, document.getElementById('toolbar-friend-bar-container')) }
|
||||
{ isVisible &&
|
||||
<NitroCardView uniqueKey="friend-list" className="nitro-friend-list">
|
||||
<NitroCardHeaderView headerText={ LocalizeText('friendlist.friends') } onCloseClick={ event => setIsVisible(false) } />
|
||||
<NitroCardContentView>
|
||||
<div className="text-black fw-bold">{ LocalizeText('friendlist.search.friendscaption') }</div>
|
||||
<FriendListFriendsView online={ true } />
|
||||
<div className="text-black fw-bold">{ LocalizeText('friendlist.search.friendscaption') }</div>
|
||||
<FriendListFriendsView online={ true } />
|
||||
<div className="text-black fw-bold">{ LocalizeText('friendlist.friends.offlinecaption') }</div>
|
||||
<FriendListFriendsView online={ false } />
|
||||
<NitroCardView className="nitro-friend-list">
|
||||
<NitroCardHeaderView headerText={ LocalizeText('friendlist.friends') } onCloseClick={ () => setIsVisible(false) } />
|
||||
<NitroCardContentView className="p-0">
|
||||
<NitroCardTabsView>
|
||||
{ TABS.map((tab, index) =>
|
||||
{
|
||||
return (<NitroCardTabsItemView key={ index } isActive={ currentTab === index } onClick={ () => setCurrentTab(index) }>
|
||||
{ LocalizeText(tab) }
|
||||
</NitroCardTabsItemView>);
|
||||
}) }
|
||||
</NitroCardTabsView>
|
||||
<div className="text-black">
|
||||
{ currentTab === 0 && <NitroCardAccordionView>
|
||||
<NitroCardAccordionItemView headerText={ LocalizeText('friendlist.friends') + ` (${onlineFriends.length})` }>
|
||||
<FriendListFriendsView list={ onlineFriends } />
|
||||
</NitroCardAccordionItemView>
|
||||
<NitroCardAccordionItemView headerText={ LocalizeText('friendlist.friends.offlinecaption') + ` (${offlineFriends.length})` }>
|
||||
<FriendListFriendsView list={ offlineFriends } />
|
||||
</NitroCardAccordionItemView>
|
||||
{ requests.length > 0 && <NitroCardAccordionItemView headerText={ LocalizeText('friendlist.tab.friendrequests') + ` (${requests.length})` }>
|
||||
<FriendListRequestsView list={ requests } />
|
||||
</NitroCardAccordionItemView> }
|
||||
</NitroCardAccordionView> }
|
||||
</div>
|
||||
</NitroCardContentView>
|
||||
</NitroCardView> }
|
||||
</FriendListContextProvider>
|
||||
|
@ -1,5 +1,12 @@
|
||||
import { FriendParser } from '@nitrots/nitro-renderer';
|
||||
|
||||
export class MessengerFriend
|
||||
{
|
||||
public static RELATIONSHIP_NONE: number = 0;
|
||||
public static RELATIONSHIP_HEART: number = 1;
|
||||
public static RELATIONSHIP_SMILE: number = 2;
|
||||
public static RELATIONSHIP_BOBBA: number = 3;
|
||||
|
||||
public id: number = -1;
|
||||
public name: string = null;
|
||||
public gender: number = 0;
|
||||
@ -15,4 +22,22 @@ export class MessengerFriend
|
||||
public pocketHabboUser: boolean = false;
|
||||
public relationshipStatus: number = -1;
|
||||
public unread: number = 0;
|
||||
|
||||
public populate(parser: FriendParser): void
|
||||
{
|
||||
this.id = parser.id;
|
||||
this.name = parser.name;
|
||||
this.gender = parser.gender;
|
||||
this.online = parser.online;
|
||||
this.followingAllowed = parser.followingAllowed;
|
||||
this.figure = parser.figure;
|
||||
this.categoryId = parser.categoryId;
|
||||
this.motto = parser.motto;
|
||||
this.realName = parser.realName;
|
||||
this.lastAccess = parser.lastAccess;
|
||||
this.persistedMessageUser = parser.persistedMessageUser;
|
||||
this.vipMember = parser.vipMember;
|
||||
this.pocketHabboUser = parser.pocketHabboUser;
|
||||
this.relationshipStatus = parser.relationshipStatus;
|
||||
}
|
||||
}
|
||||
|
41
src/views/friend-list/common/MessengerRequest.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import { FriendRequestData } from '@nitrots/nitro-renderer';
|
||||
|
||||
export class MessengerRequest
|
||||
{
|
||||
private _id: number;
|
||||
private _name: string;
|
||||
private _requesterUserId: number;
|
||||
private _figureString: string;
|
||||
|
||||
public populate(data: FriendRequestData): boolean
|
||||
{
|
||||
if(!data) return false;
|
||||
|
||||
this._id = data.requestId;
|
||||
this._name = data.requesterName;
|
||||
this._figureString = data.figureString;
|
||||
this._requesterUserId = data.requesterUserId;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public get id(): number
|
||||
{
|
||||
return this._id;
|
||||
}
|
||||
|
||||
public get name(): string
|
||||
{
|
||||
return this._name;
|
||||
}
|
||||
|
||||
public get requesterUserId(): number
|
||||
{
|
||||
return this._requesterUserId;
|
||||
}
|
||||
|
||||
public get figureString(): string
|
||||
{
|
||||
return this._figureString;
|
||||
}
|
||||
}
|
@ -1,12 +1,21 @@
|
||||
import { FriendListUpdateParser, FriendParser } from '@nitrots/nitro-renderer';
|
||||
import { FriendListUpdateParser, FriendParser, FriendRequestData } from '@nitrots/nitro-renderer';
|
||||
import { Reducer } from 'react';
|
||||
import { MessengerFriend } from '../common/MessengerFriend';
|
||||
import { MessengerRequest } from '../common/MessengerRequest';
|
||||
import { MessengerSettings } from '../common/MessengerSettings';
|
||||
|
||||
function compareName(a, b)
|
||||
{
|
||||
if( a.name < b.name ) return -1;
|
||||
if( a.name > b.name ) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
export interface IFriendListState
|
||||
{
|
||||
settings: MessengerSettings;
|
||||
friends: MessengerFriend[];
|
||||
requests: MessengerRequest[];
|
||||
}
|
||||
|
||||
export interface IFriendListAction
|
||||
@ -16,6 +25,7 @@ export interface IFriendListAction
|
||||
settings?: MessengerSettings;
|
||||
fragment?: FriendParser[];
|
||||
update?: FriendListUpdateParser;
|
||||
requests?: FriendRequestData[];
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,11 +35,13 @@ export class FriendListActions
|
||||
public static UPDATE_SETTINGS: string = 'FLA_UPDATE_SETTINGS';
|
||||
public static PROCESS_FRAGMENT: string = 'FLA_PROCESS_FRAGMENT';
|
||||
public static PROCESS_UPDATE: string = 'FLA_PROCESS_UPDATE';
|
||||
public static PROCESS_REQUESTS: string = 'FLA_PROCESS_REQUESTS';
|
||||
}
|
||||
|
||||
export const initialFriendList: IFriendListState = {
|
||||
settings: null,
|
||||
friends: []
|
||||
friends: [],
|
||||
requests: []
|
||||
}
|
||||
|
||||
export const FriendListReducer: Reducer<IFriendListState, IFriendListAction> = (state, action) =>
|
||||
@ -69,6 +81,8 @@ export const FriendListReducer: Reducer<IFriendListState, IFriendListAction> = (
|
||||
else friends.push(newFriend);
|
||||
}
|
||||
|
||||
friends.sort(compareName);
|
||||
|
||||
return { ...state, friends };
|
||||
}
|
||||
case FriendListActions.PROCESS_UPDATE: {
|
||||
@ -80,22 +94,9 @@ export const FriendListReducer: Reducer<IFriendListState, IFriendListAction> = (
|
||||
const processUpdate = (friend: FriendParser) =>
|
||||
{
|
||||
const index = friends.findIndex(existingFriend => (existingFriend.id === friend.id));
|
||||
const newFriend = new MessengerFriend();
|
||||
|
||||
newFriend.id = friend.id;
|
||||
newFriend.name = friend.name;
|
||||
newFriend.gender = friend.gender;
|
||||
newFriend.online = friend.online;
|
||||
newFriend.followingAllowed = friend.followingAllowed;
|
||||
newFriend.figure = friend.figure;
|
||||
newFriend.categoryId = friend.categoryId;
|
||||
newFriend.motto = friend.motto;
|
||||
newFriend.realName = friend.realName;
|
||||
newFriend.lastAccess = friend.lastAccess;
|
||||
newFriend.persistedMessageUser = friend.persistedMessageUser;
|
||||
newFriend.vipMember = friend.vipMember;
|
||||
newFriend.pocketHabboUser = friend.pocketHabboUser;
|
||||
newFriend.relationshipStatus = friend.relationshipStatus;
|
||||
const newFriend = new MessengerFriend();
|
||||
newFriend.populate(friend);
|
||||
|
||||
if(index > -1) friends[index] = newFriend;
|
||||
else friends.unshift(newFriend);
|
||||
@ -112,9 +113,26 @@ export const FriendListReducer: Reducer<IFriendListState, IFriendListAction> = (
|
||||
if(index > -1) friends.splice(index);
|
||||
}
|
||||
}
|
||||
|
||||
friends.sort(compareName);
|
||||
|
||||
return { ...state, friends };
|
||||
}
|
||||
case FriendListActions.PROCESS_REQUESTS: {
|
||||
const newRequests = (action.payload.requests || null);
|
||||
let requests = [ ...state.requests ];
|
||||
|
||||
for(const request of newRequests)
|
||||
{
|
||||
const newRequest = new MessengerRequest();
|
||||
newRequest.populate(request);
|
||||
requests.push(newRequest);
|
||||
}
|
||||
|
||||
requests.sort(compareName);
|
||||
|
||||
return { ...state, requests };
|
||||
}
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
@ -1,13 +1,63 @@
|
||||
import { FC } from 'react';
|
||||
import { FollowFriendComposer, SetRelationshipStatusComposer } from '@nitrots/nitro-renderer';
|
||||
import { FC, useCallback, useState } from 'react';
|
||||
import { LocalizeText } from '../../../../api';
|
||||
import { SendMessageHook } from '../../../../hooks';
|
||||
import { UserProfileIconView } from '../../../shared/user-profile-icon/UserProfileIconView';
|
||||
import { MessengerFriend } from '../../common/MessengerFriend';
|
||||
import { FriendListFriendsItemViewProps } from './FriendListFriendsItemView.types';
|
||||
|
||||
export const FriendListFriendsItemView: FC<FriendListFriendsItemViewProps> = props =>
|
||||
{
|
||||
const { friend = null } = props;
|
||||
|
||||
const [ isExpanded, setIsExpanded ] = useState<boolean>(false);
|
||||
|
||||
const followFriend = useCallback(() =>
|
||||
{
|
||||
if(!friend) return;
|
||||
|
||||
SendMessageHook(new FollowFriendComposer(friend.id));
|
||||
}, [ friend ]);
|
||||
|
||||
const getCurrentRelationshipName = useCallback(() =>
|
||||
{
|
||||
if(!friend) return 'none';
|
||||
|
||||
switch(friend.relationshipStatus)
|
||||
{
|
||||
case MessengerFriend.RELATIONSHIP_HEART: return 'heart';
|
||||
case MessengerFriend.RELATIONSHIP_SMILE: return 'smile';
|
||||
case MessengerFriend.RELATIONSHIP_BOBBA: return 'bobba';
|
||||
default: return 'none';
|
||||
}
|
||||
}, [ friend ]);
|
||||
|
||||
const updateRelationship = useCallback((type: number) =>
|
||||
{
|
||||
if(type !== friend.relationshipStatus) SendMessageHook(new SetRelationshipStatusComposer(friend.id, type));
|
||||
|
||||
setIsExpanded(false);
|
||||
}, [ friend ]);
|
||||
|
||||
if(!friend) return null;
|
||||
|
||||
return (
|
||||
<div className="d-flex">
|
||||
<div className="text-black">{ friend.name }</div>
|
||||
<div className="px-2 py-1 d-flex gap-1 align-items-center">
|
||||
<UserProfileIconView userId={ friend.id } />
|
||||
<div>{ friend.name }</div>
|
||||
<div className="ms-auto d-flex align-items-center gap-1">
|
||||
{ !isExpanded && <>
|
||||
{ friend.followingAllowed && <i onClick={ followFriend } className="icon icon-friendlist-follow cursor-pointer" title={ LocalizeText('friendlist.tip.follow') } /> }
|
||||
{ friend.online && <i className="icon icon-friendlist-chat cursor-pointer" title={ LocalizeText('friendlist.tip.im') } /> }
|
||||
<i className={ 'icon cursor-pointer icon-relationship-' + getCurrentRelationshipName() } onClick={ () => setIsExpanded(true) } title={ LocalizeText('infostand.link.relationship') } />
|
||||
</> }
|
||||
{ isExpanded && <>
|
||||
<i className="icon icon-relationship-heart cursor-pointer" onClick={ () => updateRelationship(MessengerFriend.RELATIONSHIP_HEART) } />
|
||||
<i className="icon icon-relationship-smile cursor-pointer" onClick={ () => updateRelationship(MessengerFriend.RELATIONSHIP_SMILE) } />
|
||||
<i className="icon icon-relationship-bobba cursor-pointer" onClick={ () => updateRelationship(MessengerFriend.RELATIONSHIP_BOBBA) } />
|
||||
<i className="icon icon-relationship-none cursor-pointer" onClick={ () => updateRelationship(MessengerFriend.RELATIONSHIP_NONE) } />
|
||||
</> }
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -1,35 +1,17 @@
|
||||
import { FC, useMemo } from 'react';
|
||||
import { useFriendListContext } from '../../context/FriendListContext';
|
||||
import { FC } from 'react';
|
||||
import { FriendListFriendsItemView } from '../friends-item/FriendListFriendsItemView';
|
||||
import { FriendListFriendsViewProps } from './FriendListFriendsView.types';
|
||||
|
||||
export const FriendListFriendsView: FC<FriendListFriendsViewProps> = props =>
|
||||
{
|
||||
const { online = true } = props;
|
||||
const { friendListState = null } = useFriendListContext();
|
||||
const { friends = null } = friendListState;
|
||||
const { list = null } = props;
|
||||
|
||||
const getFriendElements = useMemo(() =>
|
||||
{
|
||||
if(!friends || !friends.length) return null;
|
||||
if(!list) return null;
|
||||
|
||||
const elements: JSX.Element[] = [];
|
||||
|
||||
for(const friend of friends)
|
||||
return (<>
|
||||
{ list.map((friend, index) =>
|
||||
{
|
||||
if(!friend || (friend.online !== online)) continue;
|
||||
|
||||
elements.push(<FriendListFriendsItemView key={ friend.id } friend={ friend } />)
|
||||
}
|
||||
|
||||
console.log(elements);
|
||||
|
||||
return elements;
|
||||
}, [ friends, online ]);
|
||||
|
||||
return (
|
||||
<div className="d-flex flex-column">
|
||||
{ getFriendElements }
|
||||
</div>
|
||||
);
|
||||
return <FriendListFriendsItemView key={ index } friend={ friend } />
|
||||
}) }
|
||||
</>);
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { MessengerFriend } from './../../common/MessengerFriend';
|
||||
export interface FriendListFriendsViewProps
|
||||
{
|
||||
online?: boolean;
|
||||
list: MessengerFriend[];
|
||||
}
|
||||
|
@ -0,0 +1,37 @@
|
||||
import { AcceptFriendComposer, DeclineFriendComposer } 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 { FriendListRequestsItemViewProps } from './FriendListRequestsItemView.types';
|
||||
|
||||
export const FriendListRequestsItemView: FC<FriendListRequestsItemViewProps> = props =>
|
||||
{
|
||||
const { request = null } = props;
|
||||
|
||||
const accept = useCallback(() =>
|
||||
{
|
||||
if(!request) return;
|
||||
|
||||
SendMessageHook(new AcceptFriendComposer(request.id));
|
||||
}, [ request ]);
|
||||
|
||||
const decline = useCallback(() =>
|
||||
{
|
||||
if(!request) return;
|
||||
|
||||
SendMessageHook(new DeclineFriendComposer(false, request.id));
|
||||
}, [ request ]);
|
||||
|
||||
if(!request) return null;
|
||||
|
||||
return (
|
||||
<div className="px-2 py-1 d-flex gap-1 align-items-center">
|
||||
<UserProfileIconView userId={ request.id } />
|
||||
<div>{ request.name }</div>
|
||||
<div className="ms-auto d-flex align-items-center gap-1">
|
||||
<i className="icon icon-accept cursor-pointer" onClick={ accept } />
|
||||
<i className="icon icon-deny cursor-pointer" onClick={ decline } />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
@ -0,0 +1,6 @@
|
||||
import { MessengerRequest } from './../../common/MessengerRequest';
|
||||
|
||||
export interface FriendListRequestsItemViewProps
|
||||
{
|
||||
request: MessengerRequest;
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
import { FC } from 'react';
|
||||
import { FriendListRequestsItemView } from '../requests-item/FriendListRequestsItemView';
|
||||
import { FriendListRequestsViewProps } from './FriendListRequestsView.types';
|
||||
|
||||
export const FriendListRequestsView: FC<FriendListRequestsViewProps> = props =>
|
||||
{
|
||||
const { list = null } = props;
|
||||
|
||||
if(!list) return null;
|
||||
|
||||
return (<>
|
||||
{ list.map((request, index) =>
|
||||
{
|
||||
return <FriendListRequestsItemView key={ index } request={ request } />
|
||||
}) }
|
||||
</>);
|
||||
};
|
@ -0,0 +1,6 @@
|
||||
import { MessengerRequest } from './../../common/MessengerRequest';
|
||||
|
||||
export interface FriendListRequestsViewProps
|
||||
{
|
||||
list: MessengerRequest[];
|
||||
}
|
@ -177,10 +177,10 @@ export const GroupMembersView: FC<GroupMembersViewProps> = props =>
|
||||
<i className={ 'icon icon-group-small-' + classNames({ 'owner': member.rank === GroupRank.OWNER, 'admin': member.rank === GroupRank.ADMIN, 'not-admin': member.rank === GroupRank.MEMBER, 'cursor-pointer': pageData.admin }) } title={ LocalizeText(getRankDescription(member)) } onClick={ () => toggleAdmin(member) } />
|
||||
</div>
|
||||
{ member.rank === GroupRank.REQUESTED && <div className="d-flex align-items-center">
|
||||
<i className="icon cursor-pointer icon-group-accept-member" title={ LocalizeText('group.members.accept') } onClick={ () => acceptMembership(member) } />
|
||||
<i className="icon cursor-pointer icon-accept" title={ LocalizeText('group.members.accept') } onClick={ () => acceptMembership(member) } />
|
||||
</div> }
|
||||
{ member.rank !== GroupRank.OWNER && pageData.admin && member.id !== GetSessionDataManager().userId &&<div className="d-flex align-items-center mt-1">
|
||||
<i className="icon cursor-pointer icon-group-remove-member" title={ LocalizeText(member.rank === GroupRank.REQUESTED ? 'group.members.reject' : 'group.members.kick') } onClick={ () => removeMemberOrDeclineMembership(member) } />
|
||||
<i className="icon cursor-pointer icon-deny" title={ LocalizeText(member.rank === GroupRank.REQUESTED ? 'group.members.reject' : 'group.members.kick') } onClick={ () => removeMemberOrDeclineMembership(member) } />
|
||||
</div> }
|
||||
</div>
|
||||
</div>
|
||||
|