mirror of
https://github.com/billsonnn/nitro-react.git
synced 2025-02-20 02:32:37 +01:00
Recode friends/messenger state
This commit is contained in:
parent
95621e95eb
commit
712d8242ce
11
src/api/friends/GetGroupChatData.ts
Normal file
11
src/api/friends/GetGroupChatData.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { IGroupChatData } from './IGroupChatData';
|
||||||
|
|
||||||
|
export const GetGroupChatData = (extraData: string) =>
|
||||||
|
{
|
||||||
|
const splitData = extraData.split('/');
|
||||||
|
const username = splitData[0];
|
||||||
|
const figure = splitData[1];
|
||||||
|
const userId = parseInt(splitData[2]);
|
||||||
|
|
||||||
|
return ({ username: username, figure: figure, userId: userId } as IGroupChatData);
|
||||||
|
}
|
6
src/api/friends/IGroupChatData.ts
Normal file
6
src/api/friends/IGroupChatData.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
export interface IGroupChatData
|
||||||
|
{
|
||||||
|
username: string;
|
||||||
|
figure: string;
|
||||||
|
userId: number;
|
||||||
|
}
|
@ -2,7 +2,7 @@ import { FriendParser } from '@nitrots/nitro-renderer';
|
|||||||
|
|
||||||
export class MessengerFriend
|
export class MessengerFriend
|
||||||
{
|
{
|
||||||
public static RELATIONSHIP_NONE: number = 0;
|
public static RELATIONSHIP_NONE: number = 0;
|
||||||
public static RELATIONSHIP_HEART: number = 1;
|
public static RELATIONSHIP_HEART: number = 1;
|
||||||
public static RELATIONSHIP_SMILE: number = 2;
|
public static RELATIONSHIP_SMILE: number = 2;
|
||||||
public static RELATIONSHIP_BOBBA: number = 3;
|
public static RELATIONSHIP_BOBBA: number = 3;
|
6
src/api/friends/MessengerIconState.ts
Normal file
6
src/api/friends/MessengerIconState.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
export class MessengerIconState
|
||||||
|
{
|
||||||
|
public static HIDDEN: number = 0;
|
||||||
|
public static SHOW: number = 1;
|
||||||
|
public static UNREAD: number = 2;
|
||||||
|
}
|
@ -11,10 +11,10 @@ export class MessengerRequest
|
|||||||
{
|
{
|
||||||
if(!data) return false;
|
if(!data) return false;
|
||||||
|
|
||||||
this._id = data.requestId;
|
this._id = data.requestId;
|
||||||
this._name = data.requesterName;
|
this._name = data.requesterName;
|
||||||
this._figureString = data.figureString;
|
this._figureString = data.figureString;
|
||||||
this._requesterUserId = data.requesterUserId;
|
this._requesterUserId = data.requesterUserId;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
@ -1,14 +1,16 @@
|
|||||||
import { LocalizeText } from '../../../api';
|
import { LocalizeText } from '../utils';
|
||||||
|
import { GetGroupChatData } from './GetGroupChatData';
|
||||||
import { GroupType } from './GroupType';
|
import { GroupType } from './GroupType';
|
||||||
import { MessengerFriend } from './MessengerFriend';
|
import { MessengerFriend } from './MessengerFriend';
|
||||||
import { MessengerThreadChat } from './MessengerThreadChat';
|
import { MessengerThreadChat } from './MessengerThreadChat';
|
||||||
import { MessengerThreadChatGroup } from './MessengerThreadChatGroup';
|
import { MessengerThreadChatGroup } from './MessengerThreadChatGroup';
|
||||||
import { getGroupChatData } from './Utils';
|
|
||||||
|
|
||||||
export class MessengerThread
|
export class MessengerThread
|
||||||
{
|
{
|
||||||
public static MESSAGE_RECEIVED: string = 'MT_MESSAGE_RECEIVED';
|
public static MESSAGE_RECEIVED: string = 'MT_MESSAGE_RECEIVED';
|
||||||
|
public static THREAD_ID: number = 0;
|
||||||
|
|
||||||
|
private _threadId: number;
|
||||||
private _participant: MessengerFriend;
|
private _participant: MessengerFriend;
|
||||||
private _groups: MessengerThreadChatGroup[];
|
private _groups: MessengerThreadChatGroup[];
|
||||||
private _lastUpdated: Date;
|
private _lastUpdated: Date;
|
||||||
@ -16,6 +18,7 @@ export class MessengerThread
|
|||||||
|
|
||||||
constructor(participant: MessengerFriend, isNew: boolean = true)
|
constructor(participant: MessengerFriend, isNew: boolean = true)
|
||||||
{
|
{
|
||||||
|
this._threadId = ++MessengerThread.THREAD_ID;
|
||||||
this._participant = participant;
|
this._participant = participant;
|
||||||
this._groups = [];
|
this._groups = [];
|
||||||
this._lastUpdated = new Date();
|
this._lastUpdated = new Date();
|
||||||
@ -32,7 +35,7 @@ export class MessengerThread
|
|||||||
public addMessage(senderId: number, message: string, secondsSinceSent: number = 0, extraData: string = null, type: number = 0): MessengerThreadChat
|
public addMessage(senderId: number, message: string, secondsSinceSent: number = 0, extraData: string = null, type: number = 0): MessengerThreadChat
|
||||||
{
|
{
|
||||||
const isGroupChat = (senderId < 0 && extraData);
|
const isGroupChat = (senderId < 0 && extraData);
|
||||||
const userId = isGroupChat ? getGroupChatData(extraData).userId : senderId;
|
const userId = isGroupChat ? GetGroupChatData(extraData).userId : senderId;
|
||||||
|
|
||||||
const group = this.getLastGroup(userId);
|
const group = this.getLastGroup(userId);
|
||||||
|
|
||||||
@ -45,6 +48,7 @@ export class MessengerThread
|
|||||||
group.addChat(chat);
|
group.addChat(chat);
|
||||||
|
|
||||||
this._lastUpdated = new Date();
|
this._lastUpdated = new Date();
|
||||||
|
|
||||||
this._unreadCount++;
|
this._unreadCount++;
|
||||||
|
|
||||||
return chat;
|
return chat;
|
||||||
@ -68,6 +72,11 @@ export class MessengerThread
|
|||||||
this._unreadCount = 0;
|
this._unreadCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get threadId(): number
|
||||||
|
{
|
||||||
|
return this._threadId;
|
||||||
|
}
|
||||||
|
|
||||||
public get participant(): MessengerFriend
|
public get participant(): MessengerFriend
|
||||||
{
|
{
|
||||||
return this._participant;
|
return this._participant;
|
||||||
@ -90,6 +99,6 @@ export class MessengerThread
|
|||||||
|
|
||||||
public get unread(): boolean
|
public get unread(): boolean
|
||||||
{
|
{
|
||||||
return this._unreadCount > 0;
|
return (this._unreadCount > 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,6 +2,6 @@ import { CreateLinkEvent } from '..';
|
|||||||
|
|
||||||
export function OpenMessengerChat(friendId: number = 0): void
|
export function OpenMessengerChat(friendId: number = 0): void
|
||||||
{
|
{
|
||||||
if(friendId === 0) CreateLinkEvent('friends/messenger/open');
|
if(friendId === 0) CreateLinkEvent('friends-messenger/open');
|
||||||
else CreateLinkEvent(`friends/messenger/${friendId}`);
|
else CreateLinkEvent(`friends-messenger/${friendId}`);
|
||||||
}
|
}
|
||||||
|
@ -1 +1,11 @@
|
|||||||
|
export * from './GetGroupChatData';
|
||||||
|
export * from './GroupType';
|
||||||
|
export * from './IGroupChatData';
|
||||||
|
export * from './MessengerFriend';
|
||||||
|
export * from './MessengerIconState';
|
||||||
|
export * from './MessengerRequest';
|
||||||
|
export * from './MessengerSettings';
|
||||||
|
export * from './MessengerThread';
|
||||||
|
export * from './MessengerThreadChat';
|
||||||
|
export * from './MessengerThreadChatGroup';
|
||||||
export * from './OpenMessengerChat';
|
export * from './OpenMessengerChat';
|
||||||
|
@ -1,35 +0,0 @@
|
|||||||
import { RoomWidgetUpdateEvent } from './RoomWidgetUpdateEvent';
|
|
||||||
|
|
||||||
export class RoomWidgetUpdateFriendRequestEvent extends RoomWidgetUpdateEvent
|
|
||||||
{
|
|
||||||
public static SHOW_FRIEND_REQUEST: string = 'RWFRUE_SHOW_FRIEND_REQUEST';
|
|
||||||
public static HIDE_FRIEND_REQUEST: string = 'RWFRUE_HIDE_FRIEND_REQUEST';
|
|
||||||
|
|
||||||
private _requestId: number;
|
|
||||||
private _userId: number;
|
|
||||||
private _userName: string;
|
|
||||||
|
|
||||||
constructor(type: string, requestId: number = -1, userId: number = -1, userName: string = null)
|
|
||||||
{
|
|
||||||
super(type);
|
|
||||||
|
|
||||||
this._requestId = requestId;
|
|
||||||
this._userId = userId;
|
|
||||||
this._userName = userName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get requestId(): number
|
|
||||||
{
|
|
||||||
return this._requestId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get userId(): number
|
|
||||||
{
|
|
||||||
return this._userId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get userName(): string
|
|
||||||
{
|
|
||||||
return this._userName;
|
|
||||||
}
|
|
||||||
}
|
|
@ -24,12 +24,10 @@ export class RoomWidgetUpdateInfostandUserEvent extends RoomWidgetUpdateInfostan
|
|||||||
public carryItem: number = 0;
|
public carryItem: number = 0;
|
||||||
public roomIndex: number = 0;
|
public roomIndex: number = 0;
|
||||||
public isSpectatorMode: boolean = false;
|
public isSpectatorMode: boolean = false;
|
||||||
public realName: string = '';
|
|
||||||
public allowNameChange: boolean = false;
|
public allowNameChange: boolean = false;
|
||||||
public amIOwner: boolean = false;
|
public amIOwner: boolean = false;
|
||||||
public amIAnyRoomController: boolean = false;
|
public amIAnyRoomController: boolean = false;
|
||||||
public roomControllerLevel: number = 0;
|
public roomControllerLevel: number = 0;
|
||||||
public canBeAskedAsFriend: boolean = false;
|
|
||||||
public canBeKicked: boolean = false;
|
public canBeKicked: boolean = false;
|
||||||
public canBeBanned: boolean = false;
|
public canBeBanned: boolean = false;
|
||||||
public canBeMuted: boolean = false;
|
public canBeMuted: boolean = false;
|
||||||
@ -39,7 +37,6 @@ export class RoomWidgetUpdateInfostandUserEvent extends RoomWidgetUpdateInfostan
|
|||||||
public canTrade: boolean = false;
|
public canTrade: boolean = false;
|
||||||
public canTradeReason: number = 0;
|
public canTradeReason: number = 0;
|
||||||
public targetRoomControllerLevel: number = 0;
|
public targetRoomControllerLevel: number = 0;
|
||||||
public isFriend: boolean = false;
|
|
||||||
public isAmbassador: boolean = false;
|
public isAmbassador: boolean = false;
|
||||||
|
|
||||||
public get isOwnUser(): boolean
|
public get isOwnUser(): boolean
|
||||||
|
@ -2,15 +2,15 @@ import { RoomWidgetUpdateEvent } from './RoomWidgetUpdateEvent';
|
|||||||
|
|
||||||
export class RoomWidgetUpdateRoomObjectEvent extends RoomWidgetUpdateEvent
|
export class RoomWidgetUpdateRoomObjectEvent extends RoomWidgetUpdateEvent
|
||||||
{
|
{
|
||||||
public static OBJECT_SELECTED: string = 'RWUROE_OBJECT_SELECTED';
|
public static OBJECT_SELECTED: string = 'RWUROE_OBJECT_SELECTED';
|
||||||
public static OBJECT_DESELECTED: string = 'RWUROE_OBJECT_DESELECTED';
|
public static OBJECT_DESELECTED: string = 'RWUROE_OBJECT_DESELECTED';
|
||||||
public static USER_REMOVED: string = 'RWUROE_USER_REMOVED';
|
public static USER_REMOVED: string = 'RWUROE_USER_REMOVED';
|
||||||
public static FURNI_REMOVED: string = 'RWUROE_FURNI_REMOVED';
|
public static FURNI_REMOVED: string = 'RWUROE_FURNI_REMOVED';
|
||||||
public static FURNI_ADDED: string = 'RWUROE_FURNI_ADDED';
|
public static FURNI_ADDED: string = 'RWUROE_FURNI_ADDED';
|
||||||
public static USER_ADDED: string = 'RWUROE_USER_ADDED';
|
public static USER_ADDED: string = 'RWUROE_USER_ADDED';
|
||||||
public static OBJECT_ROLL_OVER: string = 'RWUROE_OBJECT_ROLL_OVER';
|
public static OBJECT_ROLL_OVER: string = 'RWUROE_OBJECT_ROLL_OVER';
|
||||||
public static OBJECT_ROLL_OUT: string = 'RWUROE_OBJECT_ROLL_OUT';
|
public static OBJECT_ROLL_OUT: string = 'RWUROE_OBJECT_ROLL_OUT';
|
||||||
public static OBJECT_REQUEST_MANIPULATION: string = 'RWUROE_OBJECT_REQUEST_MANIPULATION';
|
public static OBJECT_REQUEST_MANIPULATION: string = 'RWUROE_OBJECT_REQUEST_MANIPULATION';
|
||||||
|
|
||||||
private _id: number;
|
private _id: number;
|
||||||
private _category: number;
|
private _category: number;
|
||||||
|
@ -18,7 +18,6 @@ export * from './RoomWidgetUpdateDimmerEvent';
|
|||||||
export * from './RoomWidgetUpdateDimmerStateEvent';
|
export * from './RoomWidgetUpdateDimmerStateEvent';
|
||||||
export * from './RoomWidgetUpdateEvent';
|
export * from './RoomWidgetUpdateEvent';
|
||||||
export * from './RoomWidgetUpdateExternalImageEvent';
|
export * from './RoomWidgetUpdateExternalImageEvent';
|
||||||
export * from './RoomWidgetUpdateFriendRequestEvent';
|
|
||||||
export * from './RoomWidgetUpdateInfostandEvent';
|
export * from './RoomWidgetUpdateInfostandEvent';
|
||||||
export * from './RoomWidgetUpdateInfostandFurniEvent';
|
export * from './RoomWidgetUpdateInfostandFurniEvent';
|
||||||
export * from './RoomWidgetUpdateInfostandPetEvent';
|
export * from './RoomWidgetUpdateInfostandPetEvent';
|
||||||
|
@ -1,65 +0,0 @@
|
|||||||
import { NitroEvent, RoomSessionFriendRequestEvent, RoomWidgetEnum } from '@nitrots/nitro-renderer';
|
|
||||||
import { FriendRequestEvent, FriendsAcceptFriendRequestEvent, FriendsDeclineFriendRequestEvent } from '../../../../../events';
|
|
||||||
import { DispatchUiEvent } from '../../../../../hooks';
|
|
||||||
import { RoomWidgetUpdateEvent, RoomWidgetUpdateFriendRequestEvent } from '../events';
|
|
||||||
import { RoomWidgetFriendRequestMessage, RoomWidgetMessage } from '../messages';
|
|
||||||
import { RoomWidgetHandler } from './RoomWidgetHandler';
|
|
||||||
|
|
||||||
export class FriendRequestHandler extends RoomWidgetHandler
|
|
||||||
{
|
|
||||||
public processEvent(event: NitroEvent): void
|
|
||||||
{
|
|
||||||
const friendRequestEvent = (event as RoomSessionFriendRequestEvent);
|
|
||||||
|
|
||||||
switch(event.type)
|
|
||||||
{
|
|
||||||
case RoomSessionFriendRequestEvent.RSFRE_FRIEND_REQUEST:
|
|
||||||
this.container.eventDispatcher.dispatchEvent(new RoomWidgetUpdateFriendRequestEvent(RoomWidgetUpdateFriendRequestEvent.SHOW_FRIEND_REQUEST, friendRequestEvent.requestId, friendRequestEvent.userId, friendRequestEvent.userName));
|
|
||||||
return;
|
|
||||||
case FriendRequestEvent.ACCEPTED:
|
|
||||||
case FriendRequestEvent.DECLINED:
|
|
||||||
this.container.eventDispatcher.dispatchEvent(new RoomWidgetUpdateFriendRequestEvent(RoomWidgetUpdateFriendRequestEvent.HIDE_FRIEND_REQUEST, friendRequestEvent.requestId));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public processWidgetMessage(message: RoomWidgetMessage): RoomWidgetUpdateEvent
|
|
||||||
{
|
|
||||||
const friendMessage = (message as RoomWidgetFriendRequestMessage);
|
|
||||||
|
|
||||||
switch(message.type)
|
|
||||||
{
|
|
||||||
case RoomWidgetFriendRequestMessage.ACCEPT:
|
|
||||||
DispatchUiEvent(new FriendsAcceptFriendRequestEvent(friendMessage.requestId));
|
|
||||||
break;
|
|
||||||
case RoomWidgetFriendRequestMessage.DECLINE:
|
|
||||||
DispatchUiEvent(new FriendsDeclineFriendRequestEvent(friendMessage.requestId));
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get type(): string
|
|
||||||
{
|
|
||||||
return RoomWidgetEnum.FRIEND_REQUEST;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get eventTypes(): string[]
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
RoomSessionFriendRequestEvent.RSFRE_FRIEND_REQUEST,
|
|
||||||
FriendRequestEvent.ACCEPTED,
|
|
||||||
FriendRequestEvent.DECLINED
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public get messageTypes(): string[]
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
RoomWidgetFriendRequestMessage.ACCEPT,
|
|
||||||
RoomWidgetFriendRequestMessage.DECLINE
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +1,7 @@
|
|||||||
import { NitroEvent, RoomEngineUseProductEvent, RoomObjectCategory, RoomObjectType, RoomObjectVariable, RoomSessionDanceEvent, RoomSessionPetStatusUpdateEvent, RoomSessionUserDataUpdateEvent, RoomWidgetEnum, SetRelationshipStatusComposer } from '@nitrots/nitro-renderer';
|
import { NitroEvent, RoomEngineUseProductEvent, RoomObjectCategory, RoomObjectType, RoomObjectVariable, RoomSessionDanceEvent, RoomSessionPetStatusUpdateEvent, RoomSessionUserDataUpdateEvent, RoomWidgetEnum, SetRelationshipStatusComposer } from '@nitrots/nitro-renderer';
|
||||||
import { SendMessageComposer } from '../../..';
|
import { SendMessageComposer } from '../../..';
|
||||||
import { GetRoomEngine, GetSessionDataManager, IsOwnerOfFurniture } from '../../../..';
|
import { GetRoomEngine, GetSessionDataManager, IsOwnerOfFurniture } from '../../../..';
|
||||||
import { MessengerFriend } from '../../../../../components/friends/common/MessengerFriend';
|
import { MessengerFriend } from '../../../../friends/MessengerFriend';
|
||||||
import { FurniCategory } from '../../../../inventory/FurniCategory';
|
import { FurniCategory } from '../../../../inventory/FurniCategory';
|
||||||
import { RoomWidgetAvatarInfoEvent, RoomWidgetUpdateDanceStatusEvent, RoomWidgetUpdateEvent, RoomWidgetUpdateUserDataEvent, RoomWidgetUseProductBubbleEvent, UseProductItem } from '../events';
|
import { RoomWidgetAvatarInfoEvent, RoomWidgetUpdateDanceStatusEvent, RoomWidgetUpdateEvent, RoomWidgetUpdateUserDataEvent, RoomWidgetUseProductBubbleEvent, UseProductItem } from '../events';
|
||||||
import { RoomWidgetAvatarExpressionMessage, RoomWidgetChangePostureMessage, RoomWidgetDanceMessage, RoomWidgetMessage, RoomWidgetRoomObjectMessage, RoomWidgetUseProductMessage, RoomWidgetUserActionMessage } from '../messages';
|
import { RoomWidgetAvatarExpressionMessage, RoomWidgetChangePostureMessage, RoomWidgetDanceMessage, RoomWidgetMessage, RoomWidgetRoomObjectMessage, RoomWidgetUseProductMessage, RoomWidgetUserActionMessage } from '../messages';
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
import { IFurnitureData, NitroEvent, ObjectDataFactory, PetFigureData, PetRespectComposer, PetSupplementComposer, PetType, RoomControllerLevel, RoomModerationSettings, RoomObjectCategory, RoomObjectOperationType, RoomObjectType, RoomObjectVariable, RoomSessionFavoriteGroupUpdateEvent, RoomSessionPetInfoUpdateEvent, RoomSessionUserBadgesEvent, RoomSessionUserFigureUpdateEvent, RoomTradingLevelEnum, RoomUnitDropHandItemComposer, RoomUnitGiveHandItemComposer, RoomUnitGiveHandItemPetComposer, RoomUserData, RoomWidgetEnum, RoomWidgetEnumItemExtradataParameter, Vector3d } from '@nitrots/nitro-renderer';
|
import { IFurnitureData, NitroEvent, ObjectDataFactory, PetFigureData, PetRespectComposer, PetSupplementComposer, PetType, RoomControllerLevel, RoomModerationSettings, RoomObjectCategory, RoomObjectOperationType, RoomObjectType, RoomObjectVariable, RoomSessionFavoriteGroupUpdateEvent, RoomSessionPetInfoUpdateEvent, RoomSessionUserBadgesEvent, RoomSessionUserFigureUpdateEvent, RoomTradingLevelEnum, RoomUnitDropHandItemComposer, RoomUnitGiveHandItemComposer, RoomUnitGiveHandItemPetComposer, RoomUserData, RoomWidgetEnum, RoomWidgetEnumItemExtradataParameter, Vector3d } from '@nitrots/nitro-renderer';
|
||||||
import { SendMessageComposer } from '../../..';
|
import { SendMessageComposer } from '../../..';
|
||||||
import { GetNitroInstance, GetRoomEngine, GetSessionDataManager, IsOwnerOfFurniture } from '../../../..';
|
import { GetNitroInstance, GetRoomEngine, GetSessionDataManager, IsOwnerOfFurniture } from '../../../..';
|
||||||
import { FriendsHelper } from '../../../../../components/friends/common/FriendsHelper';
|
|
||||||
import { PetSupplementEnum } from '../../../../../components/room/widgets/avatar-info/common/PetSupplementEnum';
|
import { PetSupplementEnum } from '../../../../../components/room/widgets/avatar-info/common/PetSupplementEnum';
|
||||||
import { FriendsSendFriendRequestEvent, HelpReportUserEvent, InventoryTradeRequestEvent, WiredSelectObjectEvent } from '../../../../../events';
|
import { HelpReportUserEvent, InventoryTradeRequestEvent, WiredSelectObjectEvent } from '../../../../../events';
|
||||||
import { DispatchUiEvent } from '../../../../../hooks';
|
import { DispatchUiEvent } from '../../../../../hooks';
|
||||||
import { LocalizeText } from '../../../../utils/LocalizeText';
|
import { LocalizeText } from '../../../../utils/LocalizeText';
|
||||||
import { RoomWidgetObjectNameEvent, RoomWidgetUpdateChatInputContentEvent, RoomWidgetUpdateEvent, RoomWidgetUpdateInfostandFurniEvent, RoomWidgetUpdateInfostandPetEvent, RoomWidgetUpdateInfostandRentableBotEvent, RoomWidgetUpdateInfostandUserEvent } from '../events';
|
import { RoomWidgetObjectNameEvent, RoomWidgetUpdateChatInputContentEvent, RoomWidgetUpdateEvent, RoomWidgetUpdateInfostandFurniEvent, RoomWidgetUpdateInfostandPetEvent, RoomWidgetUpdateInfostandRentableBotEvent, RoomWidgetUpdateInfostandUserEvent } from '../events';
|
||||||
@ -81,9 +80,6 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler
|
|||||||
return this.processObjectNameMessage((message as RoomWidgetRoomObjectMessage));
|
return this.processObjectNameMessage((message as RoomWidgetRoomObjectMessage));
|
||||||
case RoomWidgetRoomObjectMessage.GET_OBJECT_INFO:
|
case RoomWidgetRoomObjectMessage.GET_OBJECT_INFO:
|
||||||
return this.processObjectInfoMessage((message as RoomWidgetRoomObjectMessage));
|
return this.processObjectInfoMessage((message as RoomWidgetRoomObjectMessage));
|
||||||
case RoomWidgetUserActionMessage.SEND_FRIEND_REQUEST:
|
|
||||||
DispatchUiEvent(new FriendsSendFriendRequestEvent(userData.webID, userData.name));
|
|
||||||
break;
|
|
||||||
case RoomWidgetUserActionMessage.RESPECT_USER:
|
case RoomWidgetUserActionMessage.RESPECT_USER:
|
||||||
GetSessionDataManager().giveRespect(userId);
|
GetSessionDataManager().giveRespect(userId);
|
||||||
break;
|
break;
|
||||||
@ -452,11 +448,7 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler
|
|||||||
|
|
||||||
if(roomObject) event.carryItem = (roomObject.model.getValue<number>(RoomObjectVariable.FIGURE_CARRY_OBJECT) || 0);
|
if(roomObject) event.carryItem = (roomObject.model.getValue<number>(RoomObjectVariable.FIGURE_CARRY_OBJECT) || 0);
|
||||||
|
|
||||||
if(eventType === RoomWidgetUpdateInfostandUserEvent.OWN_USER)
|
if(eventType === RoomWidgetUpdateInfostandUserEvent.OWN_USER) event.allowNameChange = GetSessionDataManager().canChangeName;
|
||||||
{
|
|
||||||
event.realName = GetSessionDataManager().realName;
|
|
||||||
event.allowNameChange = GetSessionDataManager().canChangeName;
|
|
||||||
}
|
|
||||||
|
|
||||||
event.amIOwner = this.container.roomSession.isRoomOwner;
|
event.amIOwner = this.container.roomSession.isRoomOwner;
|
||||||
event.isGuildRoom = this.container.roomSession.isGuildRoom;
|
event.isGuildRoom = this.container.roomSession.isGuildRoom;
|
||||||
@ -466,19 +458,6 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler
|
|||||||
|
|
||||||
if(eventType === RoomWidgetUpdateInfostandUserEvent.PEER)
|
if(eventType === RoomWidgetUpdateInfostandUserEvent.PEER)
|
||||||
{
|
{
|
||||||
event.canBeAskedAsFriend = FriendsHelper.canRequestFriend(userData.webID);
|
|
||||||
|
|
||||||
if(!event.canBeAskedAsFriend)
|
|
||||||
{
|
|
||||||
const friend = FriendsHelper.getFriend(userData.webID);
|
|
||||||
|
|
||||||
if(friend)
|
|
||||||
{
|
|
||||||
event.realName = friend.realName;
|
|
||||||
event.isFriend = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(roomObject)
|
if(roomObject)
|
||||||
{
|
{
|
||||||
const flatControl = roomObject.model.getValue<number>(RoomObjectVariable.FIGURE_FLAT_CONTROL);
|
const flatControl = roomObject.model.getValue<number>(RoomObjectVariable.FIGURE_FLAT_CONTROL);
|
||||||
@ -755,7 +734,6 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler
|
|||||||
return [
|
return [
|
||||||
RoomWidgetRoomObjectMessage.GET_OBJECT_INFO,
|
RoomWidgetRoomObjectMessage.GET_OBJECT_INFO,
|
||||||
RoomWidgetRoomObjectMessage.GET_OBJECT_NAME,
|
RoomWidgetRoomObjectMessage.GET_OBJECT_NAME,
|
||||||
RoomWidgetUserActionMessage.SEND_FRIEND_REQUEST,
|
|
||||||
RoomWidgetUserActionMessage.RESPECT_USER,
|
RoomWidgetUserActionMessage.RESPECT_USER,
|
||||||
RoomWidgetUserActionMessage.WHISPER_USER,
|
RoomWidgetUserActionMessage.WHISPER_USER,
|
||||||
RoomWidgetUserActionMessage.IGNORE_USER,
|
RoomWidgetUserActionMessage.IGNORE_USER,
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
export * from './DoorbellWidgetHandler';
|
export * from './DoorbellWidgetHandler';
|
||||||
export * from './FriendRequestHandler';
|
|
||||||
export * from './FurniChooserWidgetHandler';
|
export * from './FurniChooserWidgetHandler';
|
||||||
export * from './FurnitureContextMenuWidgetHandler';
|
export * from './FurnitureContextMenuWidgetHandler';
|
||||||
export * from './FurnitureCreditWidgetHandler';
|
export * from './FurnitureCreditWidgetHandler';
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
import { RoomWidgetMessage } from './RoomWidgetMessage';
|
|
||||||
|
|
||||||
export class RoomWidgetFriendRequestMessage extends RoomWidgetMessage
|
|
||||||
{
|
|
||||||
public static ACCEPT: string = 'RWFRM_ACCEPT';
|
|
||||||
public static DECLINE: string = 'RMFRM_DECLINE';
|
|
||||||
|
|
||||||
private _requestId: number;
|
|
||||||
|
|
||||||
constructor(type: string, requestId: number)
|
|
||||||
{
|
|
||||||
super(type);
|
|
||||||
|
|
||||||
this._requestId = requestId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get requestId(): number
|
|
||||||
{
|
|
||||||
return this._requestId;
|
|
||||||
}
|
|
||||||
}
|
|
@ -13,7 +13,6 @@ export class RoomWidgetUserActionMessage extends RoomWidgetMessage
|
|||||||
public static MUTE_USER_2MIN: string = 'RWUAM_MUTE_USER_2MIN';
|
public static MUTE_USER_2MIN: string = 'RWUAM_MUTE_USER_2MIN';
|
||||||
public static MUTE_USER_5MIN: string = 'RWUAM_MUTE_USER_5MIN';
|
public static MUTE_USER_5MIN: string = 'RWUAM_MUTE_USER_5MIN';
|
||||||
public static MUTE_USER_10MIN: string = 'RWUAM_MUTE_USER_10MIN';
|
public static MUTE_USER_10MIN: string = 'RWUAM_MUTE_USER_10MIN';
|
||||||
public static SEND_FRIEND_REQUEST: string = 'RWUAM_SEND_FRIEND_REQUEST';
|
|
||||||
public static RESPECT_USER: string = 'RWUAM_RESPECT_USER';
|
public static RESPECT_USER: string = 'RWUAM_RESPECT_USER';
|
||||||
public static GIVE_RIGHTS: string = 'RWUAM_GIVE_RIGHTS';
|
public static GIVE_RIGHTS: string = 'RWUAM_GIVE_RIGHTS';
|
||||||
public static TAKE_RIGHTS: string = 'RWUAM_TAKE_RIGHTS';
|
public static TAKE_RIGHTS: string = 'RWUAM_TAKE_RIGHTS';
|
||||||
|
@ -9,7 +9,6 @@ export * from './RoomWidgetDanceMessage';
|
|||||||
export * from './RoomWidgetDimmerChangeStateMessage';
|
export * from './RoomWidgetDimmerChangeStateMessage';
|
||||||
export * from './RoomWidgetDimmerPreviewMessage';
|
export * from './RoomWidgetDimmerPreviewMessage';
|
||||||
export * from './RoomWidgetDimmerSavePresetMessage';
|
export * from './RoomWidgetDimmerSavePresetMessage';
|
||||||
export * from './RoomWidgetFriendRequestMessage';
|
|
||||||
export * from './RoomWidgetFurniActionMessage';
|
export * from './RoomWidgetFurniActionMessage';
|
||||||
export * from './RoomWidgetFurniToWidgetMessage';
|
export * from './RoomWidgetFurniToWidgetMessage';
|
||||||
export * from './RoomWidgetLetUserInMessage';
|
export * from './RoomWidgetLetUserInMessage';
|
||||||
|
@ -1,32 +0,0 @@
|
|||||||
import { createContext, FC, ProviderProps, useContext } from 'react';
|
|
||||||
import { MessengerFriend } from './common/MessengerFriend';
|
|
||||||
import { MessengerRequest } from './common/MessengerRequest';
|
|
||||||
import { MessengerSettings } from './common/MessengerSettings';
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
const FriendsContext = createContext<IFriendsContext>({
|
|
||||||
friends: null,
|
|
||||||
requests: null,
|
|
||||||
settings: null,
|
|
||||||
canRequestFriend: null,
|
|
||||||
requestFriend: null,
|
|
||||||
acceptFriend: null,
|
|
||||||
declineFriend: null
|
|
||||||
});
|
|
||||||
|
|
||||||
export const FriendsContextProvider: FC<ProviderProps<IFriendsContext>> = props =>
|
|
||||||
{
|
|
||||||
return <FriendsContext.Provider value={ props.value }>{ props.children }</FriendsContext.Provider>
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useFriendsContext = () => useContext(FriendsContext);
|
|
@ -1,371 +1,42 @@
|
|||||||
import { AcceptFriendMessageComposer, FriendListFragmentEvent, FriendListUpdateEvent, FriendParser, FriendRequestsEvent, GetFriendRequestsComposer, MessengerInitComposer, MessengerInitEvent, NewFriendRequestEvent, RequestFriendComposer, RoomEngineObjectEvent, RoomObjectCategory, RoomObjectUserType } from '@nitrots/nitro-renderer';
|
import { FC } from 'react';
|
||||||
import { DeclineFriendMessageComposer } from '@nitrots/nitro-renderer/src';
|
|
||||||
import { FC, useCallback, useEffect, useMemo, useState } from 'react';
|
|
||||||
import { createPortal } from 'react-dom';
|
import { createPortal } from 'react-dom';
|
||||||
import { GetRoomSession, SendMessageComposer } from '../../api';
|
import { useFriends } from '../../hooks';
|
||||||
import { FriendEnteredRoomEvent, FriendListContentEvent, FriendRequestEvent, FriendsAcceptFriendRequestEvent, FriendsDeclineFriendRequestEvent, FriendsEvent, FriendsRequestCountEvent, FriendsSendFriendRequestEvent } from '../../events';
|
import { FriendBarView } from './views/FriendBarView';
|
||||||
import { DispatchUiEvent, UseMessageEventHook, UseRoomEngineEvent, UseUiEvent } from '../../hooks';
|
|
||||||
import { FriendsHelper } from './common/FriendsHelper';
|
|
||||||
import { MessengerFriend } from './common/MessengerFriend';
|
|
||||||
import { MessengerRequest } from './common/MessengerRequest';
|
|
||||||
import { MessengerSettings } from './common/MessengerSettings';
|
|
||||||
import { FriendsContextProvider } from './FriendsContext';
|
|
||||||
import { FriendBarView } from './views/friend-bar/FriendBarView';
|
|
||||||
import { FriendsListView } from './views/friends-list/FriendsListView';
|
import { FriendsListView } from './views/friends-list/FriendsListView';
|
||||||
import { FriendsMessengerView } from './views/messenger/FriendsMessengerView';
|
import { FriendsMessengerView } from './views/messenger/FriendsMessengerView';
|
||||||
|
|
||||||
export const FriendsView: FC<{}> = props =>
|
export const FriendsView: FC<{}> = props =>
|
||||||
{
|
{
|
||||||
const [ isReady, setIsReady ] = useState(false);
|
const { settings = null, onlineFriends = [] } = useFriends();
|
||||||
const [ isVisible, setIsVisible ] = useState(false);
|
|
||||||
const [ friends, setFriends ] = useState<MessengerFriend[]>([]);
|
|
||||||
const [ requests, setRequests ] = useState<MessengerRequest[]>([]);
|
|
||||||
const [ settings, setSettings ] = useState<MessengerSettings>(null);
|
|
||||||
const [ sentRequests, setSentRequests ] = useState<number[]>([]);
|
|
||||||
|
|
||||||
const getFriend = useCallback((userId: number) =>
|
// const onRoomEngineObjectEvent = useCallback((event: RoomEngineObjectEvent) =>
|
||||||
{
|
// {
|
||||||
for(const friend of friends)
|
// const roomSession = GetRoomSession();
|
||||||
{
|
|
||||||
if(friend.id === userId) return friend;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
// if(!roomSession) return;
|
||||||
}, [ friends ]);
|
|
||||||
|
|
||||||
FriendsHelper.getFriend = getFriend;
|
// if(event.category !== RoomObjectCategory.UNIT) return;
|
||||||
|
|
||||||
const canRequestFriend = useCallback((userId: number) =>
|
|
||||||
{
|
|
||||||
if(getFriend(userId)) return false;
|
|
||||||
|
|
||||||
if(sentRequests.indexOf(userId) >= 0) return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}, [ sentRequests, getFriend ]);
|
|
||||||
|
|
||||||
FriendsHelper.canRequestFriend = canRequestFriend;
|
|
||||||
|
|
||||||
const requestFriend = useCallback((userId: number, userName: string) =>
|
|
||||||
{
|
|
||||||
if(sentRequests.indexOf(userId) >= 0) return true;
|
|
||||||
|
|
||||||
if(!canRequestFriend(userId)) return false;
|
|
||||||
|
|
||||||
setSentRequests(prevValue =>
|
|
||||||
{
|
|
||||||
const newSentRequests = [ ...prevValue ];
|
|
||||||
|
|
||||||
newSentRequests.push(userId);
|
|
||||||
|
|
||||||
return newSentRequests;
|
|
||||||
});
|
|
||||||
|
|
||||||
SendMessageComposer(new RequestFriendComposer(userName));
|
|
||||||
}, [ sentRequests, canRequestFriend ]);
|
|
||||||
|
|
||||||
const acceptFriend = useCallback((userId: number) =>
|
|
||||||
{
|
|
||||||
setRequests(prevValue =>
|
|
||||||
{
|
|
||||||
const newRequests: MessengerRequest[] = [ ...prevValue ];
|
|
||||||
|
|
||||||
const index = newRequests.findIndex(request => (request.requesterUserId === userId));
|
|
||||||
|
|
||||||
if(index >= 0)
|
|
||||||
{
|
|
||||||
SendMessageComposer(new AcceptFriendMessageComposer(newRequests[index].id));
|
|
||||||
|
|
||||||
DispatchUiEvent(new FriendRequestEvent(FriendRequestEvent.ACCEPTED, userId));
|
|
||||||
|
|
||||||
newRequests.splice(index, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return newRequests;
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const declineFriend = useCallback((userId: number, declineAll: boolean = false) =>
|
|
||||||
{
|
|
||||||
setRequests(prevValue =>
|
|
||||||
{
|
|
||||||
if(declineAll)
|
|
||||||
{
|
|
||||||
SendMessageComposer(new DeclineFriendMessageComposer(true));
|
|
||||||
|
|
||||||
for(const request of prevValue) DispatchUiEvent(new FriendRequestEvent(FriendRequestEvent.DECLINED, request.requesterUserId));
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const newRequests: MessengerRequest[] = [ ...prevValue ];
|
|
||||||
|
|
||||||
const index = newRequests.findIndex(request => (request.requesterUserId === userId));
|
|
||||||
|
|
||||||
if(index >= 0)
|
|
||||||
{
|
|
||||||
SendMessageComposer(new DeclineFriendMessageComposer(false, newRequests[index].id));
|
|
||||||
|
|
||||||
DispatchUiEvent(new FriendRequestEvent(FriendRequestEvent.DECLINED, userId));
|
|
||||||
|
|
||||||
newRequests.splice(index, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return newRequests;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const onMessengerInitEvent = useCallback((event: MessengerInitEvent) =>
|
|
||||||
{
|
|
||||||
const parser = event.getParser();
|
|
||||||
|
|
||||||
setSettings(new MessengerSettings(
|
|
||||||
parser.userFriendLimit,
|
|
||||||
parser.normalFriendLimit,
|
|
||||||
parser.extendedFriendLimit,
|
|
||||||
parser.categories));
|
|
||||||
|
|
||||||
SendMessageComposer(new GetFriendRequestsComposer());
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
UseMessageEventHook(MessengerInitEvent, onMessengerInitEvent);
|
|
||||||
|
|
||||||
const onFriendsFragmentEvent = useCallback((event: FriendListFragmentEvent) =>
|
|
||||||
{
|
|
||||||
const parser = event.getParser();
|
|
||||||
|
|
||||||
setFriends(prevValue =>
|
|
||||||
{
|
|
||||||
const newFriends = [ ...prevValue ];
|
|
||||||
|
|
||||||
for(const friend of parser.fragment)
|
|
||||||
{
|
|
||||||
const index = newFriends.findIndex(existingFriend => (existingFriend.id === friend.id));
|
|
||||||
const newFriend = new MessengerFriend();
|
|
||||||
|
|
||||||
newFriend.populate(friend);
|
|
||||||
|
|
||||||
if(index > -1) newFriends[index] = newFriend;
|
|
||||||
else newFriends.push(newFriend);
|
|
||||||
}
|
|
||||||
|
|
||||||
return newFriends;
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
UseMessageEventHook(FriendListFragmentEvent, onFriendsFragmentEvent);
|
|
||||||
|
|
||||||
const onFriendsUpdateEvent = useCallback((event: FriendListUpdateEvent) =>
|
|
||||||
{
|
|
||||||
const parser = event.getParser();
|
|
||||||
|
|
||||||
setFriends(prevValue =>
|
|
||||||
{
|
|
||||||
const newFriends = [ ...prevValue ];
|
|
||||||
|
|
||||||
const processUpdate = (friend: FriendParser) =>
|
|
||||||
{
|
|
||||||
const index = newFriends.findIndex(existingFriend => (existingFriend.id === friend.id));
|
|
||||||
|
|
||||||
if(index === -1)
|
|
||||||
{
|
|
||||||
const newFriend = new MessengerFriend();
|
|
||||||
newFriend.populate(friend);
|
|
||||||
|
|
||||||
newFriends.unshift(newFriend);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
newFriends[index].populate(friend);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for(const friend of parser.addedFriends) processUpdate(friend);
|
|
||||||
|
|
||||||
for(const friend of parser.updatedFriends) processUpdate(friend);
|
|
||||||
|
|
||||||
for(const removedFriendId of parser.removedFriendIds)
|
|
||||||
{
|
|
||||||
const index = newFriends.findIndex(existingFriend => (existingFriend.id === removedFriendId));
|
|
||||||
|
|
||||||
if(index > -1) newFriends.splice(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
return newFriends;
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
UseMessageEventHook(FriendListUpdateEvent, onFriendsUpdateEvent);
|
|
||||||
|
|
||||||
const onFriendRequestsEvent = useCallback((event: FriendRequestsEvent) =>
|
|
||||||
{
|
|
||||||
const parser = event.getParser();
|
|
||||||
|
|
||||||
setRequests(prevValue =>
|
|
||||||
{
|
|
||||||
const newRequests = [ ...prevValue ];
|
|
||||||
|
|
||||||
for(const request of parser.requests)
|
|
||||||
{
|
|
||||||
const index = newRequests.findIndex(existing => (existing.requesterUserId === request.requesterUserId));
|
|
||||||
|
|
||||||
if(index > 0) continue;
|
|
||||||
|
|
||||||
const newRequest = new MessengerRequest();
|
|
||||||
newRequest.populate(request);
|
|
||||||
|
|
||||||
newRequests.push(newRequest);
|
|
||||||
}
|
|
||||||
|
|
||||||
return newRequests;
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
UseMessageEventHook(FriendRequestsEvent, onFriendRequestsEvent);
|
|
||||||
|
|
||||||
const onNewFriendRequestEvent = useCallback((event: NewFriendRequestEvent) =>
|
|
||||||
{
|
|
||||||
const parser = event.getParser();
|
|
||||||
const request = parser.request;
|
|
||||||
|
|
||||||
setRequests(prevValue =>
|
|
||||||
{
|
|
||||||
const newRequests = [ ...prevValue ];
|
|
||||||
|
|
||||||
const index = newRequests.findIndex(existing => (existing.requesterUserId === request.requesterUserId));
|
|
||||||
|
|
||||||
if(index === -1)
|
|
||||||
{
|
|
||||||
const newRequest = new MessengerRequest();
|
|
||||||
newRequest.populate(request);
|
|
||||||
|
|
||||||
newRequests.push(newRequest);
|
|
||||||
}
|
|
||||||
|
|
||||||
return newRequests;
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
UseMessageEventHook(NewFriendRequestEvent, onNewFriendRequestEvent);
|
|
||||||
|
|
||||||
const onFriendsEvent = useCallback((event: FriendsEvent) =>
|
|
||||||
{
|
|
||||||
switch(event.type)
|
|
||||||
{
|
|
||||||
case FriendsEvent.SHOW_FRIEND_LIST:
|
|
||||||
setIsVisible(true);
|
|
||||||
return;
|
|
||||||
case FriendsEvent.TOGGLE_FRIEND_LIST:
|
|
||||||
setIsVisible(value => !value);
|
|
||||||
return;
|
|
||||||
case FriendsSendFriendRequestEvent.SEND_FRIEND_REQUEST:
|
|
||||||
const requestEvent = (event as FriendsSendFriendRequestEvent);
|
|
||||||
requestFriend(requestEvent.userId, requestEvent.userName);
|
|
||||||
return;
|
|
||||||
case FriendsEvent.REQUEST_FRIEND_LIST:
|
|
||||||
DispatchUiEvent(new FriendListContentEvent(friends));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}, [ friends, requestFriend ]);
|
|
||||||
|
|
||||||
UseUiEvent(FriendsEvent.SHOW_FRIEND_LIST, onFriendsEvent);
|
|
||||||
UseUiEvent(FriendsEvent.TOGGLE_FRIEND_LIST, onFriendsEvent);
|
|
||||||
UseUiEvent(FriendsSendFriendRequestEvent.SEND_FRIEND_REQUEST, onFriendsEvent);
|
|
||||||
UseUiEvent(FriendsEvent.REQUEST_FRIEND_LIST, onFriendsEvent);
|
|
||||||
|
|
||||||
const onFriendsAcceptFriendRequestEvent = useCallback((event: FriendsAcceptFriendRequestEvent) =>
|
|
||||||
{
|
|
||||||
acceptFriend(event.requestId);
|
|
||||||
}, [ acceptFriend ]);
|
|
||||||
|
|
||||||
UseUiEvent(FriendsAcceptFriendRequestEvent.ACCEPT_FRIEND_REQUEST, onFriendsAcceptFriendRequestEvent);
|
|
||||||
|
|
||||||
const onFriendsDeclineFriendRequestEvent = useCallback((event: FriendsDeclineFriendRequestEvent) =>
|
|
||||||
{
|
|
||||||
declineFriend(event.requestId);
|
|
||||||
}, [ declineFriend ]);
|
|
||||||
|
|
||||||
UseUiEvent(FriendsDeclineFriendRequestEvent.DECLINE_FRIEND_REQUEST, onFriendsDeclineFriendRequestEvent);
|
|
||||||
|
|
||||||
const onRoomEngineObjectEvent = useCallback((event: RoomEngineObjectEvent) =>
|
|
||||||
{
|
|
||||||
const roomSession = GetRoomSession();
|
|
||||||
|
|
||||||
if(!roomSession) return;
|
|
||||||
|
|
||||||
if(event.category !== RoomObjectCategory.UNIT) return;
|
|
||||||
|
|
||||||
const userData = roomSession.userDataManager.getUserDataByIndex(event.objectId);
|
// const userData = roomSession.userDataManager.getUserDataByIndex(event.objectId);
|
||||||
|
|
||||||
if(!userData || (userData.type !== RoomObjectUserType.getTypeNumber(RoomObjectUserType.USER))) return;
|
// if(!userData || (userData.type !== RoomObjectUserType.getTypeNumber(RoomObjectUserType.USER))) return;
|
||||||
|
|
||||||
const friend = getFriend(userData.webID);
|
// const friend = getFriend(userData.webID);
|
||||||
|
|
||||||
if(!friend) return;
|
// if(!friend) return;
|
||||||
|
|
||||||
DispatchUiEvent(new FriendEnteredRoomEvent(userData.roomIndex, RoomObjectCategory.UNIT, userData.webID, userData.name, userData.type));
|
// DispatchUiEvent(new FriendEnteredRoomEvent(userData.roomIndex, RoomObjectCategory.UNIT, userData.webID, userData.name, userData.type));
|
||||||
}, [ getFriend ]);
|
// }, [ getFriend ]);
|
||||||
|
|
||||||
UseRoomEngineEvent(RoomEngineObjectEvent.ADDED, onRoomEngineObjectEvent);
|
// UseRoomEngineEvent(RoomEngineObjectEvent.ADDED, onRoomEngineObjectEvent);
|
||||||
|
|
||||||
const onlineFriends = useMemo(() =>
|
if(!settings) return null;
|
||||||
{
|
|
||||||
const onlineFriends = friends.filter(friend => friend.online);
|
|
||||||
|
|
||||||
onlineFriends.sort((a, b) =>
|
|
||||||
{
|
|
||||||
if( a.name < b.name ) return -1;
|
|
||||||
|
|
||||||
if( a.name > b.name ) return 1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
});
|
|
||||||
|
|
||||||
return onlineFriends;
|
|
||||||
}, [ friends ]);
|
|
||||||
|
|
||||||
const offlineFriends = useMemo(() =>
|
|
||||||
{
|
|
||||||
const offlineFriends = friends.filter(friend => !friend.online);
|
|
||||||
|
|
||||||
offlineFriends.sort((a, b) =>
|
|
||||||
{
|
|
||||||
if( a.name < b.name ) return -1;
|
|
||||||
|
|
||||||
if( a.name > b.name ) return 1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
});
|
|
||||||
|
|
||||||
return offlineFriends;
|
|
||||||
}, [ friends ]);
|
|
||||||
|
|
||||||
useEffect(() =>
|
|
||||||
{
|
|
||||||
SendMessageComposer(new MessengerInitComposer());
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() =>
|
|
||||||
{
|
|
||||||
if(!settings) return;
|
|
||||||
|
|
||||||
setIsReady(true);
|
|
||||||
}, [ settings ]);
|
|
||||||
|
|
||||||
useEffect(() =>
|
|
||||||
{
|
|
||||||
DispatchUiEvent(new FriendsRequestCountEvent(requests.length));
|
|
||||||
}, [ requests ]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FriendsContextProvider value={ { friends, requests, settings, canRequestFriend, requestFriend, acceptFriend, declineFriend } }>
|
<>
|
||||||
{ isReady &&
|
{ createPortal(<FriendBarView onlineFriends={ onlineFriends } />, document.getElementById('toolbar-friend-bar-container')) }
|
||||||
createPortal(<FriendBarView onlineFriends={ onlineFriends } />, document.getElementById('toolbar-friend-bar-container')) }
|
<FriendsListView />
|
||||||
{ isVisible &&
|
|
||||||
<FriendsListView onlineFriends={ onlineFriends } offlineFriends={ offlineFriends } friendRequests={ requests } onCloseClick={ () => setIsVisible(false) } /> }
|
|
||||||
<FriendsMessengerView />
|
<FriendsMessengerView />
|
||||||
</FriendsContextProvider>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
import { MessengerFriend } from './MessengerFriend';
|
|
||||||
|
|
||||||
export class FriendsHelper
|
|
||||||
{
|
|
||||||
public static getFriend(userId: number): MessengerFriend
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static canRequestFriend(userId: number): boolean
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
export const getGroupChatData = (extraData: string) =>
|
|
||||||
{
|
|
||||||
const splitData = extraData.split('/');
|
|
||||||
|
|
||||||
const username = splitData[0];
|
|
||||||
const figure = splitData[1];
|
|
||||||
const userId = parseInt(splitData[2]);
|
|
||||||
|
|
||||||
const result: IGroupChatData = { username: username, figure: figure, userId: userId }
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IGroupChatData
|
|
||||||
{
|
|
||||||
username: string;
|
|
||||||
figure: string;
|
|
||||||
userId: number;
|
|
||||||
}
|
|
93
src/components/friends/views/FriendBarView.tsx
Normal file
93
src/components/friends/views/FriendBarView.tsx
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
|
import { MouseEventType } from '@nitrots/nitro-renderer';
|
||||||
|
import { FC, useEffect, useRef, useState } from 'react';
|
||||||
|
import { GetUserProfile, LocalizeText, MessengerFriend, OpenMessengerChat } from '../../../api';
|
||||||
|
import { Base, Button, Flex, LayoutAvatarImageView, LayoutBadgeImageView } from '../../../common';
|
||||||
|
import { useFriends } from '../../../hooks';
|
||||||
|
|
||||||
|
interface FriendBarViewProps
|
||||||
|
{
|
||||||
|
onlineFriends: MessengerFriend[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FriendBarView: FC<FriendBarViewProps> = props =>
|
||||||
|
{
|
||||||
|
const { onlineFriends = null } = props;
|
||||||
|
const [ indexOffset, setIndexOffset ] = useState(0);
|
||||||
|
const [ maxDisplayCount, setMaxDisplayCount ] = useState(3);
|
||||||
|
const { followFriend = null } = useFriends();
|
||||||
|
|
||||||
|
const FriendBarItemView: FC<{ friend: MessengerFriend }> = props =>
|
||||||
|
{
|
||||||
|
const { friend = null } = props;
|
||||||
|
const [ isVisible, setVisible ] = useState(false);
|
||||||
|
const elementRef = useRef<HTMLDivElement>();
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
const onClick = (event: MouseEvent) =>
|
||||||
|
{
|
||||||
|
const element = elementRef.current;
|
||||||
|
|
||||||
|
if(!element) return;
|
||||||
|
|
||||||
|
if((event.target !== element) && !element.contains((event.target as Node)))
|
||||||
|
{
|
||||||
|
setVisible(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener(MouseEventType.MOUSE_CLICK, onClick);
|
||||||
|
|
||||||
|
return () =>
|
||||||
|
{
|
||||||
|
document.removeEventListener(MouseEventType.MOUSE_CLICK, onClick);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
if(!friend)
|
||||||
|
{
|
||||||
|
return (
|
||||||
|
<div ref={ elementRef } className="btn btn-primary friend-bar-item friend-bar-search">
|
||||||
|
<div className="friend-bar-item-head position-absolute"/>
|
||||||
|
<div className="text-truncate">{ LocalizeText('friend.bar.find.title') }</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<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 ${friend.id > 0 ? 'avatar': 'group'}`}>
|
||||||
|
{ friend.id > 0 && <LayoutAvatarImageView headOnly={ true } figure={ friend.figure } direction={ 2 } /> }
|
||||||
|
{ friend.id <= 0 && <LayoutBadgeImageView isGroup={ true } badgeCode={ friend.figure} />}
|
||||||
|
</div>
|
||||||
|
<div className="text-truncate">{ friend.name }</div>
|
||||||
|
{ isVisible &&
|
||||||
|
<div className="d-flex justify-content-between">
|
||||||
|
<Base className="nitro-friends-spritesheet icon-friendbar-chat cursor-pointer" onClick={ event => OpenMessengerChat(friend.id) } />
|
||||||
|
{ friend.followingAllowed &&
|
||||||
|
<Base className="nitro-friends-spritesheet icon-friendbar-visit cursor-pointer" onClick={ event => followFriend(friend) } /> }
|
||||||
|
<Base className="nitro-friends-spritesheet icon-profile cursor-pointer" onClick={ event => GetUserProfile(friend.id) } />
|
||||||
|
</div> }
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const canDecreaseIndex = () => (indexOffset === 0) ? false : true;
|
||||||
|
const canIncreaseIndex = () => ((onlineFriends.length <= maxDisplayCount) || (indexOffset === (onlineFriends.length - 1))) ? false : true;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Flex alignItems="center" className="friend-bar">
|
||||||
|
<Button variant="black" className="friend-bar-button" disabled={ !canDecreaseIndex } onClick={ event => setIndexOffset(indexOffset - 1) }>
|
||||||
|
<FontAwesomeIcon icon="chevron-left" />
|
||||||
|
</Button>
|
||||||
|
{ Array.from(Array(maxDisplayCount), (e, i) =>
|
||||||
|
{
|
||||||
|
return <FriendBarItemView key={ i } friend={ (onlineFriends[ indexOffset + i ] || null) } />;
|
||||||
|
}) }
|
||||||
|
<Button variant="black" className="friend-bar-button" disabled={ !canIncreaseIndex } onClick={ event => setIndexOffset(indexOffset + 1) }>
|
||||||
|
<FontAwesomeIcon icon="chevron-right" />
|
||||||
|
</Button>
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
}
|
@ -1,78 +0,0 @@
|
|||||||
import { FollowFriendMessageComposer, MouseEventType } from '@nitrots/nitro-renderer';
|
|
||||||
import { FC, useCallback, useEffect, useRef, useState } from 'react';
|
|
||||||
import { GetUserProfile, LocalizeText, OpenMessengerChat, SendMessageComposer } from '../../../../api';
|
|
||||||
import { Base, LayoutAvatarImageView, LayoutBadgeImageView } from '../../../../common';
|
|
||||||
import { MessengerFriend } from '../../common/MessengerFriend';
|
|
||||||
|
|
||||||
interface FriendBarItemViewProps
|
|
||||||
{
|
|
||||||
friend: MessengerFriend;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const FriendBarItemView: FC<FriendBarItemViewProps> = props =>
|
|
||||||
{
|
|
||||||
const { friend = null } = props;
|
|
||||||
const [ isVisible, setVisible ] = useState(false);
|
|
||||||
const elementRef = useRef<HTMLDivElement>();
|
|
||||||
|
|
||||||
const followFriend = useCallback(() =>
|
|
||||||
{
|
|
||||||
SendMessageComposer(new FollowFriendMessageComposer(friend.id));
|
|
||||||
}, [ friend ]);
|
|
||||||
|
|
||||||
const openMessengerChat = useCallback(() =>
|
|
||||||
{
|
|
||||||
if(!friend) return;
|
|
||||||
|
|
||||||
OpenMessengerChat(friend.id);
|
|
||||||
}, [ friend ]);
|
|
||||||
|
|
||||||
const onClick = useCallback((event: MouseEvent) =>
|
|
||||||
{
|
|
||||||
const element = elementRef.current;
|
|
||||||
|
|
||||||
if(!element) return;
|
|
||||||
|
|
||||||
if((event.target !== element) && !element.contains((event.target as Node)))
|
|
||||||
{
|
|
||||||
setVisible(false);
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() =>
|
|
||||||
{
|
|
||||||
document.addEventListener(MouseEventType.MOUSE_CLICK, onClick);
|
|
||||||
|
|
||||||
return () =>
|
|
||||||
{
|
|
||||||
document.removeEventListener(MouseEventType.MOUSE_CLICK, onClick);
|
|
||||||
}
|
|
||||||
}, [ onClick ]);
|
|
||||||
|
|
||||||
if(!friend)
|
|
||||||
{
|
|
||||||
return (
|
|
||||||
<div ref={ elementRef } className="btn btn-primary friend-bar-item friend-bar-search">
|
|
||||||
<div className="friend-bar-item-head position-absolute"/>
|
|
||||||
<div className="text-truncate">{ LocalizeText('friend.bar.find.title') }</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<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 ${friend.id > 0 ? 'avatar': 'group'}`}>
|
|
||||||
{ friend.id > 0 && <LayoutAvatarImageView headOnly={ true } figure={ friend.figure } direction={ 2 } /> }
|
|
||||||
{ friend.id <= 0 && <LayoutBadgeImageView isGroup={ true } badgeCode={ friend.figure} />}
|
|
||||||
</div>
|
|
||||||
<div className="text-truncate">{ friend.name }</div>
|
|
||||||
{ isVisible &&
|
|
||||||
<div className="d-flex justify-content-between">
|
|
||||||
<Base className="nitro-friends-spritesheet icon-friendbar-chat cursor-pointer" onClick={ openMessengerChat } />
|
|
||||||
{ friend.followingAllowed &&
|
|
||||||
<Base className="nitro-friends-spritesheet icon-friendbar-visit cursor-pointer" onClick={ followFriend } /> }
|
|
||||||
<Base className="nitro-friends-spritesheet icon-profile cursor-pointer" onClick={ event => GetUserProfile(friend.id) } />
|
|
||||||
</div> }
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,48 +0,0 @@
|
|||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
||||||
import { FC, useMemo, useState } from 'react';
|
|
||||||
import { Button } from '../../../../common';
|
|
||||||
import { Flex } from '../../../../common/Flex';
|
|
||||||
import { MessengerFriend } from '../../common/MessengerFriend';
|
|
||||||
import { FriendBarItemView } from './FriendBarItemView';
|
|
||||||
|
|
||||||
interface FriendBarViewProps
|
|
||||||
{
|
|
||||||
onlineFriends: MessengerFriend[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export const FriendBarView: FC<FriendBarViewProps> = props =>
|
|
||||||
{
|
|
||||||
const { onlineFriends = null } = props;
|
|
||||||
|
|
||||||
const [ indexOffset, setIndexOffset ] = useState(0);
|
|
||||||
const [ maxDisplayCount, setMaxDisplayCount ] = useState(3);
|
|
||||||
|
|
||||||
const canDecreaseIndex = useMemo(() =>
|
|
||||||
{
|
|
||||||
if(indexOffset === 0) return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}, [ indexOffset ]);
|
|
||||||
|
|
||||||
const canIncreaseIndex = useMemo(() =>
|
|
||||||
{
|
|
||||||
if((onlineFriends.length <= maxDisplayCount) || (indexOffset === (onlineFriends.length - 1))) return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}, [ maxDisplayCount, indexOffset, onlineFriends ]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Flex alignItems="center" className="friend-bar">
|
|
||||||
<Button variant="black" className="friend-bar-button" disabled={ !canDecreaseIndex } onClick={ event => setIndexOffset(indexOffset - 1) }>
|
|
||||||
<FontAwesomeIcon icon="chevron-left" />
|
|
||||||
</Button>
|
|
||||||
{ Array.from(Array(maxDisplayCount), (e, i) =>
|
|
||||||
{
|
|
||||||
return <FriendBarItemView key={ i } friend={ (onlineFriends[ indexOffset + i ] || null) } />;
|
|
||||||
}) }
|
|
||||||
<Button variant="black" className="friend-bar-button" disabled={ !canIncreaseIndex } onClick={ event => setIndexOffset(indexOffset + 1) }>
|
|
||||||
<FontAwesomeIcon icon="chevron-right" />
|
|
||||||
</Button>
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
}
|
|
@ -0,0 +1,105 @@
|
|||||||
|
import { FC, MouseEvent, useState } from 'react';
|
||||||
|
import { LocalizeText, MessengerFriend, OpenMessengerChat } from '../../../../api';
|
||||||
|
import { Base, Flex, NitroCardAccordionItemView, UserProfileIconView } from '../../../../common';
|
||||||
|
import { useFriends } from '../../../../hooks';
|
||||||
|
|
||||||
|
interface FriendsListGroupViewProps
|
||||||
|
{
|
||||||
|
list: MessengerFriend[];
|
||||||
|
selectedFriendsIds: number[];
|
||||||
|
selectFriend: (userId: number) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FriendsListGroupView: FC<FriendsListGroupViewProps> = props =>
|
||||||
|
{
|
||||||
|
const { list = null, selectedFriendsIds = null, selectFriend = null } = props;
|
||||||
|
const { followFriend = null, updateRelationship = null } = useFriends();
|
||||||
|
|
||||||
|
if(!list || !list.length) return null;
|
||||||
|
|
||||||
|
const FriendsListGroupItemView: FC<{ friend: MessengerFriend, selected: boolean }> = props =>
|
||||||
|
{
|
||||||
|
const { friend = null, selected = false } = props;
|
||||||
|
const [ isRelationshipOpen, setIsRelationshipOpen ] = useState<boolean>(false);
|
||||||
|
|
||||||
|
const clickFollowFriend = (event: MouseEvent<HTMLDivElement>) =>
|
||||||
|
{
|
||||||
|
event.stopPropagation();
|
||||||
|
|
||||||
|
followFriend(friend);
|
||||||
|
}
|
||||||
|
|
||||||
|
const openMessengerChat = (event: MouseEvent<HTMLDivElement>) =>
|
||||||
|
{
|
||||||
|
event.stopPropagation();
|
||||||
|
|
||||||
|
OpenMessengerChat(friend.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
const openRelationship = (event: MouseEvent<HTMLDivElement>) =>
|
||||||
|
{
|
||||||
|
event.stopPropagation();
|
||||||
|
|
||||||
|
setIsRelationshipOpen(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
const clickUpdateRelationship = (event: MouseEvent<HTMLDivElement>, type: number) =>
|
||||||
|
{
|
||||||
|
event.stopPropagation();
|
||||||
|
|
||||||
|
updateRelationship(friend, type);
|
||||||
|
|
||||||
|
setIsRelationshipOpen(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
const getCurrentRelationshipName = () =>
|
||||||
|
{
|
||||||
|
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';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!friend) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<NitroCardAccordionItemView justifyContent="between" className={ `px-2 py-1 ${ selected && 'bg-primary text-white' }` } onClick={ event => selectFriend(friend.id) }>
|
||||||
|
<Flex alignItems="center" gap={ 1 }>
|
||||||
|
<Base onClick={ event => event.stopPropagation() }>
|
||||||
|
<UserProfileIconView userId={ friend.id } />
|
||||||
|
</Base>
|
||||||
|
<div>{ friend.name }</div>
|
||||||
|
</Flex>
|
||||||
|
<Flex alignItems="center" gap={ 1 }>
|
||||||
|
{ !isRelationshipOpen &&
|
||||||
|
<>
|
||||||
|
{ friend.followingAllowed &&
|
||||||
|
<Base pointer onClick={ clickFollowFriend } className="nitro-friends-spritesheet icon-follow" title={ LocalizeText('friendlist.tip.follow') } /> }
|
||||||
|
{ friend.online &&
|
||||||
|
<Base pointer className="nitro-friends-spritesheet icon-chat" onClick={ openMessengerChat } title={ LocalizeText('friendlist.tip.im') } /> }
|
||||||
|
{ (friend.id > 0) &&
|
||||||
|
<Base className={ `nitro-friends-spritesheet icon-${ getCurrentRelationshipName() } cursor-pointer` } onClick={ openRelationship } title={ LocalizeText('infostand.link.relationship') } /> }
|
||||||
|
</> }
|
||||||
|
{ isRelationshipOpen &&
|
||||||
|
<>
|
||||||
|
<Base pointer className="nitro-friends-spritesheet icon-heart" onClick={ event => clickUpdateRelationship(event, MessengerFriend.RELATIONSHIP_HEART) } />
|
||||||
|
<Base pointer className="nitro-friends-spritesheet icon-smile" onClick={ event => clickUpdateRelationship(event, MessengerFriend.RELATIONSHIP_SMILE) } />
|
||||||
|
<Base pointer className="nitro-friends-spritesheet icon-bobba" onClick={ event => clickUpdateRelationship(event, MessengerFriend.RELATIONSHIP_BOBBA) } />
|
||||||
|
<Base pointer className="nitro-friends-spritesheet icon-none" onClick={ event => clickUpdateRelationship(event, MessengerFriend.RELATIONSHIP_NONE) } />
|
||||||
|
</> }
|
||||||
|
</Flex>
|
||||||
|
</NitroCardAccordionItemView>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{ list.map((item, index) => <FriendsListGroupItemView key={ index } friend={ item } selected={ selectedFriendsIds && selectedFriendsIds.includes(item.id) } />) }
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
import { FC } from 'react';
|
||||||
|
import { LocalizeText, MessengerRequest } from '../../../../api';
|
||||||
|
import { Base, Button, Column, Flex, NitroCardAccordionItemView, NitroCardAccordionSetView, NitroCardAccordionSetViewProps, UserProfileIconView } from '../../../../common';
|
||||||
|
import { useFriends } from '../../../../hooks';
|
||||||
|
|
||||||
|
export const FriendsListRequestView: FC<NitroCardAccordionSetViewProps> = props =>
|
||||||
|
{
|
||||||
|
const { children = null, ...rest } = props;
|
||||||
|
const { requests = [], requestResponse = null } = useFriends();
|
||||||
|
|
||||||
|
if(!requests.length) return null;
|
||||||
|
|
||||||
|
const FriendsListRequestItemView: FC<{ request: MessengerRequest }> = props =>
|
||||||
|
{
|
||||||
|
const { request = null } = props;
|
||||||
|
|
||||||
|
if(!request) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<NitroCardAccordionItemView justifyContent="between" className="px-2 py-1">
|
||||||
|
<Flex alignItems="center" gap={ 1 }>
|
||||||
|
<UserProfileIconView userId={ request.id } />
|
||||||
|
<div>{ request.name }</div>
|
||||||
|
</Flex>
|
||||||
|
<Flex alignItems="center" gap={ 1 }>
|
||||||
|
<Base className="nitro-friends-spritesheet icon-accept cursor-pointer" onClick={ event => requestResponse(request.id, true) } />
|
||||||
|
<Base className="nitro-friends-spritesheet icon-deny cursor-pointer" onClick={ event => requestResponse(request.id, false) } />
|
||||||
|
</Flex>
|
||||||
|
</NitroCardAccordionItemView>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<NitroCardAccordionSetView { ...rest }>
|
||||||
|
<Column fullHeight justifyContent="between" gap={ 1 }>
|
||||||
|
<Column gap={ 0 }>
|
||||||
|
{ requests.map((request, index) => <FriendsListRequestItemView key={ index } request={ request } />) }
|
||||||
|
</Column>
|
||||||
|
<Flex justifyContent="center" className="px-2 py-1">
|
||||||
|
<Button onClick={ event => requestResponse(-1, false) }>
|
||||||
|
{ LocalizeText('friendlist.requests.dismissall') }
|
||||||
|
</Button>
|
||||||
|
</Flex>
|
||||||
|
</Column>
|
||||||
|
{ children }
|
||||||
|
</NitroCardAccordionSetView>
|
||||||
|
);
|
||||||
|
}
|
@ -12,7 +12,6 @@ interface FriendsRoomInviteViewProps
|
|||||||
export const FriendsRoomInviteView: FC<FriendsRoomInviteViewProps> = props =>
|
export const FriendsRoomInviteView: FC<FriendsRoomInviteViewProps> = props =>
|
||||||
{
|
{
|
||||||
const { selectedFriendsIds = null, onCloseClick = null, sendRoomInvite = null } = props;
|
const { selectedFriendsIds = null, onCloseClick = null, sendRoomInvite = null } = props;
|
||||||
|
|
||||||
const [ roomInviteMessage, setRoomInviteMessage ] = useState<string>('');
|
const [ roomInviteMessage, setRoomInviteMessage ] = useState<string>('');
|
||||||
|
|
||||||
return (
|
return (
|
@ -2,8 +2,7 @@ import { HabboSearchComposer, HabboSearchResultData, HabboSearchResultEvent } fr
|
|||||||
import { FC, useCallback, useEffect, useState } from 'react';
|
import { FC, useCallback, useEffect, useState } from 'react';
|
||||||
import { LocalizeText, OpenMessengerChat, SendMessageComposer } from '../../../../api';
|
import { LocalizeText, OpenMessengerChat, SendMessageComposer } from '../../../../api';
|
||||||
import { Base, Column, Flex, NitroCardAccordionItemView, NitroCardAccordionSetView, NitroCardAccordionSetViewProps, Text, UserProfileIconView } from '../../../../common';
|
import { Base, Column, Flex, NitroCardAccordionItemView, NitroCardAccordionSetView, NitroCardAccordionSetViewProps, Text, UserProfileIconView } from '../../../../common';
|
||||||
import { BatchUpdates, UseMessageEventHook } from '../../../../hooks';
|
import { BatchUpdates, useFriends, UseMessageEventHook } from '../../../../hooks';
|
||||||
import { useFriendsContext } from '../../FriendsContext';
|
|
||||||
|
|
||||||
interface FriendsSearchViewProps extends NitroCardAccordionSetViewProps
|
interface FriendsSearchViewProps extends NitroCardAccordionSetViewProps
|
||||||
{
|
{
|
||||||
@ -16,7 +15,7 @@ export const FriendsSearchView: FC<FriendsSearchViewProps> = props =>
|
|||||||
const [ searchValue, setSearchValue ] = useState('');
|
const [ searchValue, setSearchValue ] = useState('');
|
||||||
const [ friendResults, setFriendResults ] = useState<HabboSearchResultData[]>(null);
|
const [ friendResults, setFriendResults ] = useState<HabboSearchResultData[]>(null);
|
||||||
const [ otherResults, setOtherResults ] = useState<HabboSearchResultData[]>(null);
|
const [ otherResults, setOtherResults ] = useState<HabboSearchResultData[]>(null);
|
||||||
const { canRequestFriend = null, requestFriend = null } = useFriendsContext();
|
const { canRequestFriend = null, requestFriend = null } = useFriends();
|
||||||
|
|
||||||
const onHabboSearchResultEvent = useCallback((event: HabboSearchResultEvent) =>
|
const onHabboSearchResultEvent = useCallback((event: HabboSearchResultEvent) =>
|
||||||
{
|
{
|
@ -1,29 +1,21 @@
|
|||||||
import { RemoveFriendComposer, SendRoomInviteComposer } from '@nitrots/nitro-renderer';
|
import { ILinkEventTracker, RemoveFriendComposer, SendRoomInviteComposer } from '@nitrots/nitro-renderer';
|
||||||
import { FC, useCallback, useMemo, useState } from 'react';
|
import { FC, useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import { LocalizeText, SendMessageComposer } from '../../../../api';
|
import { AddEventLinkTracker, LocalizeText, MessengerFriend, RemoveLinkEventTracker, SendMessageComposer } from '../../../../api';
|
||||||
import { Button, Flex, NitroCardAccordionSetView, NitroCardAccordionView, NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../common';
|
import { Button, Flex, NitroCardAccordionSetView, NitroCardAccordionView, NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../common';
|
||||||
import { MessengerFriend } from '../../common/MessengerFriend';
|
import { useFriends } from '../../../../hooks';
|
||||||
import { MessengerRequest } from '../../common/MessengerRequest';
|
import { FriendsListGroupView } from './FriendsListGroupView';
|
||||||
import { FriendsListGroupView } from './friends-list-group/FriendsListGroupView';
|
import { FriendsRemoveConfirmationView } from './FriendsListRemoveConfirmationView';
|
||||||
import { FriendsListRequestView } from './friends-list-request/FriendsListRequestView';
|
import { FriendsListRequestView } from './FriendsListRequestView';
|
||||||
import { FriendsRemoveConfirmationView } from './FriendsRemoveConfirmationView';
|
import { FriendsRoomInviteView } from './FriendsListRoomInviteView';
|
||||||
import { FriendsRoomInviteView } from './FriendsRoomInviteView';
|
import { FriendsSearchView } from './FriendsListSearchView';
|
||||||
import { FriendsSearchView } from './FriendsSearchView';
|
|
||||||
|
|
||||||
interface FriendsListViewProps
|
export const FriendsListView: FC<{}> = props =>
|
||||||
{
|
{
|
||||||
onCloseClick: () => void;
|
const [ isVisible, setIsVisible ] = useState(false);
|
||||||
onlineFriends: MessengerFriend[];
|
|
||||||
offlineFriends: MessengerFriend[];
|
|
||||||
friendRequests: MessengerRequest[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export const FriendsListView: FC<FriendsListViewProps> = props =>
|
|
||||||
{
|
|
||||||
const { onlineFriends = [], offlineFriends = [], friendRequests = [], onCloseClick = null } = props;
|
|
||||||
const [ selectedFriendsIds, setSelectedFriendsIds ] = useState<number[]>([]);
|
const [ selectedFriendsIds, setSelectedFriendsIds ] = useState<number[]>([]);
|
||||||
const [ showRoomInvite, setShowRoomInvite ] = useState<boolean>(false);
|
const [ showRoomInvite, setShowRoomInvite ] = useState<boolean>(false);
|
||||||
const [ showRemoveFriendsConfirmation, setShowRemoveFriendsConfirmation ] = useState<boolean>(false);
|
const [ showRemoveFriendsConfirmation, setShowRemoveFriendsConfirmation ] = useState<boolean>(false);
|
||||||
|
const { onlineFriends = [], offlineFriends = [], requests = [], requestFriend = null } = useFriends();
|
||||||
|
|
||||||
const removeFriendsText = useMemo(() =>
|
const removeFriendsText = useMemo(() =>
|
||||||
{
|
{
|
||||||
@ -90,10 +82,46 @@ export const FriendsListView: FC<FriendsListViewProps> = props =>
|
|||||||
setShowRemoveFriendsConfirmation(false);
|
setShowRemoveFriendsConfirmation(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
const linkTracker: ILinkEventTracker = {
|
||||||
|
linkReceived: (url: string) =>
|
||||||
|
{
|
||||||
|
const parts = url.split('/');
|
||||||
|
|
||||||
|
if(parts.length < 2) return;
|
||||||
|
|
||||||
|
switch(parts[1])
|
||||||
|
{
|
||||||
|
case 'show':
|
||||||
|
setIsVisible(true);
|
||||||
|
return;
|
||||||
|
case 'hide':
|
||||||
|
setIsVisible(false);
|
||||||
|
return;
|
||||||
|
case 'toggle':
|
||||||
|
setIsVisible(prevValue => !prevValue);
|
||||||
|
return;
|
||||||
|
case 'request':
|
||||||
|
if(parts.length < 4) return;
|
||||||
|
|
||||||
|
requestFriend(parseInt(parts[2]), parts[3]);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
eventUrlPrefix: 'friends/'
|
||||||
|
};
|
||||||
|
|
||||||
|
AddEventLinkTracker(linkTracker);
|
||||||
|
|
||||||
|
return () => RemoveLinkEventTracker(linkTracker);
|
||||||
|
}, [ requestFriend ]);
|
||||||
|
|
||||||
|
if(!isVisible) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<NitroCardView className="nitro-friends" uniqueKey="nitro-friends" theme="primary-slim">
|
<NitroCardView className="nitro-friends" uniqueKey="nitro-friends" theme="primary-slim">
|
||||||
<NitroCardHeaderView headerText={ LocalizeText('friendlist.friends') } onCloseClick={ onCloseClick } />
|
<NitroCardHeaderView headerText={ LocalizeText('friendlist.friends') } onCloseClick={ event => setIsVisible(false) } />
|
||||||
<NitroCardContentView overflow="hidden" gap={ 1 } className="text-black p-0">
|
<NitroCardContentView overflow="hidden" gap={ 1 } className="text-black p-0">
|
||||||
<NitroCardAccordionView fullHeight overflow="hidden">
|
<NitroCardAccordionView fullHeight overflow="hidden">
|
||||||
<NitroCardAccordionSetView headerText={ LocalizeText('friendlist.friends') + ` (${onlineFriends.length})` } isExpanded={ true }>
|
<NitroCardAccordionSetView headerText={ LocalizeText('friendlist.friends') + ` (${onlineFriends.length})` } isExpanded={ true }>
|
||||||
@ -102,7 +130,7 @@ export const FriendsListView: FC<FriendsListViewProps> = props =>
|
|||||||
<NitroCardAccordionSetView headerText={ LocalizeText('friendlist.friends.offlinecaption') + ` (${offlineFriends.length})` }>
|
<NitroCardAccordionSetView headerText={ LocalizeText('friendlist.friends.offlinecaption') + ` (${offlineFriends.length})` }>
|
||||||
<FriendsListGroupView list={ offlineFriends } selectedFriendsIds={ selectedFriendsIds } selectFriend={ selectFriend } />
|
<FriendsListGroupView list={ offlineFriends } selectedFriendsIds={ selectedFriendsIds } selectFriend={ selectFriend } />
|
||||||
</NitroCardAccordionSetView>
|
</NitroCardAccordionSetView>
|
||||||
<FriendsListRequestView headerText={ LocalizeText('friendlist.tab.friendrequests') + ` (${ friendRequests.length })` } isExpanded={ true } requests={ friendRequests } />
|
<FriendsListRequestView headerText={ LocalizeText('friendlist.tab.friendrequests') + ` (${ requests.length })` } isExpanded={ true } />
|
||||||
<FriendsSearchView headerText={ LocalizeText('people.search.title') } />
|
<FriendsSearchView headerText={ LocalizeText('people.search.title') } />
|
||||||
</NitroCardAccordionView>
|
</NitroCardAccordionView>
|
||||||
{ selectedFriendsIds && selectedFriendsIds.length > 0 &&
|
{ selectedFriendsIds && selectedFriendsIds.length > 0 &&
|
||||||
|
@ -1,93 +0,0 @@
|
|||||||
import { FollowFriendMessageComposer, SetRelationshipStatusComposer } from '@nitrots/nitro-renderer';
|
|
||||||
import { FC, MouseEvent, useState } from 'react';
|
|
||||||
import { LocalizeText, OpenMessengerChat, SendMessageComposer } from '../../../../../api';
|
|
||||||
import { Base, Flex, NitroCardAccordionItemView, NitroCardAccordionItemViewProps, UserProfileIconView } from '../../../../../common';
|
|
||||||
import { MessengerFriend } from '../../../common/MessengerFriend';
|
|
||||||
|
|
||||||
interface FriendsListGroupItemViewProps extends NitroCardAccordionItemViewProps
|
|
||||||
{
|
|
||||||
friend: MessengerFriend;
|
|
||||||
selected?: boolean;
|
|
||||||
selectFriend: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const FriendsListGroupItemView: FC<FriendsListGroupItemViewProps> = props =>
|
|
||||||
{
|
|
||||||
const { friend = null, selected = false, selectFriend = null, children = null, ...rest } = props;
|
|
||||||
const [ isRelationshipOpen, setIsRelationshipOpen ] = useState<boolean>(false);
|
|
||||||
|
|
||||||
const followFriend = (event: MouseEvent<HTMLDivElement>) =>
|
|
||||||
{
|
|
||||||
event.stopPropagation();
|
|
||||||
|
|
||||||
SendMessageComposer(new FollowFriendMessageComposer(friend.id));
|
|
||||||
}
|
|
||||||
|
|
||||||
const openMessengerChat = (event: MouseEvent<HTMLDivElement>) =>
|
|
||||||
{
|
|
||||||
event.stopPropagation();
|
|
||||||
|
|
||||||
OpenMessengerChat(friend.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
const openRelationship = (event: MouseEvent<HTMLDivElement>) =>
|
|
||||||
{
|
|
||||||
event.stopPropagation();
|
|
||||||
|
|
||||||
setIsRelationshipOpen(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
const updateRelationship = (event: MouseEvent<HTMLDivElement>, type: number) =>
|
|
||||||
{
|
|
||||||
event.stopPropagation();
|
|
||||||
|
|
||||||
if(type !== friend.relationshipStatus) SendMessageComposer(new SetRelationshipStatusComposer(friend.id, type));
|
|
||||||
|
|
||||||
setIsRelationshipOpen(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
const getCurrentRelationshipName = () =>
|
|
||||||
{
|
|
||||||
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';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!friend) return null;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<NitroCardAccordionItemView justifyContent="between" className={ `px-2 py-1 ${ selected && 'bg-primary text-white' }` } onClick={ selectFriend } { ...rest }>
|
|
||||||
<Flex alignItems="center" gap={ 1 }>
|
|
||||||
<Base onClick={ event => event.stopPropagation() }>
|
|
||||||
<UserProfileIconView userId={ friend.id } />
|
|
||||||
</Base>
|
|
||||||
<div>{ friend.name }</div>
|
|
||||||
</Flex>
|
|
||||||
<Flex alignItems="center" gap={ 1 }>
|
|
||||||
{ !isRelationshipOpen &&
|
|
||||||
<>
|
|
||||||
{ friend.followingAllowed &&
|
|
||||||
<Base pointer onClick={ followFriend } className="nitro-friends-spritesheet icon-follow" title={ LocalizeText('friendlist.tip.follow') } /> }
|
|
||||||
{ friend.online &&
|
|
||||||
<Base pointer className="nitro-friends-spritesheet icon-chat" onClick={ openMessengerChat } title={ LocalizeText('friendlist.tip.im') } /> }
|
|
||||||
{ (friend.id > 0) &&
|
|
||||||
<Base className={ `nitro-friends-spritesheet icon-${ getCurrentRelationshipName() } cursor-pointer` } onClick={ openRelationship } title={ LocalizeText('infostand.link.relationship') } /> }
|
|
||||||
</> }
|
|
||||||
{ isRelationshipOpen &&
|
|
||||||
<>
|
|
||||||
<Base pointer className="nitro-friends-spritesheet icon-heart" onClick={ event => updateRelationship(event, MessengerFriend.RELATIONSHIP_HEART) } />
|
|
||||||
<Base pointer className="nitro-friends-spritesheet icon-smile" onClick={ event => updateRelationship(event, MessengerFriend.RELATIONSHIP_SMILE) } />
|
|
||||||
<Base pointer className="nitro-friends-spritesheet icon-bobba" onClick={ event => updateRelationship(event, MessengerFriend.RELATIONSHIP_BOBBA) } />
|
|
||||||
<Base pointer className="nitro-friends-spritesheet icon-none" onClick={ event => updateRelationship(event, MessengerFriend.RELATIONSHIP_NONE) } />
|
|
||||||
</> }
|
|
||||||
</Flex>
|
|
||||||
{ children }
|
|
||||||
</NitroCardAccordionItemView>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,24 +0,0 @@
|
|||||||
import { FC } from 'react';
|
|
||||||
import { MessengerFriend } from '../../../common/MessengerFriend';
|
|
||||||
import { FriendsListGroupItemView } from './FriendsListGroupItemView';
|
|
||||||
|
|
||||||
interface FriendsListGroupViewProps
|
|
||||||
{
|
|
||||||
list: MessengerFriend[];
|
|
||||||
selectedFriendsIds: number[];
|
|
||||||
selectFriend: (userId: number) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const FriendsListGroupView: FC<FriendsListGroupViewProps> = props =>
|
|
||||||
{
|
|
||||||
const { list = null, selectedFriendsIds = null, selectFriend = null } = props;
|
|
||||||
|
|
||||||
if(!list || !list.length) return null;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{ list.map((item, index) => <FriendsListGroupItemView key={ index } friend={ item } selected={ selectedFriendsIds && selectedFriendsIds.includes(item.id) } selectFriend={ () => selectFriend(item.id) } />) }
|
|
||||||
</>
|
|
||||||
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,31 +0,0 @@
|
|||||||
import { FC } from 'react';
|
|
||||||
import { Base, Flex, NitroCardAccordionItemView, NitroCardAccordionItemViewProps, UserProfileIconView } from '../../../../../common';
|
|
||||||
import { MessengerRequest } from '../../../common/MessengerRequest';
|
|
||||||
import { useFriendsContext } from '../../../FriendsContext';
|
|
||||||
|
|
||||||
interface FriendsListRequestItemViewProps extends NitroCardAccordionItemViewProps
|
|
||||||
{
|
|
||||||
request: MessengerRequest;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const FriendsListRequestItemView: FC<FriendsListRequestItemViewProps> = props =>
|
|
||||||
{
|
|
||||||
const { request = null, children = null, ...rest } = props;
|
|
||||||
const { acceptFriend = null, declineFriend = null } = useFriendsContext();
|
|
||||||
|
|
||||||
if(!request) return null;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<NitroCardAccordionItemView justifyContent="between" className="px-2 py-1" { ...rest }>
|
|
||||||
<Flex alignItems="center" gap={ 1 }>
|
|
||||||
<UserProfileIconView userId={ request.id } />
|
|
||||||
<div>{ request.name }</div>
|
|
||||||
</Flex>
|
|
||||||
<Flex alignItems="center" gap={ 1 }>
|
|
||||||
<Base className="nitro-friends-spritesheet icon-accept cursor-pointer" onClick={ event => acceptFriend(request.requesterUserId) } />
|
|
||||||
<Base className="nitro-friends-spritesheet icon-deny cursor-pointer" onClick={ event => declineFriend(request.requesterUserId) } />
|
|
||||||
</Flex>
|
|
||||||
{ children }
|
|
||||||
</NitroCardAccordionItemView>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,35 +0,0 @@
|
|||||||
import { FC } from 'react';
|
|
||||||
import { LocalizeText } from '../../../../../api';
|
|
||||||
import { Button, Column, Flex, NitroCardAccordionSetView, NitroCardAccordionSetViewProps } from '../../../../../common';
|
|
||||||
import { MessengerRequest } from '../../../common/MessengerRequest';
|
|
||||||
import { useFriendsContext } from '../../../FriendsContext';
|
|
||||||
import { FriendsListRequestItemView } from './FriendsListRequestItemView';
|
|
||||||
|
|
||||||
interface FriendsListRequestViewProps extends NitroCardAccordionSetViewProps
|
|
||||||
{
|
|
||||||
requests: MessengerRequest[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export const FriendsListRequestView: FC<FriendsListRequestViewProps> = props =>
|
|
||||||
{
|
|
||||||
const { requests = [], children = null, ...rest } = props;
|
|
||||||
const { declineFriend = null } = useFriendsContext();
|
|
||||||
|
|
||||||
if(!requests.length) return null;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<NitroCardAccordionSetView { ...rest }>
|
|
||||||
<Column fullHeight justifyContent="between" gap={ 1 }>
|
|
||||||
<Column gap={ 0 }>
|
|
||||||
{ requests.map((request, index) => <FriendsListRequestItemView key={ index } request={ request } />) }
|
|
||||||
</Column>
|
|
||||||
<Flex justifyContent="center" className="px-2 py-1">
|
|
||||||
<Button onClick={ event => declineFriend(-1, true) }>
|
|
||||||
{ LocalizeText('friendlist.requests.dismissall') }
|
|
||||||
</Button>
|
|
||||||
</Flex>
|
|
||||||
</Column>
|
|
||||||
{ children }
|
|
||||||
</NitroCardAccordionSetView>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,84 +0,0 @@
|
|||||||
import { FC, useMemo } from 'react';
|
|
||||||
import { GetSessionDataManager, LocalizeText } from '../../../../api';
|
|
||||||
import { Base, Flex, LayoutAvatarImageView } from '../../../../common';
|
|
||||||
import { GroupType } from '../../common/GroupType';
|
|
||||||
import { MessengerThread } from '../../common/MessengerThread';
|
|
||||||
import { MessengerThreadChat } from '../../common/MessengerThreadChat';
|
|
||||||
import { MessengerThreadChatGroup } from '../../common/MessengerThreadChatGroup';
|
|
||||||
import { getGroupChatData } from '../../common/Utils';
|
|
||||||
|
|
||||||
interface FriendsMessengerThreadGroupProps
|
|
||||||
{
|
|
||||||
thread: MessengerThread;
|
|
||||||
group: MessengerThreadChatGroup;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const FriendsMessengerThreadGroup: FC<FriendsMessengerThreadGroupProps> = props =>
|
|
||||||
{
|
|
||||||
const { thread = null, group = null } = props;
|
|
||||||
|
|
||||||
const isOwnChat = useMemo(() =>
|
|
||||||
{
|
|
||||||
if(!thread || !group) return false;
|
|
||||||
|
|
||||||
if(group.type === GroupType.PRIVATE_CHAT && (group.userId === GetSessionDataManager().userId)) return true;
|
|
||||||
|
|
||||||
if( (group.type === GroupType.GROUP_CHAT) && (group.chats.length && getGroupChatData(group.chats[0].extraData).userId === GetSessionDataManager().userId)) return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}, [group, thread]);
|
|
||||||
|
|
||||||
if(!thread || !group) return null;
|
|
||||||
|
|
||||||
if(!group.userId)
|
|
||||||
{
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{ group.chats.map((chat, index) =>
|
|
||||||
{
|
|
||||||
return (
|
|
||||||
<div className="d-flex gap-2 w-100 justify-content-start">
|
|
||||||
<Base key={ index } className="w-100 text-break">
|
|
||||||
{ chat.type === MessengerThreadChat.SECURITY_NOTIFICATION &&
|
|
||||||
<Base className="bg-light rounded mb-2 d-flex gap-2 px-2 py-1 small text-muted align-items-center">
|
|
||||||
<Base className="nitro-friends-spritesheet icon-warning flex-shrink-0" />
|
|
||||||
<Base>{ chat.message }</Base>
|
|
||||||
</Base> }
|
|
||||||
{ chat.type === MessengerThreadChat.ROOM_INVITE &&
|
|
||||||
<Base className="bg-light rounded mb-2 d-flex gap-2 px-2 py-1 small text-black align-items-center">
|
|
||||||
<Base className="messenger-notification-icon flex-shrink-0" />
|
|
||||||
<Base>{(LocalizeText('messenger.invitation') + ' ') }{ chat.message }</Base>
|
|
||||||
</Base> }
|
|
||||||
</Base>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}) }
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Flex className={ 'w-100 justify-content-' + (isOwnChat ? 'end' : 'start') } gap={ 2 }>
|
|
||||||
<Base className="message-avatar flex-shrink-0">
|
|
||||||
{ (group.type === GroupType.PRIVATE_CHAT && !isOwnChat) &&
|
|
||||||
<LayoutAvatarImageView figure={ thread.participant.figure } direction={ 2 } />
|
|
||||||
}
|
|
||||||
{ (group.type === GroupType.GROUP_CHAT && !isOwnChat) &&
|
|
||||||
<LayoutAvatarImageView figure={ getGroupChatData(group.chats[0].extraData).figure } direction={ 2} />
|
|
||||||
}
|
|
||||||
</Base>
|
|
||||||
<Base className={ 'bg-light text-black border-radius mb-2 rounded py-1 px-2 messages-group-' + (isOwnChat ? 'right' : 'left') }>
|
|
||||||
<Base className='fw-bold'>
|
|
||||||
{ (isOwnChat) && GetSessionDataManager().userName }
|
|
||||||
{ (!isOwnChat) && ((group.type === GroupType.GROUP_CHAT) ? getGroupChatData(group.chats[0].extraData).username : thread.participant.name)
|
|
||||||
}
|
|
||||||
</Base>
|
|
||||||
{ group.chats.map((chat, index) =><Base key={ index } className="text-break">{ chat.message }</Base>) }
|
|
||||||
</Base>
|
|
||||||
{ (isOwnChat) &&
|
|
||||||
<Base className="message-avatar flex-shrink-0">
|
|
||||||
<LayoutAvatarImageView figure={ GetSessionDataManager().figure } direction={ 4 } />
|
|
||||||
</Base> }
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,22 +1,84 @@
|
|||||||
import { FC } from 'react';
|
import { FC, useMemo } from 'react';
|
||||||
import { MessengerThread } from '../../common/MessengerThread';
|
import { GetGroupChatData, GetSessionDataManager, GroupType, LocalizeText, MessengerThread, MessengerThreadChat, MessengerThreadChatGroup } from '../../../../api';
|
||||||
import { FriendsMessengerThreadGroup } from './FriendsMessengerThreadGroup';
|
import { Base, Flex, LayoutAvatarImageView } from '../../../../common';
|
||||||
|
|
||||||
interface FriendsMessengerThreadViewProps
|
export const FriendsMessengerThreadView: FC<{ thread: MessengerThread }> = props =>
|
||||||
{
|
|
||||||
thread: MessengerThread;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const FriendsMessengerThreadView: FC<FriendsMessengerThreadViewProps> = props =>
|
|
||||||
{
|
{
|
||||||
const { thread = null } = props;
|
const { thread = null } = props;
|
||||||
|
|
||||||
|
const FriendsMessengerThreadGroup: FC<{ thread: MessengerThread, group: MessengerThreadChatGroup }> = props =>
|
||||||
|
{
|
||||||
|
const { thread = null, group = null, ...rest } = props;
|
||||||
|
|
||||||
|
const isOwnChat = useMemo(() =>
|
||||||
|
{
|
||||||
|
if(!thread || !group) return false;
|
||||||
|
|
||||||
|
if(group.type === GroupType.PRIVATE_CHAT && (group.userId === GetSessionDataManager().userId)) return true;
|
||||||
|
|
||||||
|
if( (group.type === GroupType.GROUP_CHAT) && (group.chats.length && GetGroupChatData(group.chats[0].extraData).userId === GetSessionDataManager().userId)) return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}, [ group, thread ]);
|
||||||
|
|
||||||
|
if(!thread || !group) return null;
|
||||||
|
|
||||||
|
if(!group.userId)
|
||||||
|
{
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{ group.chats.map((chat, index) =>
|
||||||
|
{
|
||||||
|
return (
|
||||||
|
<Flex key={ index } fullWidth justifyContent="start" gap={ 2 }>
|
||||||
|
<Base className="w-100 text-break">
|
||||||
|
{ (chat.type === MessengerThreadChat.SECURITY_NOTIFICATION) &&
|
||||||
|
<Base className="bg-light rounded mb-2 d-flex gap-2 px-2 py-1 small text-muted align-items-center">
|
||||||
|
<Base className="nitro-friends-spritesheet icon-warning flex-shrink-0" />
|
||||||
|
<Base>{ chat.message }</Base>
|
||||||
|
</Base> }
|
||||||
|
{ (chat.type === MessengerThreadChat.ROOM_INVITE) &&
|
||||||
|
<Base className="bg-light rounded mb-2 d-flex gap-2 px-2 py-1 small text-black align-items-center">
|
||||||
|
<Base className="messenger-notification-icon flex-shrink-0" />
|
||||||
|
<Base>{ `${ LocalizeText('messenger.invitation') } ${ chat.message }` }</Base>
|
||||||
|
</Base> }
|
||||||
|
</Base>
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
}) }
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Flex className={ 'w-100 justify-content-' + (isOwnChat ? 'end' : 'start') } gap={ 2 } { ...rest }>
|
||||||
|
<Base className="message-avatar flex-shrink-0">
|
||||||
|
{ (group.type === GroupType.PRIVATE_CHAT && !isOwnChat) &&
|
||||||
|
<LayoutAvatarImageView figure={ thread.participant.figure } direction={ 2 } />
|
||||||
|
}
|
||||||
|
{ (group.type === GroupType.GROUP_CHAT && !isOwnChat) &&
|
||||||
|
<LayoutAvatarImageView figure={ GetGroupChatData(group.chats[0].extraData).figure } direction={ 2} />
|
||||||
|
}
|
||||||
|
</Base>
|
||||||
|
<Base className={ 'bg-light text-black border-radius mb-2 rounded py-1 px-2 messages-group-' + (isOwnChat ? 'right' : 'left') }>
|
||||||
|
<Base className='fw-bold'>
|
||||||
|
{ (isOwnChat) && GetSessionDataManager().userName }
|
||||||
|
{ (!isOwnChat) && ((group.type === GroupType.GROUP_CHAT) ? GetGroupChatData(group.chats[0].extraData).username : thread.participant.name)
|
||||||
|
}
|
||||||
|
</Base>
|
||||||
|
{ group.chats.map((chat, index) =><Base key={ index } className="text-break">{ chat.message }</Base>) }
|
||||||
|
</Base>
|
||||||
|
{ (isOwnChat) &&
|
||||||
|
<Base className="message-avatar flex-shrink-0">
|
||||||
|
<LayoutAvatarImageView figure={ GetSessionDataManager().figure } direction={ 4 } />
|
||||||
|
</Base> }
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{ (thread.groups.length > 0) && thread.groups.map((group, index) =>
|
{ (thread.groups.length > 0) && thread.groups.map((group, index) => <FriendsMessengerThreadGroup key={ index } thread={ thread } group={ group } />) }
|
||||||
{
|
|
||||||
return <FriendsMessengerThreadGroup key={ index } thread={ thread } group={ group } />;
|
|
||||||
}) }
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,281 +1,123 @@
|
|||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { FollowFriendMessageComposer, ILinkEventTracker, NewConsoleMessageEvent, RoomInviteErrorEvent, RoomInviteEvent, SendMessageComposer as SendMessageComposerPacket } from '@nitrots/nitro-renderer';
|
import { FollowFriendMessageComposer, ILinkEventTracker } from '@nitrots/nitro-renderer';
|
||||||
import { FC, KeyboardEvent, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
import { FC, KeyboardEvent, useEffect, useRef, useState } from 'react';
|
||||||
import { AddEventLinkTracker, GetSessionDataManager, GetUserProfile, LocalizeText, NotificationAlertType, NotificationUtilities, PlaySound, RemoveLinkEventTracker, SendMessageComposer, SoundNames } from '../../../../api';
|
import { AddEventLinkTracker, GetUserProfile, LocalizeText, RemoveLinkEventTracker, SendMessageComposer } from '../../../../api';
|
||||||
import { Base, Button, ButtonGroup, Column, Flex, Grid, LayoutAvatarImageView, LayoutBadgeImageView, LayoutGridItem, LayoutItemCountView, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../../common';
|
import { Base, Button, ButtonGroup, Column, Flex, Grid, LayoutAvatarImageView, LayoutBadgeImageView, LayoutGridItem, LayoutItemCountView, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../../common';
|
||||||
import { FriendsMessengerIconEvent } from '../../../../events';
|
import { BatchUpdates, useMessenger } from '../../../../hooks';
|
||||||
import { BatchUpdates, DispatchUiEvent, UseMessageEventHook } from '../../../../hooks';
|
|
||||||
import { MessengerThread } from '../../common/MessengerThread';
|
|
||||||
import { MessengerThreadChat } from '../../common/MessengerThreadChat';
|
|
||||||
import { useFriendsContext } from '../../FriendsContext';
|
|
||||||
import { FriendsMessengerThreadView } from './FriendsMessengerThreadView';
|
import { FriendsMessengerThreadView } from './FriendsMessengerThreadView';
|
||||||
|
|
||||||
export const FriendsMessengerView: FC<{}> = props =>
|
export const FriendsMessengerView: FC<{}> = props =>
|
||||||
{
|
{
|
||||||
const [isVisible, setIsVisible] = useState(false);
|
const [ isVisible, setIsVisible ] = useState(false);
|
||||||
const [messageThreads, setMessageThreads] = useState<MessengerThread[]>([]);
|
const [ lastThreadId, setLastThreadId ] = useState(-1);
|
||||||
const [activeThreadIndex, setActiveThreadIndex] = useState(-1);
|
const [ messageText, setMessageText ] = useState('');
|
||||||
const [hiddenThreadIndexes, setHiddenThreadIndexes] = useState<number[]>([]);
|
const { visibleThreads = [], activeThread = null, getMessageThread = null, sendMessage = null, setActiveThread = null, closeThread = null } = useMessenger();
|
||||||
const [messageText, setMessageText] = useState('');
|
|
||||||
const [updateValue, setUpdateValue] = useState({});
|
|
||||||
const { friends = [] } = useFriendsContext();
|
|
||||||
const messagesBox = useRef<HTMLDivElement>();
|
const messagesBox = useRef<HTMLDivElement>();
|
||||||
|
|
||||||
const followFriend = useCallback(() =>
|
const followFriend = () => (activeThread && activeThread.participant && SendMessageComposer(new FollowFriendMessageComposer(activeThread.participant.id)));
|
||||||
|
const openProfile = () => (activeThread && activeThread.participant && GetUserProfile(activeThread.participant.id));
|
||||||
|
|
||||||
|
const send = () =>
|
||||||
{
|
{
|
||||||
SendMessageComposer(new FollowFriendMessageComposer(messageThreads[activeThreadIndex].participant.id));
|
if(!activeThread || !messageText.length) return;
|
||||||
}, [messageThreads, activeThreadIndex]);
|
|
||||||
|
|
||||||
const openProfile = useCallback(() =>
|
sendMessage(activeThread, messageText);
|
||||||
{
|
|
||||||
GetUserProfile(messageThreads[activeThreadIndex].participant.id);
|
|
||||||
}, [messageThreads, activeThreadIndex]);
|
|
||||||
|
|
||||||
const getFriend = useCallback((userId: number) =>
|
setMessageText('');
|
||||||
{
|
}
|
||||||
return ((friends.find(friend => (friend.id === userId))) || null);
|
|
||||||
}, [friends]);
|
|
||||||
|
|
||||||
const visibleThreads = useMemo(() =>
|
const onKeyDown = (event: KeyboardEvent<HTMLInputElement>) =>
|
||||||
{
|
|
||||||
return messageThreads.filter((thread, index) =>
|
|
||||||
{
|
|
||||||
if(hiddenThreadIndexes.indexOf(index) >= 0) return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}, [messageThreads, hiddenThreadIndexes]);
|
|
||||||
|
|
||||||
const getMessageThreadWithIndex = useCallback<(userId: number) => [number, MessengerThread]>((userId: number) =>
|
|
||||||
{
|
|
||||||
if(messageThreads.length > 0)
|
|
||||||
{
|
|
||||||
for(let i = 0; i < messageThreads.length; i++)
|
|
||||||
{
|
|
||||||
const thread = messageThreads[i];
|
|
||||||
|
|
||||||
if(thread.participant && (thread.participant.id === userId))
|
|
||||||
{
|
|
||||||
const hiddenIndex = hiddenThreadIndexes.indexOf(i);
|
|
||||||
|
|
||||||
if(hiddenIndex >= 0)
|
|
||||||
{
|
|
||||||
setHiddenThreadIndexes(prevValue =>
|
|
||||||
{
|
|
||||||
const newIndexes = [...prevValue];
|
|
||||||
|
|
||||||
newIndexes.splice(hiddenIndex, 1);
|
|
||||||
|
|
||||||
return newIndexes;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return [i, thread];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const friend = getFriend(userId);
|
|
||||||
|
|
||||||
if(!friend) return [-1, null];
|
|
||||||
|
|
||||||
const thread = new MessengerThread(friend);
|
|
||||||
const newThreads = [...messageThreads, thread];
|
|
||||||
|
|
||||||
setMessageThreads(newThreads);
|
|
||||||
|
|
||||||
return [(newThreads.length - 1), thread];
|
|
||||||
}, [messageThreads, hiddenThreadIndexes, getFriend]);
|
|
||||||
|
|
||||||
const onNewConsoleMessageEvent = useCallback((event: NewConsoleMessageEvent) =>
|
|
||||||
{
|
|
||||||
const parser = event.getParser();
|
|
||||||
const [threadIndex, thread] = getMessageThreadWithIndex(parser.senderId);
|
|
||||||
|
|
||||||
if((threadIndex === -1) || !thread) return;
|
|
||||||
|
|
||||||
thread.addMessage(parser.senderId, parser.messageText, parser.secondsSinceSent, parser.extraData);
|
|
||||||
|
|
||||||
setMessageThreads(prevValue => [...prevValue]);
|
|
||||||
}, [getMessageThreadWithIndex]);
|
|
||||||
|
|
||||||
UseMessageEventHook(NewConsoleMessageEvent, onNewConsoleMessageEvent);
|
|
||||||
|
|
||||||
const onRoomInviteEvent = useCallback((event: RoomInviteEvent) =>
|
|
||||||
{
|
|
||||||
const parser = event.getParser();
|
|
||||||
|
|
||||||
const [threadIndex, thread] = getMessageThreadWithIndex(parser.senderId);
|
|
||||||
|
|
||||||
if((threadIndex === -1) || !thread) return;
|
|
||||||
|
|
||||||
thread.addMessage(null, parser.messageText, 0, null, MessengerThreadChat.ROOM_INVITE);
|
|
||||||
|
|
||||||
setMessageThreads(prevValue => [...prevValue]);
|
|
||||||
}, [getMessageThreadWithIndex]);
|
|
||||||
|
|
||||||
UseMessageEventHook(RoomInviteEvent, onRoomInviteEvent);
|
|
||||||
|
|
||||||
const onRoomInviteErrorEvent = useCallback((event: RoomInviteErrorEvent) =>
|
|
||||||
{
|
|
||||||
const parser = event.getParser();
|
|
||||||
const message = ((('Received room invite error: errorCode: ' + parser.errorCode) + ', recipients: ') + parser.failedRecipients);
|
|
||||||
|
|
||||||
NotificationUtilities.simpleAlert(message, NotificationAlertType.DEFAULT, null, null, LocalizeText('friendlist.alert.title'));
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
UseMessageEventHook(RoomInviteErrorEvent, onRoomInviteErrorEvent);
|
|
||||||
|
|
||||||
const sendMessage = useCallback(() =>
|
|
||||||
{
|
|
||||||
if(!messageText || !messageText.length) return;
|
|
||||||
|
|
||||||
if(activeThreadIndex === -1) return;
|
|
||||||
|
|
||||||
const thread = messageThreads[activeThreadIndex];
|
|
||||||
|
|
||||||
if(!thread) return;
|
|
||||||
|
|
||||||
SendMessageComposer(new SendMessageComposerPacket(thread.participant.id, messageText));
|
|
||||||
|
|
||||||
if(messageThreads.length === 1 && thread.groups.length === 1) PlaySound(SoundNames.MESSENGER_NEW_THREAD);
|
|
||||||
|
|
||||||
thread.addMessage(GetSessionDataManager().userId, messageText, 0, null, MessengerThreadChat.CHAT);
|
|
||||||
|
|
||||||
BatchUpdates(() =>
|
|
||||||
{
|
|
||||||
setMessageThreads(prevValue => [...prevValue]);
|
|
||||||
setMessageText('');
|
|
||||||
});
|
|
||||||
}, [messageThreads, activeThreadIndex, messageText]);
|
|
||||||
|
|
||||||
const onKeyDown = useCallback((event: KeyboardEvent<HTMLInputElement>) =>
|
|
||||||
{
|
{
|
||||||
if(event.key !== 'Enter') return;
|
if(event.key !== 'Enter') return;
|
||||||
|
|
||||||
sendMessage();
|
send();
|
||||||
}, [sendMessage]);
|
}
|
||||||
|
|
||||||
const linkReceived = useCallback((url: string) =>
|
|
||||||
{
|
|
||||||
const parts = url.split('/');
|
|
||||||
|
|
||||||
if(parts.length < 3) return;
|
|
||||||
|
|
||||||
if(parts[2] === 'open')
|
|
||||||
{
|
|
||||||
setIsVisible(true);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const [threadIndex] = getMessageThreadWithIndex(parseInt(parts[2]));
|
|
||||||
|
|
||||||
if(threadIndex === -1) return;
|
|
||||||
|
|
||||||
BatchUpdates(() =>
|
|
||||||
{
|
|
||||||
setActiveThreadIndex(threadIndex);
|
|
||||||
setIsVisible(true);
|
|
||||||
});
|
|
||||||
}, [getMessageThreadWithIndex]);
|
|
||||||
|
|
||||||
const closeThread = useCallback((threadIndex: number) =>
|
|
||||||
{
|
|
||||||
setHiddenThreadIndexes(prevValue =>
|
|
||||||
{
|
|
||||||
const values = [...prevValue];
|
|
||||||
|
|
||||||
if(values.indexOf(threadIndex) === -1) values.push(threadIndex);
|
|
||||||
|
|
||||||
return values;
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
const linkTracker: ILinkEventTracker = {
|
const linkTracker: ILinkEventTracker = {
|
||||||
linkReceived,
|
linkReceived: (url: string) =>
|
||||||
eventUrlPrefix: 'friends/messenger/'
|
{
|
||||||
|
const parts = url.split('/');
|
||||||
|
|
||||||
|
if(parts.length === 2)
|
||||||
|
{
|
||||||
|
if(parts[1] === 'open')
|
||||||
|
{
|
||||||
|
setIsVisible(true);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const thread = getMessageThread(parseInt(parts[1]));
|
||||||
|
|
||||||
|
if(!thread) return;
|
||||||
|
|
||||||
|
BatchUpdates(() =>
|
||||||
|
{
|
||||||
|
setActiveThread(thread);
|
||||||
|
setIsVisible(true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
eventUrlPrefix: 'friends-messenger/'
|
||||||
};
|
};
|
||||||
|
|
||||||
AddEventLinkTracker(linkTracker);
|
AddEventLinkTracker(linkTracker);
|
||||||
|
|
||||||
return () => RemoveLinkEventTracker(linkTracker);
|
return () => RemoveLinkEventTracker(linkTracker);
|
||||||
}, [linkReceived]);
|
}, [ getMessageThread, setActiveThread ]);
|
||||||
|
|
||||||
|
// useEffect(() =>
|
||||||
|
// {
|
||||||
|
// if(!isVisible || activeThread || !visibleThreads || !visibleThreads.length) return;
|
||||||
|
|
||||||
|
// setActiveThread(visibleThreads[0]);
|
||||||
|
// }, [ isVisible, visibleThreads, activeThread, setActiveThread ]);
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
if(!isVisible) return;
|
if(!isVisible || !activeThread) return;
|
||||||
|
|
||||||
if(activeThreadIndex === -1) setActiveThreadIndex(0);
|
messagesBox.current.scrollTop = messagesBox.current.scrollHeight;
|
||||||
}, [isVisible, activeThreadIndex]);
|
}, [ isVisible, activeThread ]);
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
if(hiddenThreadIndexes.indexOf(activeThreadIndex) >= 0) setActiveThreadIndex(0);
|
|
||||||
}, [activeThreadIndex, hiddenThreadIndexes]);
|
|
||||||
|
|
||||||
useEffect(() =>
|
|
||||||
{
|
|
||||||
if(!isVisible || (activeThreadIndex === -1)) return;
|
|
||||||
|
|
||||||
const activeThread = messageThreads[activeThreadIndex];
|
|
||||||
|
|
||||||
if(!activeThread) return;
|
if(!activeThread) return;
|
||||||
|
|
||||||
if(activeThread.unread)
|
return () =>
|
||||||
{
|
{
|
||||||
messagesBox.current.scrollTop = messagesBox.current.scrollHeight;
|
console.log('set last thread id', activeThread.threadId);
|
||||||
activeThread.setRead();
|
setLastThreadId(activeThread.threadId);
|
||||||
setUpdateValue({});
|
|
||||||
}
|
}
|
||||||
}, [isVisible, messageThreads, activeThreadIndex]);
|
}, [ activeThread ]);
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
if(!visibleThreads.length)
|
return () =>
|
||||||
{
|
{
|
||||||
setIsVisible(false);
|
console.log('clear thread')
|
||||||
|
setActiveThread(null);
|
||||||
DispatchUiEvent(new FriendsMessengerIconEvent(FriendsMessengerIconEvent.UPDATE_ICON, FriendsMessengerIconEvent.HIDE_ICON));
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
}, [ setActiveThread ]);
|
||||||
let isUnread = false;
|
|
||||||
|
|
||||||
for(const thread of visibleThreads)
|
|
||||||
{
|
|
||||||
if(thread.unreadCount > 0)
|
|
||||||
{
|
|
||||||
isUnread = true;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(isUnread) PlaySound(SoundNames.MESSENGER_MESSAGE_RECEIVED);
|
|
||||||
|
|
||||||
DispatchUiEvent(new FriendsMessengerIconEvent(FriendsMessengerIconEvent.UPDATE_ICON, isUnread ? FriendsMessengerIconEvent.UNREAD_ICON : FriendsMessengerIconEvent.SHOW_ICON));
|
|
||||||
}, [visibleThreads, updateValue]);
|
|
||||||
|
|
||||||
if(!isVisible) return null;
|
if(!isVisible) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NitroCardView className="nitro-friends-messenger" uniqueKey="nitro-friends-messenger" theme="primary-slim">
|
<NitroCardView className="nitro-friends-messenger" uniqueKey="nitro-friends-messenger" theme="primary-slim">
|
||||||
<NitroCardHeaderView headerText={LocalizeText('messenger.window.title', ['OPEN_CHAT_COUNT'], [visibleThreads.length.toString()])} onCloseClick={event => setIsVisible(false)} />
|
<NitroCardHeaderView headerText={ LocalizeText('messenger.window.title', [ 'OPEN_CHAT_COUNT' ], [ visibleThreads.length.toString() ]) } onCloseClick={ event => setIsVisible(false) } />
|
||||||
<NitroCardContentView>
|
<NitroCardContentView>
|
||||||
<Grid overflow="hidden">
|
<Grid overflow="hidden">
|
||||||
<Column size={ 4 }>
|
<Column size={ 4 }>
|
||||||
<Text bold>{ LocalizeText('toolbar.icon.label.messenger') }</Text>
|
<Text bold>{ LocalizeText('toolbar.icon.label.messenger') }</Text>
|
||||||
<Column fullHeight overflow="auto">
|
<Column fullHeight overflow="auto">
|
||||||
{ visibleThreads && (visibleThreads.length > 0) && visibleThreads.map((thread, index) =>
|
{ visibleThreads && (visibleThreads.length > 0) && visibleThreads.map(thread =>
|
||||||
{
|
{
|
||||||
const messageThreadIndex = messageThreads.indexOf(thread);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LayoutGridItem key={ index } itemActive={ (activeThreadIndex === messageThreadIndex) } onClick={ event => setActiveThreadIndex(messageThreadIndex) }>
|
<LayoutGridItem key={ thread.threadId } itemActive={ (activeThread === thread) } onClick={ event => setActiveThread(thread) }>
|
||||||
{ thread.unread &&
|
{ thread.unread &&
|
||||||
<LayoutItemCountView count={ thread.unreadCount } /> }
|
<LayoutItemCountView count={ thread.unreadCount } /> }
|
||||||
<Flex fullWidth alignItems="center" gap={ 1 }>
|
<Flex fullWidth alignItems="center" gap={ 1 }>
|
||||||
@ -293,9 +135,9 @@ export const FriendsMessengerView: FC<{}> = props =>
|
|||||||
</Column>
|
</Column>
|
||||||
</Column>
|
</Column>
|
||||||
<Column size={ 8 } overflow="hidden">
|
<Column size={ 8 } overflow="hidden">
|
||||||
{ visibleThreads && (visibleThreads.length > 0) && (activeThreadIndex >= 0) &&
|
{ activeThread &&
|
||||||
<>
|
<>
|
||||||
<Text bold center>{ LocalizeText('messenger.window.separator', [ 'FRIEND_NAME' ], [ messageThreads[activeThreadIndex].participant.name ]) }</Text>
|
<Text bold center>{ LocalizeText('messenger.window.separator', [ 'FRIEND_NAME' ], [ activeThread.participant.name ]) }</Text>
|
||||||
<Flex alignItems="center" justifyContent="between" gap={ 1 }>
|
<Flex alignItems="center" justifyContent="between" gap={ 1 }>
|
||||||
<Flex gap={ 1 }>
|
<Flex gap={ 1 }>
|
||||||
<ButtonGroup>
|
<ButtonGroup>
|
||||||
@ -307,21 +149,21 @@ export const FriendsMessengerView: FC<{}> = props =>
|
|||||||
</Button>
|
</Button>
|
||||||
</ButtonGroup>
|
</ButtonGroup>
|
||||||
<Button variant="danger" onClick={ openProfile }>
|
<Button variant="danger" onClick={ openProfile }>
|
||||||
{LocalizeText('messenger.window.button.report')}
|
{ LocalizeText('messenger.window.button.report') }
|
||||||
</Button>
|
</Button>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Button onClick={ event => closeThread(activeThreadIndex) }>
|
<Button onClick={ event => closeThread(activeThread.threadId) }>
|
||||||
<FontAwesomeIcon icon="times" />
|
<FontAwesomeIcon icon="times" />
|
||||||
</Button>
|
</Button>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Column fit className="bg-muted p-2 rounded chat-messages">
|
<Column fit className="bg-muted p-2 rounded chat-messages">
|
||||||
<Column innerRef={ messagesBox } overflow="auto">
|
<Column innerRef={ messagesBox } overflow="auto">
|
||||||
<FriendsMessengerThreadView thread={ messageThreads[activeThreadIndex] } />
|
<FriendsMessengerThreadView thread={ activeThread } />
|
||||||
</Column>
|
</Column>
|
||||||
</Column>
|
</Column>
|
||||||
<Flex gap={ 1 }>
|
<Flex gap={ 1 }>
|
||||||
<input type="text" className="form-control form-control-sm" maxLength={ 255 } placeholder={ LocalizeText('messenger.window.input.default', [ 'FRIEND_NAME' ], [ messageThreads[activeThreadIndex].participant.name ]) } value={ messageText } onChange={ event => setMessageText(event.target.value) } onKeyDown={ onKeyDown } />
|
<input type="text" className="form-control form-control-sm" maxLength={ 255 } placeholder={ LocalizeText('messenger.window.input.default', [ 'FRIEND_NAME' ], [ activeThread.participant.name ]) } value={ messageText } onChange={ event => setMessageText(event.target.value) } onKeyDown={ onKeyDown } />
|
||||||
<Button variant="success" onClick={ sendMessage }>
|
<Button variant="success" onClick={ send }>
|
||||||
{ LocalizeText('widgets.chatinput.say') }
|
{ LocalizeText('widgets.chatinput.say') }
|
||||||
</Button>
|
</Button>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { EventDispatcher, IRoomSession, NitroRectangle, RoomGeometry, RoomVariableEnum, Vector3d } from '@nitrots/nitro-renderer';
|
import { EventDispatcher, IRoomSession, NitroRectangle, RoomGeometry, RoomVariableEnum, Vector3d } from '@nitrots/nitro-renderer';
|
||||||
import { FC, useEffect, useRef, useState } from 'react';
|
import { FC, useEffect, useRef, useState } from 'react';
|
||||||
import { DispatchMouseEvent, DispatchTouchEvent, DoorbellWidgetHandler, FriendRequestHandler, FurniChooserWidgetHandler, FurnitureContextMenuWidgetHandler, FurnitureCreditWidgetHandler, FurnitureCustomStackHeightWidgetHandler, FurnitureDimmerWidgetHandler, FurnitureExternalImageWidgetHandler, FurnitureInternalLinkHandler, FurnitureMannequinWidgetHandler, FurniturePresentWidgetHandler, FurnitureRoomLinkHandler, FurnitureYoutubeDisplayWidgetHandler, GetNitroInstance, GetRoomEngine, InitializeRoomInstanceRenderingCanvas, IRoomWidgetHandlerManager, PollWidgetHandler, RoomWidgetAvatarInfoHandler, RoomWidgetChatHandler, RoomWidgetChatInputHandler, RoomWidgetHandlerManager, RoomWidgetInfostandHandler, RoomWidgetRoomToolsHandler, RoomWidgetUpdateRoomViewEvent, UserChooserWidgetHandler, WordQuizWidgetHandler } from '../../api';
|
import { DispatchMouseEvent, DispatchTouchEvent, DoorbellWidgetHandler, FurniChooserWidgetHandler, FurnitureContextMenuWidgetHandler, FurnitureCreditWidgetHandler, FurnitureCustomStackHeightWidgetHandler, FurnitureDimmerWidgetHandler, FurnitureExternalImageWidgetHandler, FurnitureInternalLinkHandler, FurnitureMannequinWidgetHandler, FurniturePresentWidgetHandler, FurnitureRoomLinkHandler, FurnitureYoutubeDisplayWidgetHandler, GetNitroInstance, GetRoomEngine, InitializeRoomInstanceRenderingCanvas, IRoomWidgetHandlerManager, PollWidgetHandler, RoomWidgetAvatarInfoHandler, RoomWidgetChatHandler, RoomWidgetChatInputHandler, RoomWidgetHandlerManager, RoomWidgetInfostandHandler, RoomWidgetRoomToolsHandler, RoomWidgetUpdateRoomViewEvent, UserChooserWidgetHandler, WordQuizWidgetHandler } from '../../api';
|
||||||
import { Base } from '../../common';
|
import { Base } from '../../common';
|
||||||
import { RoomColorView } from './RoomColorView';
|
import { RoomColorView } from './RoomColorView';
|
||||||
import { RoomContextProvider } from './RoomContext';
|
import { RoomContextProvider } from './RoomContext';
|
||||||
@ -41,7 +41,6 @@ export const RoomView: FC<RoomViewProps> = props =>
|
|||||||
widgetHandlerManager.registerHandler(new DoorbellWidgetHandler());
|
widgetHandlerManager.registerHandler(new DoorbellWidgetHandler());
|
||||||
widgetHandlerManager.registerHandler(new WordQuizWidgetHandler());
|
widgetHandlerManager.registerHandler(new WordQuizWidgetHandler());
|
||||||
widgetHandlerManager.registerHandler(new PollWidgetHandler());
|
widgetHandlerManager.registerHandler(new PollWidgetHandler());
|
||||||
widgetHandlerManager.registerHandler(new FriendRequestHandler());
|
|
||||||
|
|
||||||
widgetHandlerManager.registerHandler(new FurniChooserWidgetHandler());
|
widgetHandlerManager.registerHandler(new FurniChooserWidgetHandler());
|
||||||
widgetHandlerManager.registerHandler(new FurnitureContextMenuWidgetHandler());
|
widgetHandlerManager.registerHandler(new FurnitureContextMenuWidgetHandler());
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import { RoomEngineEvent, RoomEngineObjectEvent, RoomEngineRoomAdEvent, RoomEngineTriggerWidgetEvent, RoomEngineUseProductEvent, RoomId, RoomObjectCategory, RoomObjectOperationType, RoomObjectVariable, RoomSessionChatEvent, RoomSessionDanceEvent, RoomSessionDimmerPresetsEvent, RoomSessionDoorbellEvent, RoomSessionErrorMessageEvent, RoomSessionEvent, RoomSessionFavoriteGroupUpdateEvent, RoomSessionFriendRequestEvent, RoomSessionPetInfoUpdateEvent, RoomSessionPetStatusUpdateEvent, RoomSessionPollEvent, RoomSessionPresentEvent, RoomSessionUserBadgesEvent, RoomSessionUserFigureUpdateEvent, RoomSessionWordQuizEvent, RoomZoomEvent } from '@nitrots/nitro-renderer';
|
import { RoomEngineEvent, RoomEngineObjectEvent, RoomEngineRoomAdEvent, RoomEngineTriggerWidgetEvent, RoomEngineUseProductEvent, RoomId, RoomObjectCategory, RoomObjectOperationType, RoomObjectVariable, RoomSessionChatEvent, RoomSessionDanceEvent, RoomSessionDimmerPresetsEvent, RoomSessionDoorbellEvent, RoomSessionErrorMessageEvent, RoomSessionEvent, RoomSessionFavoriteGroupUpdateEvent, RoomSessionPetInfoUpdateEvent, RoomSessionPetStatusUpdateEvent, RoomSessionPollEvent, RoomSessionPresentEvent, RoomSessionUserBadgesEvent, RoomSessionUserFigureUpdateEvent, RoomSessionWordQuizEvent, RoomZoomEvent } from '@nitrots/nitro-renderer';
|
||||||
import { FC, useCallback } from 'react';
|
import { FC, useCallback } from 'react';
|
||||||
import { CanManipulateFurniture, GetRoomEngine, GetSessionDataManager, IsFurnitureSelectionDisabled, LocalizeText, NotificationAlertType, NotificationUtilities, ProcessRoomObjectOperation, RoomWidgetFurniToWidgetMessage, RoomWidgetUpdateRoomEngineEvent, RoomWidgetUpdateRoomObjectEvent } from '../../../api';
|
import { CanManipulateFurniture, GetRoomEngine, GetSessionDataManager, IsFurnitureSelectionDisabled, LocalizeText, NotificationAlertType, NotificationUtilities, ProcessRoomObjectOperation, RoomWidgetFurniToWidgetMessage, RoomWidgetUpdateRoomEngineEvent, RoomWidgetUpdateRoomObjectEvent } from '../../../api';
|
||||||
import { FriendRequestEvent } from '../../../events';
|
import { UseRoomEngineEvent, UseRoomSessionManagerEvent } from '../../../hooks';
|
||||||
import { UseRoomEngineEvent, UseRoomSessionManagerEvent, UseUiEvent } from '../../../hooks';
|
|
||||||
import { useRoomContext } from '../RoomContext';
|
import { useRoomContext } from '../RoomContext';
|
||||||
import { AvatarInfoWidgetView } from './avatar-info/AvatarInfoWidgetView';
|
import { AvatarInfoWidgetView } from './avatar-info/AvatarInfoWidgetView';
|
||||||
import { ChatInputView } from './chat-input/ChatInputView';
|
import { ChatInputView } from './chat-input/ChatInputView';
|
||||||
@ -269,7 +268,6 @@ export const RoomWidgetsView: FC<{}> = props =>
|
|||||||
UseRoomSessionManagerEvent(RoomSessionDoorbellEvent.RSDE_REJECTED, onRoomSessionEvent);
|
UseRoomSessionManagerEvent(RoomSessionDoorbellEvent.RSDE_REJECTED, onRoomSessionEvent);
|
||||||
UseRoomSessionManagerEvent(RoomSessionDoorbellEvent.RSDE_ACCEPTED, onRoomSessionEvent);
|
UseRoomSessionManagerEvent(RoomSessionDoorbellEvent.RSDE_ACCEPTED, onRoomSessionEvent);
|
||||||
UseRoomSessionManagerEvent(RoomSessionDimmerPresetsEvent.ROOM_DIMMER_PRESETS, onRoomSessionEvent);
|
UseRoomSessionManagerEvent(RoomSessionDimmerPresetsEvent.ROOM_DIMMER_PRESETS, onRoomSessionEvent);
|
||||||
UseRoomSessionManagerEvent(RoomSessionFriendRequestEvent.RSFRE_FRIEND_REQUEST, onRoomSessionEvent);
|
|
||||||
UseRoomSessionManagerEvent(RoomSessionPresentEvent.RSPE_PRESENT_OPENED, onRoomSessionEvent);
|
UseRoomSessionManagerEvent(RoomSessionPresentEvent.RSPE_PRESENT_OPENED, onRoomSessionEvent);
|
||||||
UseRoomSessionManagerEvent(RoomSessionPetInfoUpdateEvent.PET_INFO, onRoomSessionEvent);
|
UseRoomSessionManagerEvent(RoomSessionPetInfoUpdateEvent.PET_INFO, onRoomSessionEvent);
|
||||||
UseRoomSessionManagerEvent(RoomSessionWordQuizEvent.ANSWERED, onRoomSessionEvent);
|
UseRoomSessionManagerEvent(RoomSessionWordQuizEvent.ANSWERED, onRoomSessionEvent);
|
||||||
@ -278,8 +276,6 @@ export const RoomWidgetsView: FC<{}> = props =>
|
|||||||
UseRoomSessionManagerEvent(RoomSessionPollEvent.OFFER, onRoomSessionEvent);
|
UseRoomSessionManagerEvent(RoomSessionPollEvent.OFFER, onRoomSessionEvent);
|
||||||
UseRoomSessionManagerEvent(RoomSessionPollEvent.ERROR, onRoomSessionEvent);
|
UseRoomSessionManagerEvent(RoomSessionPollEvent.ERROR, onRoomSessionEvent);
|
||||||
UseRoomSessionManagerEvent(RoomSessionPollEvent.CONTENT, onRoomSessionEvent);
|
UseRoomSessionManagerEvent(RoomSessionPollEvent.CONTENT, onRoomSessionEvent);
|
||||||
UseUiEvent(FriendRequestEvent.ACCEPTED, onRoomSessionEvent);
|
|
||||||
UseUiEvent(FriendRequestEvent.DECLINED, onRoomSessionEvent);
|
|
||||||
|
|
||||||
const onRoomSessionErrorMessageEvent = useCallback((event: RoomSessionErrorMessageEvent) =>
|
const onRoomSessionErrorMessageEvent = useCallback((event: RoomSessionErrorMessageEvent) =>
|
||||||
{
|
{
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { RoomControllerLevel, RoomObjectCategory, RoomObjectVariable } from '@nitrots/nitro-renderer';
|
import { RoomControllerLevel, RoomObjectCategory, RoomObjectVariable } from '@nitrots/nitro-renderer';
|
||||||
import { FC, useCallback, useEffect, useMemo, useState } from 'react';
|
import { FC, useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import { GetOwnRoomObject, GetUserProfile, LocalizeText, RoomWidgetMessage, RoomWidgetUpdateInfostandUserEvent, RoomWidgetUserActionMessage } from '../../../../api';
|
import { CreateLinkEvent, GetOwnRoomObject, GetUserProfile, LocalizeText, RoomWidgetMessage, RoomWidgetUpdateInfostandUserEvent, RoomWidgetUserActionMessage } from '../../../../api';
|
||||||
import { Base, Flex } from '../../../../common';
|
import { Base, Flex } from '../../../../common';
|
||||||
import { BatchUpdates } from '../../../../hooks';
|
import { BatchUpdates, useFriends } from '../../../../hooks';
|
||||||
import { useRoomContext } from '../../RoomContext';
|
import { useRoomContext } from '../../RoomContext';
|
||||||
import { ContextMenuHeaderView } from '../context-menu/ContextMenuHeaderView';
|
import { ContextMenuHeaderView } from '../context-menu/ContextMenuHeaderView';
|
||||||
import { ContextMenuListItemView } from '../context-menu/ContextMenuListItemView';
|
import { ContextMenuListItemView } from '../context-menu/ContextMenuListItemView';
|
||||||
@ -28,6 +28,7 @@ export const AvatarInfoWidgetAvatarView: FC<AvatarInfoWidgetAvatarViewProps> = p
|
|||||||
const { userData = null, close = null } = props;
|
const { userData = null, close = null } = props;
|
||||||
const [ mode, setMode ] = useState(MODE_NORMAL);
|
const [ mode, setMode ] = useState(MODE_NORMAL);
|
||||||
const [ respectsLeft, setRespectsLeft ] = useState(0);
|
const [ respectsLeft, setRespectsLeft ] = useState(0);
|
||||||
|
const { canRequestFriend = null } = useFriends();
|
||||||
const { widgetHandler = null } = useRoomContext();
|
const { widgetHandler = null } = useRoomContext();
|
||||||
|
|
||||||
const isShowGiveRights = useMemo(() =>
|
const isShowGiveRights = useMemo(() =>
|
||||||
@ -107,8 +108,7 @@ export const AvatarInfoWidgetAvatarView: FC<AvatarInfoWidgetAvatarViewProps> = p
|
|||||||
messageType = RoomWidgetUserActionMessage.WHISPER_USER;
|
messageType = RoomWidgetUserActionMessage.WHISPER_USER;
|
||||||
break;
|
break;
|
||||||
case 'friend':
|
case 'friend':
|
||||||
//userData.canBeAskedAsFriend = false;
|
CreateLinkEvent(`friends/request/${ userData.webID }/${ userData.name }`);
|
||||||
messageType = RoomWidgetUserActionMessage.SEND_FRIEND_REQUEST;
|
|
||||||
break;
|
break;
|
||||||
case 'relationship':
|
case 'relationship':
|
||||||
hideMenu = false;
|
hideMenu = false;
|
||||||
@ -222,7 +222,7 @@ export const AvatarInfoWidgetAvatarView: FC<AvatarInfoWidgetAvatarViewProps> = p
|
|||||||
</ContextMenuHeaderView>
|
</ContextMenuHeaderView>
|
||||||
{ (mode === MODE_NORMAL) &&
|
{ (mode === MODE_NORMAL) &&
|
||||||
<>
|
<>
|
||||||
{ userData.canBeAskedAsFriend &&
|
{ canRequestFriend(userData.webID) &&
|
||||||
<ContextMenuListItemView onClick={ event => processAction('friend') }>
|
<ContextMenuListItemView onClick={ event => processAction('friend') }>
|
||||||
{ LocalizeText('infostand.button.friend') }
|
{ LocalizeText('infostand.button.friend') }
|
||||||
</ContextMenuListItemView> }
|
</ContextMenuListItemView> }
|
||||||
@ -236,7 +236,7 @@ export const AvatarInfoWidgetAvatarView: FC<AvatarInfoWidgetAvatarViewProps> = p
|
|||||||
<ContextMenuListItemView onClick={ event => processAction('respect') }>
|
<ContextMenuListItemView onClick={ event => processAction('respect') }>
|
||||||
{ LocalizeText('infostand.button.respect', [ 'count' ], [ respectsLeft.toString() ]) }
|
{ LocalizeText('infostand.button.respect', [ 'count' ], [ respectsLeft.toString() ]) }
|
||||||
</ContextMenuListItemView>}
|
</ContextMenuListItemView>}
|
||||||
{ !userData.canBeAskedAsFriend &&
|
{ !canRequestFriend(userData.webID) &&
|
||||||
<ContextMenuListItemView onClick={ event => processAction('relationship') }>
|
<ContextMenuListItemView onClick={ event => processAction('relationship') }>
|
||||||
{LocalizeText('infostand.link.relationship')}
|
{LocalizeText('infostand.link.relationship')}
|
||||||
<FontAwesomeIcon icon="chevron-right" className="right" />
|
<FontAwesomeIcon icon="chevron-right" className="right" />
|
||||||
|
@ -1,44 +0,0 @@
|
|||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
||||||
import { FC } from 'react';
|
|
||||||
import { LocalizeText, RoomWidgetFriendRequestMessage } from '../../../../api';
|
|
||||||
import { Base, Button, Column, Flex, Text } from '../../../../common';
|
|
||||||
import { useRoomContext } from '../../RoomContext';
|
|
||||||
import { UserLocationView } from '../user-location/UserLocationView';
|
|
||||||
|
|
||||||
interface FriendRequestDialogViewProps
|
|
||||||
{
|
|
||||||
requestId: number;
|
|
||||||
userId: number;
|
|
||||||
userName: string;
|
|
||||||
close: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const FriendRequestDialogView: FC<FriendRequestDialogViewProps> = props =>
|
|
||||||
{
|
|
||||||
const { requestId = -1, userId = -1, userName = null, close = null } = props;
|
|
||||||
const { widgetHandler = null } = useRoomContext();
|
|
||||||
|
|
||||||
const respond = (flag: boolean) =>
|
|
||||||
{
|
|
||||||
widgetHandler.processWidgetMessage(new RoomWidgetFriendRequestMessage((flag ? RoomWidgetFriendRequestMessage.ACCEPT : RoomWidgetFriendRequestMessage.DECLINE), requestId));
|
|
||||||
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<UserLocationView userId={ userId }>
|
|
||||||
<Base className="nitro-friend-request-dialog nitro-context-menu p-2">
|
|
||||||
<Column>
|
|
||||||
<Flex alignItems="center" justifyContent="between" gap={ 2 }>
|
|
||||||
<Text variant="white" fontSize={ 6 }>{ LocalizeText('widget.friendrequest.from', [ 'username' ], [ userName ]) }</Text>
|
|
||||||
<FontAwesomeIcon icon="times" className="cursor-pointer" onClick={ close } />
|
|
||||||
</Flex>
|
|
||||||
<Flex justifyContent="end" gap={ 1 }>
|
|
||||||
<Button variant="danger" onClick={ event => respond(false) }>{ LocalizeText('widget.friendrequest.decline') }</Button>
|
|
||||||
<Button variant="success" onClick={ event => respond(true) }>{ LocalizeText('widget.friendrequest.accept') }</Button>
|
|
||||||
</Flex>
|
|
||||||
</Column>
|
|
||||||
</Base>
|
|
||||||
</UserLocationView>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,69 +1,123 @@
|
|||||||
import { FC, useCallback, useState } from 'react';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { RoomWidgetUpdateFriendRequestEvent } from '../../../../api';
|
import { RoomObjectCategory, RoomObjectUserType } from '@nitrots/nitro-renderer';
|
||||||
import { UseEventDispatcherHook } from '../../../../hooks';
|
import { FC, useCallback, useEffect, useState } from 'react';
|
||||||
|
import { LocalizeText, MessengerRequest, RoomWidgetUpdateRoomObjectEvent } from '../../../../api';
|
||||||
|
import { Base, Button, Column, Flex, Text } from '../../../../common';
|
||||||
|
import { UseEventDispatcherHook, useFriends } from '../../../../hooks';
|
||||||
import { useRoomContext } from '../../RoomContext';
|
import { useRoomContext } from '../../RoomContext';
|
||||||
import { FriendRequestDialogView } from './FriendRequestDialogView';
|
import { ObjectLocationView } from '../object-location/ObjectLocationView';
|
||||||
|
|
||||||
export const FriendRequestWidgetView: FC<{}> = props =>
|
export const FriendRequestWidgetView: FC<{}> = props =>
|
||||||
{
|
{
|
||||||
const [ friendRequests, setFriendRequests ] = useState<{ requestId: number, userId: number, userName: string }[]>([]);
|
const [ displayedRequests, setDisplayedRequests ] = useState<{ roomIndex: number, request: MessengerRequest }[]>([]);
|
||||||
const { eventDispatcher = null } = useRoomContext();
|
const [ dismissedRequestIds, setDismissedRequestIds ] = useState<number[]>([]);
|
||||||
|
const { roomSession = null, eventDispatcher = null } = useRoomContext();
|
||||||
|
const { requests = [], requestResponse = null } = useFriends();
|
||||||
|
|
||||||
const showFriendRequest = useCallback((requestId: number, userId: number, userName: string) =>
|
const hideFriendRequest = (userId: number) =>
|
||||||
{
|
{
|
||||||
const index = friendRequests.findIndex(value => (value.userId === userId));
|
setDismissedRequestIds(prevValue =>
|
||||||
|
|
||||||
if(index >= 0) return;
|
|
||||||
|
|
||||||
setFriendRequests(prevValue =>
|
|
||||||
{
|
{
|
||||||
|
if(prevValue.indexOf(userId) >= 0) return prevValue;
|
||||||
|
|
||||||
const newValue = [ ...prevValue ];
|
const newValue = [ ...prevValue ];
|
||||||
|
|
||||||
newValue.push({ requestId, userId, userName });
|
newValue.push(userId);
|
||||||
|
|
||||||
return newValue;
|
return newValue;
|
||||||
});
|
});
|
||||||
}, [ friendRequests ]);
|
}
|
||||||
|
|
||||||
const hideFriendRequest = useCallback((requestId: number) =>
|
const onRoomWidgetUpdateRoomObjectEvent = useCallback((event: RoomWidgetUpdateRoomObjectEvent) =>
|
||||||
{
|
{
|
||||||
const index = friendRequests.findIndex(value => (value.requestId === requestId));
|
if(event.category !== RoomObjectCategory.UNIT) return;
|
||||||
|
|
||||||
|
const userData = roomSession.userDataManager.getUserDataByIndex(event.id);
|
||||||
|
|
||||||
if(index === -1) return;
|
if(userData && (userData.type === RoomObjectUserType.getTypeNumber(RoomObjectUserType.USER)))
|
||||||
|
|
||||||
setFriendRequests(prevValue =>
|
|
||||||
{
|
|
||||||
const newValue = [ ...prevValue ];
|
|
||||||
|
|
||||||
newValue.splice(index, 1);
|
|
||||||
|
|
||||||
return newValue;
|
|
||||||
});
|
|
||||||
}, [ friendRequests ]);
|
|
||||||
|
|
||||||
const onRoomWidgetUpdateFriendRequestEvent = useCallback((event: RoomWidgetUpdateFriendRequestEvent) =>
|
|
||||||
{
|
|
||||||
switch(event.type)
|
|
||||||
{
|
{
|
||||||
case RoomWidgetUpdateFriendRequestEvent.SHOW_FRIEND_REQUEST:
|
if(event.type === RoomWidgetUpdateRoomObjectEvent.USER_ADDED)
|
||||||
showFriendRequest(event.requestId, event.userId, event.userName);
|
{
|
||||||
return;
|
const request = requests.find(request => (request.requesterUserId === userData.webID));
|
||||||
case RoomWidgetUpdateFriendRequestEvent.HIDE_FRIEND_REQUEST:
|
|
||||||
hideFriendRequest(event.requestId);
|
if(!request || displayedRequests.find(request => (request.request.requesterUserId === userData.webID))) return;
|
||||||
return;
|
|
||||||
|
const newValue = [ ...displayedRequests ];
|
||||||
|
|
||||||
|
newValue.push({ roomIndex: userData.roomIndex, request });
|
||||||
|
|
||||||
|
setDisplayedRequests(newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}, [ showFriendRequest, hideFriendRequest ]);
|
|
||||||
|
|
||||||
UseEventDispatcherHook(RoomWidgetUpdateFriendRequestEvent.SHOW_FRIEND_REQUEST, eventDispatcher, onRoomWidgetUpdateFriendRequestEvent);
|
if(event.type === RoomWidgetUpdateRoomObjectEvent.USER_REMOVED)
|
||||||
UseEventDispatcherHook(RoomWidgetUpdateFriendRequestEvent.HIDE_FRIEND_REQUEST, eventDispatcher, onRoomWidgetUpdateFriendRequestEvent);
|
{
|
||||||
|
const index = displayedRequests.findIndex(request => (request.roomIndex === event.id));
|
||||||
|
|
||||||
if(!friendRequests.length) return null;
|
if(index === -1) return;
|
||||||
|
|
||||||
|
const newValue = [ ...displayedRequests ];
|
||||||
|
|
||||||
|
newValue.splice(index, 1);
|
||||||
|
|
||||||
|
setDisplayedRequests(newValue);
|
||||||
|
}
|
||||||
|
}, [ roomSession, requests, displayedRequests ]);
|
||||||
|
|
||||||
|
UseEventDispatcherHook(RoomWidgetUpdateRoomObjectEvent.USER_ADDED, eventDispatcher, onRoomWidgetUpdateRoomObjectEvent);
|
||||||
|
UseEventDispatcherHook(RoomWidgetUpdateRoomObjectEvent.USER_REMOVED, eventDispatcher, onRoomWidgetUpdateRoomObjectEvent);
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
if(!requests || !requests.length) return;
|
||||||
|
|
||||||
|
const newDisplayedRequests: { roomIndex: number, request: MessengerRequest }[] = [];
|
||||||
|
|
||||||
|
for(const request of requests)
|
||||||
|
{
|
||||||
|
const userData = roomSession.userDataManager.getUserData(request.requesterUserId);
|
||||||
|
|
||||||
|
if(!userData) continue;
|
||||||
|
|
||||||
|
newDisplayedRequests.push({ roomIndex: userData.roomIndex, request });
|
||||||
|
}
|
||||||
|
|
||||||
|
setDisplayedRequests(newDisplayedRequests);
|
||||||
|
}, [ roomSession, requests ]);
|
||||||
|
|
||||||
|
if(!requests.length) return null;
|
||||||
|
|
||||||
|
const FriendRequestDialogView: FC<{ roomIndex: number, request: MessengerRequest }> = props =>
|
||||||
|
{
|
||||||
|
const { roomIndex = -1, request = null } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ObjectLocationView objectId={ roomIndex } category={ RoomObjectCategory.UNIT }>
|
||||||
|
<Base className="nitro-friend-request-dialog nitro-context-menu p-2">
|
||||||
|
<Column>
|
||||||
|
<Flex alignItems="center" justifyContent="between" gap={ 2 }>
|
||||||
|
<Text variant="white" fontSize={ 6 }>{ LocalizeText('widget.friendrequest.from', [ 'username' ], [ request.name ]) }</Text>
|
||||||
|
<FontAwesomeIcon icon="times" className="cursor-pointer" onClick={ event => hideFriendRequest(request.requesterUserId) } />
|
||||||
|
</Flex>
|
||||||
|
<Flex justifyContent="end" gap={ 1 }>
|
||||||
|
<Button variant="danger" onClick={ event => requestResponse(request.requesterUserId, false) }>{ LocalizeText('widget.friendrequest.decline') }</Button>
|
||||||
|
<Button variant="success" onClick={ event => requestResponse(request.requesterUserId, true) }>{ LocalizeText('widget.friendrequest.accept') }</Button>
|
||||||
|
</Flex>
|
||||||
|
</Column>
|
||||||
|
</Base>
|
||||||
|
</ObjectLocationView>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{ friendRequests.map((request, index) =>
|
{ displayedRequests.map((request, index) =>
|
||||||
{
|
{
|
||||||
return <FriendRequestDialogView key={ index } { ...request } close={ () => hideFriendRequest(request.userId) } />
|
if(dismissedRequestIds.indexOf(request.request.requesterUserId) >= 0) return null;
|
||||||
|
|
||||||
|
return <FriendRequestDialogView key={ index } roomIndex={ request.roomIndex } request={ request.request } />;
|
||||||
}) }
|
}) }
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
@ -1,19 +1,21 @@
|
|||||||
import { RoomObjectCategory } from '@nitrots/nitro-renderer';
|
import { MouseEventType, RoomObjectCategory } from '@nitrots/nitro-renderer';
|
||||||
import { FC, useEffect } from 'react';
|
import { Dispatch, FC, SetStateAction, useEffect, useRef } from 'react';
|
||||||
import { CreateLinkEvent, GetRoomEngine, GetRoomSession } from '../../api';
|
import { CreateLinkEvent, GetRoomEngine, GetRoomSession, GetSessionDataManager, GetUserProfile } from '../../api';
|
||||||
import { Base, Flex, LayoutItemCountView } from '../../common';
|
import { Base, Flex, LayoutItemCountView } from '../../common';
|
||||||
import { ToolbarViewItems } from './common/ToolbarViewItems';
|
import { GuideToolEvent, UserSettingsUIEvent } from '../../events';
|
||||||
|
import { DispatchUiEvent } from '../../hooks';
|
||||||
|
|
||||||
export interface ToolbarMeViewProps
|
interface ToolbarMeViewProps
|
||||||
{
|
{
|
||||||
useGuideTool: boolean;
|
useGuideTool: boolean;
|
||||||
unseenAchievementCount: number;
|
unseenAchievementCount: number;
|
||||||
handleToolbarItemClick: (item: string) => void;
|
setMeExpanded: Dispatch<SetStateAction<boolean>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ToolbarMeView: FC<ToolbarMeViewProps> = props =>
|
export const ToolbarMeView: FC<ToolbarMeViewProps> = props =>
|
||||||
{
|
{
|
||||||
const { useGuideTool = false, unseenAchievementCount = 0, handleToolbarItemClick = null } = props;
|
const { useGuideTool = false, unseenAchievementCount = 0, setMeExpanded = null, children = null, ...rest } = props;
|
||||||
|
const elementRef = useRef<HTMLDivElement>();
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
@ -24,18 +26,28 @@ export const ToolbarMeView: FC<ToolbarMeViewProps> = props =>
|
|||||||
GetRoomEngine().selectRoomObject(roomSession.roomId, roomSession.ownRoomIndex, RoomObjectCategory.UNIT);
|
GetRoomEngine().selectRoomObject(roomSession.roomId, roomSession.ownRoomIndex, RoomObjectCategory.UNIT);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
const onClick = (event: MouseEvent) => setMeExpanded(false);
|
||||||
|
|
||||||
|
document.addEventListener('click', onClick);
|
||||||
|
|
||||||
|
return () => document.removeEventListener(MouseEventType.MOUSE_CLICK, onClick);
|
||||||
|
}, [ setMeExpanded ]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex alignItems="center" className="nitro-toolbar-me p-2" gap={ 2 }>
|
<Flex innerRef={ elementRef } alignItems="center" className="nitro-toolbar-me p-2" gap={ 2 }>
|
||||||
{ useGuideTool &&
|
{ useGuideTool &&
|
||||||
<Base pointer className="navigation-item icon icon-me-helper-tool" onClick={ event => handleToolbarItemClick(ToolbarViewItems.GUIDE_TOOL_ITEM) } /> }
|
<Base pointer className="navigation-item icon icon-me-helper-tool" onClick={ event => DispatchUiEvent(new GuideToolEvent(GuideToolEvent.TOGGLE_GUIDE_TOOL)) } /> }
|
||||||
<Base pointer className="navigation-item icon icon-me-achievements" onClick={ event => handleToolbarItemClick(ToolbarViewItems.ACHIEVEMENTS_ITEM) }>
|
<Base pointer className="navigation-item icon icon-me-achievements" onClick={ event => CreateLinkEvent('achievements/toggle') }>
|
||||||
{ (unseenAchievementCount > 0) &&
|
{ (unseenAchievementCount > 0) &&
|
||||||
<LayoutItemCountView count={ unseenAchievementCount } /> }
|
<LayoutItemCountView count={ unseenAchievementCount } /> }
|
||||||
</Base>
|
</Base>
|
||||||
<Base pointer className="navigation-item icon icon-me-profile" onClick={ event => handleToolbarItemClick(ToolbarViewItems.PROFILE_ITEM) } />
|
<Base pointer className="navigation-item icon icon-me-profile" onClick={ event => GetUserProfile(GetSessionDataManager().userId) } />
|
||||||
<Base pointer className="navigation-item icon icon-me-rooms" onClick={ event => CreateLinkEvent('navigator/search/myworld_view')} />
|
<Base pointer className="navigation-item icon icon-me-rooms" onClick={ event => CreateLinkEvent('navigator/search/myworld_view')} />
|
||||||
<Base pointer className="navigation-item icon icon-me-clothing" onClick={ event => handleToolbarItemClick(ToolbarViewItems.CLOTHING_ITEM) } />
|
<Base pointer className="navigation-item icon icon-me-clothing" onClick={ event => CreateLinkEvent('avatar-editor/toggle') } />
|
||||||
<Base pointer className="navigation-item icon icon-me-settings" onClick={ event => handleToolbarItemClick(ToolbarViewItems.SETTINGS_ITEM) } />
|
<Base pointer className="navigation-item icon icon-me-settings" onClick={ event => DispatchUiEvent(new UserSettingsUIEvent(UserSettingsUIEvent.TOGGLE_USER_SETTINGS)) } />
|
||||||
|
{ children }
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,12 @@
|
|||||||
import { Dispose, DropBounce, EaseOut, FigureUpdateEvent, JumpBy, Motions, NitroToolbarAnimateIconEvent, PerkAllowancesMessageEvent, PerkEnum, Queue, UserInfoDataParser, UserInfoEvent, Wait } from '@nitrots/nitro-renderer';
|
import { Dispose, DropBounce, EaseOut, FigureUpdateEvent, JumpBy, Motions, NitroToolbarAnimateIconEvent, PerkAllowancesMessageEvent, PerkEnum, Queue, UserInfoDataParser, UserInfoEvent, Wait } from '@nitrots/nitro-renderer';
|
||||||
import { FC, useCallback, useState } from 'react';
|
import { FC, useCallback, useState } from 'react';
|
||||||
import { CreateLinkEvent, GetSessionDataManager, GetUserProfile, OpenMessengerChat, VisitDesktop } from '../../api';
|
import { CreateLinkEvent, GetSessionDataManager, MessengerIconState, OpenMessengerChat, VisitDesktop } from '../../api';
|
||||||
import { Base, Flex, LayoutAvatarImageView, LayoutItemCountView, TransitionAnimation, TransitionAnimationTypes } from '../../common';
|
import { Base, Flex, LayoutAvatarImageView, LayoutItemCountView, TransitionAnimation, TransitionAnimationTypes } from '../../common';
|
||||||
import { AchievementsUIUnseenCountEvent, FriendsEvent, FriendsMessengerIconEvent, FriendsRequestCountEvent, GuideToolEvent, ModToolsEvent, UserSettingsUIEvent } from '../../events';
|
import { AchievementsUIUnseenCountEvent, ModToolsEvent } from '../../events';
|
||||||
import { BatchUpdates, DispatchUiEvent, useInventoryUnseenTracker, UseMessageEventHook, UseRoomEngineEvent, UseUiEvent } from '../../hooks';
|
import { BatchUpdates, DispatchUiEvent, useFriends, useInventoryUnseenTracker, UseMessageEventHook, useMessenger, UseRoomEngineEvent, UseUiEvent } from '../../hooks';
|
||||||
import { ToolbarViewItems } from './common/ToolbarViewItems';
|
|
||||||
import { ToolbarMeView } from './ToolbarMeView';
|
import { ToolbarMeView } from './ToolbarMeView';
|
||||||
|
|
||||||
export interface ToolbarViewProps
|
export const ToolbarView: FC<{ isInRoom: boolean }> = props =>
|
||||||
{
|
|
||||||
isInRoom: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
const CHAT_ICON_HIDDEN: number = 0;
|
|
||||||
const CHAT_ICON_SHOWING: number = 1;
|
|
||||||
const CHAT_ICON_UNREAD: number = 2;
|
|
||||||
|
|
||||||
export const ToolbarView: FC<ToolbarViewProps> = props =>
|
|
||||||
{
|
{
|
||||||
const { isInRoom } = props;
|
const { isInRoom } = props;
|
||||||
|
|
||||||
@ -24,10 +14,10 @@ export const ToolbarView: FC<ToolbarViewProps> = props =>
|
|||||||
const [ userFigure, setUserFigure ] = useState<string>(null);
|
const [ userFigure, setUserFigure ] = useState<string>(null);
|
||||||
const [ isMeExpanded, setMeExpanded ] = useState(false);
|
const [ isMeExpanded, setMeExpanded ] = useState(false);
|
||||||
const [ useGuideTool, setUseGuideTool ] = useState(false);
|
const [ useGuideTool, setUseGuideTool ] = useState(false);
|
||||||
const [ chatIconType, setChatIconType ] = useState(CHAT_ICON_HIDDEN);
|
|
||||||
const [ unseenAchievementCount, setUnseenAchievementCount ] = useState(0);
|
const [ unseenAchievementCount, setUnseenAchievementCount ] = useState(0);
|
||||||
const [ unseenFriendRequestCount, setFriendRequestCount ] = useState(0);
|
|
||||||
const { getFullCount = null } = useInventoryUnseenTracker();
|
const { getFullCount = null } = useInventoryUnseenTracker();
|
||||||
|
const { requests = [] } = useFriends();
|
||||||
|
const { iconState = MessengerIconState.HIDDEN } = useMessenger();
|
||||||
const isMod = GetSessionDataManager().isModerator;
|
const isMod = GetSessionDataManager().isModerator;
|
||||||
|
|
||||||
const onUserInfoEvent = useCallback((event: UserInfoEvent) =>
|
const onUserInfoEvent = useCallback((event: UserInfoEvent) =>
|
||||||
@ -61,13 +51,6 @@ export const ToolbarView: FC<ToolbarViewProps> = props =>
|
|||||||
|
|
||||||
UseMessageEventHook(PerkAllowancesMessageEvent, onPerkAllowancesMessageEvent);
|
UseMessageEventHook(PerkAllowancesMessageEvent, onPerkAllowancesMessageEvent);
|
||||||
|
|
||||||
const onFriendsMessengerIconEvent = useCallback((event: FriendsMessengerIconEvent) =>
|
|
||||||
{
|
|
||||||
setChatIconType(event.iconType);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
UseUiEvent(FriendsMessengerIconEvent.UPDATE_ICON, onFriendsMessengerIconEvent);
|
|
||||||
|
|
||||||
const onAchievementsUIUnseenCountEvent = useCallback((event: AchievementsUIUnseenCountEvent) =>
|
const onAchievementsUIUnseenCountEvent = useCallback((event: AchievementsUIUnseenCountEvent) =>
|
||||||
{
|
{
|
||||||
setUnseenAchievementCount(event.count);
|
setUnseenAchievementCount(event.count);
|
||||||
@ -75,13 +58,6 @@ export const ToolbarView: FC<ToolbarViewProps> = props =>
|
|||||||
|
|
||||||
UseUiEvent(AchievementsUIUnseenCountEvent.UNSEEN_COUNT, onAchievementsUIUnseenCountEvent);
|
UseUiEvent(AchievementsUIUnseenCountEvent.UNSEEN_COUNT, onAchievementsUIUnseenCountEvent);
|
||||||
|
|
||||||
const onFriendsRequestCountEvent = useCallback((event: FriendsRequestCountEvent) =>
|
|
||||||
{
|
|
||||||
setFriendRequestCount(event.count);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
UseUiEvent(FriendsRequestCountEvent.UPDATE_COUNT, onFriendsRequestCountEvent);
|
|
||||||
|
|
||||||
const animationIconToToolbar = useCallback((iconName: string, image: HTMLImageElement, x: number, y: number) =>
|
const animationIconToToolbar = useCallback((iconName: string, image: HTMLImageElement, x: number, y: number) =>
|
||||||
{
|
{
|
||||||
const target = (document.body.getElementsByClassName(iconName)[0] as HTMLElement);
|
const target = (document.body.getElementsByClassName(iconName)[0] as HTMLElement);
|
||||||
@ -123,60 +99,12 @@ export const ToolbarView: FC<ToolbarViewProps> = props =>
|
|||||||
|
|
||||||
UseRoomEngineEvent(NitroToolbarAnimateIconEvent.ANIMATE_ICON, onNitroToolbarAnimateIconEvent);
|
UseRoomEngineEvent(NitroToolbarAnimateIconEvent.ANIMATE_ICON, onNitroToolbarAnimateIconEvent);
|
||||||
|
|
||||||
const handleToolbarItemClick = useCallback((item: string) =>
|
|
||||||
{
|
|
||||||
switch(item)
|
|
||||||
{
|
|
||||||
case ToolbarViewItems.NAVIGATOR_ITEM:
|
|
||||||
CreateLinkEvent('navigator/toggle');
|
|
||||||
return;
|
|
||||||
case ToolbarViewItems.INVENTORY_ITEM:
|
|
||||||
CreateLinkEvent('inventory/toggle');
|
|
||||||
return;
|
|
||||||
case ToolbarViewItems.CATALOG_ITEM:
|
|
||||||
CreateLinkEvent('catalog/toggle');
|
|
||||||
return;
|
|
||||||
case ToolbarViewItems.FRIEND_LIST_ITEM:
|
|
||||||
DispatchUiEvent(new FriendsEvent(FriendsEvent.TOGGLE_FRIEND_LIST));
|
|
||||||
return;
|
|
||||||
case ToolbarViewItems.CAMERA_ITEM:
|
|
||||||
CreateLinkEvent('camera/toggle');
|
|
||||||
return;
|
|
||||||
case ToolbarViewItems.CLOTHING_ITEM:
|
|
||||||
CreateLinkEvent('avatar-editor/toggle');
|
|
||||||
setMeExpanded(false);
|
|
||||||
return;
|
|
||||||
case ToolbarViewItems.MOD_TOOLS_ITEM:
|
|
||||||
DispatchUiEvent(new ModToolsEvent(ModToolsEvent.TOGGLE_MOD_TOOLS));
|
|
||||||
return;
|
|
||||||
case ToolbarViewItems.ACHIEVEMENTS_ITEM:
|
|
||||||
CreateLinkEvent('achievements/toggle');
|
|
||||||
setMeExpanded(false);
|
|
||||||
return;
|
|
||||||
case ToolbarViewItems.PROFILE_ITEM:
|
|
||||||
GetUserProfile(GetSessionDataManager().userId);
|
|
||||||
setMeExpanded(false);
|
|
||||||
return;
|
|
||||||
case ToolbarViewItems.SETTINGS_ITEM:
|
|
||||||
DispatchUiEvent(new UserSettingsUIEvent(UserSettingsUIEvent.TOGGLE_USER_SETTINGS));
|
|
||||||
setMeExpanded(false);
|
|
||||||
return;
|
|
||||||
case ToolbarViewItems.GUIDE_TOOL_ITEM:
|
|
||||||
DispatchUiEvent(new GuideToolEvent(GuideToolEvent.TOGGLE_GUIDE_TOOL));
|
|
||||||
setMeExpanded(false);
|
|
||||||
return;
|
|
||||||
case ToolbarViewItems.FRIEND_CHAT_ITEM:
|
|
||||||
OpenMessengerChat();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const unseenInventoryCount = getFullCount();
|
const unseenInventoryCount = getFullCount();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<TransitionAnimation type={ TransitionAnimationTypes.FADE_IN } inProp={ isMeExpanded } timeout={ 300 }>
|
<TransitionAnimation type={ TransitionAnimationTypes.FADE_IN } inProp={ isMeExpanded } timeout={ 300 }>
|
||||||
<ToolbarMeView useGuideTool={ useGuideTool } unseenAchievementCount={ unseenAchievementCount } handleToolbarItemClick={ handleToolbarItemClick } />
|
<ToolbarMeView useGuideTool={ useGuideTool } unseenAchievementCount={ unseenAchievementCount } setMeExpanded={ setMeExpanded } />
|
||||||
</TransitionAnimation>
|
</TransitionAnimation>
|
||||||
<Flex alignItems="center" justifyContent="between" gap={ 2 } className="nitro-toolbar py-1 px-3">
|
<Flex alignItems="center" justifyContent="between" gap={ 2 } className="nitro-toolbar py-1 px-3">
|
||||||
<Flex gap={ 2 } alignItems="center">
|
<Flex gap={ 2 } alignItems="center">
|
||||||
@ -190,27 +118,27 @@ export const ToolbarView: FC<ToolbarViewProps> = props =>
|
|||||||
<Base pointer className="navigation-item icon icon-habbo" onClick={ event => VisitDesktop() } /> }
|
<Base pointer className="navigation-item icon icon-habbo" onClick={ event => VisitDesktop() } /> }
|
||||||
{ !isInRoom &&
|
{ !isInRoom &&
|
||||||
<Base pointer className="navigation-item icon icon-house" onClick={ event => CreateLinkEvent('navigator/goto/home') } /> }
|
<Base pointer className="navigation-item icon icon-house" onClick={ event => CreateLinkEvent('navigator/goto/home') } /> }
|
||||||
<Base pointer className="navigation-item icon icon-rooms" onClick={ event => handleToolbarItemClick(ToolbarViewItems.NAVIGATOR_ITEM) } />
|
<Base pointer className="navigation-item icon icon-rooms" onClick={ event => CreateLinkEvent('navigator/toggle') } />
|
||||||
<Base pointer className="navigation-item icon icon-catalog" onClick={ event => handleToolbarItemClick(ToolbarViewItems.CATALOG_ITEM) } />
|
<Base pointer className="navigation-item icon icon-catalog" onClick={ event => CreateLinkEvent('catalog/toggle') } />
|
||||||
<Base pointer className="navigation-item icon icon-inventory" onClick={ event => handleToolbarItemClick(ToolbarViewItems.INVENTORY_ITEM) }>
|
<Base pointer className="navigation-item icon icon-inventory" onClick={ event => CreateLinkEvent('inventory/toggle') }>
|
||||||
{ (unseenInventoryCount > 0) &&
|
{ (unseenInventoryCount > 0) &&
|
||||||
<LayoutItemCountView count={ unseenInventoryCount } /> }
|
<LayoutItemCountView count={ unseenInventoryCount } /> }
|
||||||
</Base>
|
</Base>
|
||||||
{ isInRoom &&
|
{ isInRoom &&
|
||||||
<Base pointer className="navigation-item icon icon-camera" onClick={ event => handleToolbarItemClick(ToolbarViewItems.CAMERA_ITEM) } /> }
|
<Base pointer className="navigation-item icon icon-camera" onClick={ event => CreateLinkEvent('camera/toggle') } /> }
|
||||||
{ isMod &&
|
{ isMod &&
|
||||||
<Base pointer className="navigation-item icon icon-modtools" onClick={ event => handleToolbarItemClick(ToolbarViewItems.MOD_TOOLS_ITEM) } /> }
|
<Base pointer className="navigation-item icon icon-modtools" onClick={ event => DispatchUiEvent(new ModToolsEvent(ModToolsEvent.TOGGLE_MOD_TOOLS)) } /> }
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex alignItems="center" id="toolbar-chat-input-container" />
|
<Flex alignItems="center" id="toolbar-chat-input-container" />
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex alignItems="center" gap={ 2 }>
|
<Flex alignItems="center" gap={ 2 }>
|
||||||
<Flex gap={ 2 }>
|
<Flex gap={ 2 }>
|
||||||
<Base pointer className="navigation-item icon icon-friendall" onClick={ event => handleToolbarItemClick(ToolbarViewItems.FRIEND_LIST_ITEM) }>
|
<Base pointer className="navigation-item icon icon-friendall" onClick={ event => CreateLinkEvent('friends/toggle') }>
|
||||||
{ (unseenFriendRequestCount > 0) &&
|
{ (requests.length > 0) &&
|
||||||
<LayoutItemCountView count={ unseenFriendRequestCount } /> }
|
<LayoutItemCountView count={ requests.length } /> }
|
||||||
</Base>
|
</Base>
|
||||||
{ ((chatIconType === CHAT_ICON_SHOWING) || (chatIconType === CHAT_ICON_UNREAD)) &&
|
{ ((iconState === MessengerIconState.SHOW) || (iconState === MessengerIconState.UNREAD)) &&
|
||||||
<Base pointer className={ `navigation-item icon icon-message ${ (chatIconType === CHAT_ICON_UNREAD) && 'is-unseen' }` } onClick={ event => handleToolbarItemClick(ToolbarViewItems.FRIEND_CHAT_ITEM) } /> }
|
<Base pointer className={ `navigation-item icon icon-message ${ (iconState === MessengerIconState.UNREAD) && 'is-unseen' }` } onClick={ event => OpenMessengerChat() } /> }
|
||||||
</Flex>
|
</Flex>
|
||||||
<Base id="toolbar-friend-bar-container" className="d-none d-lg-block" />
|
<Base id="toolbar-friend-bar-container" className="d-none d-lg-block" />
|
||||||
</Flex>
|
</Flex>
|
||||||
|
@ -1,26 +0,0 @@
|
|||||||
import { NitroEvent } from '@nitrots/nitro-renderer';
|
|
||||||
import { MessengerFriend } from '../../components/friends/common/MessengerFriend';
|
|
||||||
|
|
||||||
export class FriendListContentEvent extends NitroEvent
|
|
||||||
{
|
|
||||||
public static FRIEND_LIST_CONTENT: string = 'FLSFRE_FRIEND_LIST_CONTENT';
|
|
||||||
|
|
||||||
private _friends: Map<number, string>;
|
|
||||||
|
|
||||||
constructor(friends: MessengerFriend[])
|
|
||||||
{
|
|
||||||
super(FriendListContentEvent.FRIEND_LIST_CONTENT);
|
|
||||||
|
|
||||||
this._friends = new Map();
|
|
||||||
|
|
||||||
friends.forEach(entry =>
|
|
||||||
{
|
|
||||||
this._friends.set(entry.id, entry.name);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public get friends(): Map<number, string>
|
|
||||||
{
|
|
||||||
return this._friends;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
import { NitroEvent } from '@nitrots/nitro-renderer';
|
|
||||||
|
|
||||||
export class FriendRequestEvent extends NitroEvent
|
|
||||||
{
|
|
||||||
public static ACCEPTED: string = 'FRE_ACCEPTED';
|
|
||||||
public static DECLINED: string = 'FRE_DECLINED';
|
|
||||||
|
|
||||||
private _requestId: number;
|
|
||||||
|
|
||||||
constructor(type: string, requestId: number)
|
|
||||||
{
|
|
||||||
super(type);
|
|
||||||
|
|
||||||
this._requestId = requestId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get requestId(): number
|
|
||||||
{
|
|
||||||
return this._requestId;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
import { NitroEvent } from '@nitrots/nitro-renderer';
|
|
||||||
|
|
||||||
export class FriendsAcceptFriendRequestEvent extends NitroEvent
|
|
||||||
{
|
|
||||||
public static ACCEPT_FRIEND_REQUEST: string = 'FAFRE_ACCEPT_FRIEND_REQUEST';
|
|
||||||
|
|
||||||
private _requestId: number;
|
|
||||||
|
|
||||||
constructor(requestId: number)
|
|
||||||
{
|
|
||||||
super(FriendsAcceptFriendRequestEvent.ACCEPT_FRIEND_REQUEST);
|
|
||||||
|
|
||||||
this._requestId = requestId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get requestId(): number
|
|
||||||
{
|
|
||||||
return this._requestId;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
import { NitroEvent } from '@nitrots/nitro-renderer';
|
|
||||||
|
|
||||||
export class FriendsDeclineFriendRequestEvent extends NitroEvent
|
|
||||||
{
|
|
||||||
public static DECLINE_FRIEND_REQUEST: string = 'FAFRE_DECLINE_FRIEND_REQUEST';
|
|
||||||
|
|
||||||
private _requestId: number;
|
|
||||||
|
|
||||||
constructor(requestId: number)
|
|
||||||
{
|
|
||||||
super(FriendsDeclineFriendRequestEvent.DECLINE_FRIEND_REQUEST);
|
|
||||||
|
|
||||||
this._requestId = requestId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get requestId(): number
|
|
||||||
{
|
|
||||||
return this._requestId;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
import { NitroEvent } from '@nitrots/nitro-renderer';
|
|
||||||
|
|
||||||
export class FriendsEvent extends NitroEvent
|
|
||||||
{
|
|
||||||
public static SHOW_FRIEND_LIST: string = 'IE_SHOW_FRIEND_LIST';
|
|
||||||
public static TOGGLE_FRIEND_LIST: string = 'IE_TOGGLE_FRIEND_LIST';
|
|
||||||
public static SHOW_FRIEND_MESSENGER: string = 'IE_SHOW_FRIEND_MESSENGER';
|
|
||||||
public static TOGGLE_FRIEND_MESSENGER: string = 'IE_TOGGLE_FRIEND_MESSENGER';
|
|
||||||
public static REQUEST_FRIEND_LIST: string = 'FLSFRE_REQUEST_FRIEND_LIST';
|
|
||||||
}
|
|
@ -1,23 +0,0 @@
|
|||||||
import { NitroEvent } from '@nitrots/nitro-renderer';
|
|
||||||
|
|
||||||
export class FriendsMessengerIconEvent extends NitroEvent
|
|
||||||
{
|
|
||||||
public static UPDATE_ICON: string = 'FMIE_UPDATE_ICON';
|
|
||||||
public static HIDE_ICON: number = 0;
|
|
||||||
public static SHOW_ICON: number = 1;
|
|
||||||
public static UNREAD_ICON: number = 2;
|
|
||||||
|
|
||||||
private _iconType: number;
|
|
||||||
|
|
||||||
constructor(type: string, subType: number = FriendsMessengerIconEvent.SHOW_ICON)
|
|
||||||
{
|
|
||||||
super(type);
|
|
||||||
|
|
||||||
this._iconType = subType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get iconType(): number
|
|
||||||
{
|
|
||||||
return this._iconType;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
import { NitroEvent } from '@nitrots/nitro-renderer';
|
|
||||||
|
|
||||||
export class FriendsRequestCountEvent extends NitroEvent
|
|
||||||
{
|
|
||||||
public static UPDATE_COUNT: string = 'FRCE_UPDATE_COUNT';
|
|
||||||
|
|
||||||
private _count: number;
|
|
||||||
|
|
||||||
constructor(count: number)
|
|
||||||
{
|
|
||||||
super(FriendsRequestCountEvent.UPDATE_COUNT);
|
|
||||||
|
|
||||||
this._count = count;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get count(): number
|
|
||||||
{
|
|
||||||
return this._count;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
import { NitroEvent } from '@nitrots/nitro-renderer';
|
|
||||||
|
|
||||||
export class FriendsSendFriendRequestEvent extends NitroEvent
|
|
||||||
{
|
|
||||||
public static SEND_FRIEND_REQUEST: string = 'FLSFRE_SEND_FRIEND_REQUEST';
|
|
||||||
|
|
||||||
private _userId: number;
|
|
||||||
private _userName: string;
|
|
||||||
|
|
||||||
constructor(userId: number, userName: string)
|
|
||||||
{
|
|
||||||
super(FriendsSendFriendRequestEvent.SEND_FRIEND_REQUEST);
|
|
||||||
|
|
||||||
this._userId = userId;
|
|
||||||
this._userName = userName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get userId(): number
|
|
||||||
{
|
|
||||||
return this._userId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get userName(): string
|
|
||||||
{
|
|
||||||
return this._userName;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,9 +1 @@
|
|||||||
export * from './FriendEnteredRoomEvent';
|
export * from './FriendEnteredRoomEvent';
|
||||||
export * from './FriendListContentEvent';
|
|
||||||
export * from './FriendRequestEvent';
|
|
||||||
export * from './FriendsAcceptFriendRequestEvent';
|
|
||||||
export * from './FriendsDeclineFriendRequestEvent';
|
|
||||||
export * from './FriendsEvent';
|
|
||||||
export * from './FriendsMessengerIconEvent';
|
|
||||||
export * from './FriendsRequestCountEvent';
|
|
||||||
export * from './FriendsSendFriendRequestEvent';
|
|
||||||
|
2
src/hooks/friends/index.ts
Normal file
2
src/hooks/friends/index.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export * from './useFriends';
|
||||||
|
export * from './useMessenger';
|
265
src/hooks/friends/useFriends.ts
Normal file
265
src/hooks/friends/useFriends.ts
Normal file
@ -0,0 +1,265 @@
|
|||||||
|
import { AcceptFriendMessageComposer, DeclineFriendMessageComposer, FollowFriendMessageComposer, FriendListFragmentEvent, FriendListUpdateEvent, FriendParser, FriendRequestsEvent, GetFriendRequestsComposer, MessengerInitComposer, MessengerInitEvent, NewFriendRequestEvent, RequestFriendComposer, SetRelationshipStatusComposer } from '@nitrots/nitro-renderer';
|
||||||
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
|
import { useBetween } from 'use-between';
|
||||||
|
import { CloneObject, MessengerFriend, MessengerRequest, MessengerSettings, SendMessageComposer } from '../../api';
|
||||||
|
import { UseMessageEventHook } from '../messages';
|
||||||
|
|
||||||
|
const useFriendsState = () =>
|
||||||
|
{
|
||||||
|
const [ friends, setFriends ] = useState<MessengerFriend[]>([]);
|
||||||
|
const [ requests, setRequests ] = useState<MessengerRequest[]>([]);
|
||||||
|
const [ sentRequests, setSentRequests ] = useState<number[]>([]);
|
||||||
|
const [ settings, setSettings ] = useState<MessengerSettings>(null);
|
||||||
|
|
||||||
|
const onlineFriends = useMemo(() =>
|
||||||
|
{
|
||||||
|
const onlineFriends = friends.filter(friend => friend.online);
|
||||||
|
|
||||||
|
onlineFriends.sort((a, b) =>
|
||||||
|
{
|
||||||
|
if( a.name < b.name ) return -1;
|
||||||
|
|
||||||
|
if( a.name > b.name ) return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
return onlineFriends;
|
||||||
|
}, [ friends ]);
|
||||||
|
|
||||||
|
const offlineFriends = useMemo(() =>
|
||||||
|
{
|
||||||
|
const offlineFriends = friends.filter(friend => !friend.online);
|
||||||
|
|
||||||
|
offlineFriends.sort((a, b) =>
|
||||||
|
{
|
||||||
|
if( a.name < b.name ) return -1;
|
||||||
|
|
||||||
|
if( a.name > b.name ) return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
return offlineFriends;
|
||||||
|
}, [ friends ]);
|
||||||
|
|
||||||
|
const followFriend = useCallback((friend: MessengerFriend) => SendMessageComposer(new FollowFriendMessageComposer(friend.id)), []);
|
||||||
|
const updateRelationship = useCallback((friend: MessengerFriend, type: number) => ((type !== friend.relationshipStatus) && SendMessageComposer(new SetRelationshipStatusComposer(friend.id, type))), []);
|
||||||
|
|
||||||
|
const getFriend = useCallback((userId: number) =>
|
||||||
|
{
|
||||||
|
for(const friend of friends)
|
||||||
|
{
|
||||||
|
if(friend.id === userId) return friend;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}, [ friends ]);
|
||||||
|
|
||||||
|
const canRequestFriend = useCallback((userId: number) =>
|
||||||
|
{
|
||||||
|
if(getFriend(userId)) return false;
|
||||||
|
|
||||||
|
if(requests.find(request => (request.requesterUserId === userId))) return false;
|
||||||
|
|
||||||
|
if(sentRequests.indexOf(userId) >= 0) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}, [ requests, sentRequests, getFriend ]);
|
||||||
|
|
||||||
|
const requestFriend = useCallback((userId: number, userName: string) =>
|
||||||
|
{
|
||||||
|
if(!canRequestFriend(userId)) return false;
|
||||||
|
|
||||||
|
setSentRequests(prevValue =>
|
||||||
|
{
|
||||||
|
const newSentRequests = [ ...prevValue ];
|
||||||
|
|
||||||
|
newSentRequests.push(userId);
|
||||||
|
|
||||||
|
return newSentRequests;
|
||||||
|
});
|
||||||
|
|
||||||
|
SendMessageComposer(new RequestFriendComposer(userName));
|
||||||
|
}, [ canRequestFriend ]);
|
||||||
|
|
||||||
|
const requestResponse = useCallback((requestId: number, flag: boolean) =>
|
||||||
|
{
|
||||||
|
if(requestId === -1 && !flag)
|
||||||
|
{
|
||||||
|
SendMessageComposer(new DeclineFriendMessageComposer(true));
|
||||||
|
|
||||||
|
setRequests([]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
setRequests(prevValue =>
|
||||||
|
{
|
||||||
|
const newRequests = [ ...prevValue ];
|
||||||
|
const index = newRequests.findIndex(request => (request.id === requestId));
|
||||||
|
|
||||||
|
if(index === -1) return prevValue;
|
||||||
|
|
||||||
|
if(flag)
|
||||||
|
{
|
||||||
|
SendMessageComposer(new AcceptFriendMessageComposer(newRequests[index].id));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SendMessageComposer(new DeclineFriendMessageComposer(false, newRequests[index].id));
|
||||||
|
}
|
||||||
|
|
||||||
|
newRequests.splice(index, 1);
|
||||||
|
|
||||||
|
return newRequests;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const onMessengerInitEvent = useCallback((event: MessengerInitEvent) =>
|
||||||
|
{
|
||||||
|
const parser = event.getParser();
|
||||||
|
|
||||||
|
setSettings(new MessengerSettings(
|
||||||
|
parser.userFriendLimit,
|
||||||
|
parser.normalFriendLimit,
|
||||||
|
parser.extendedFriendLimit,
|
||||||
|
parser.categories));
|
||||||
|
|
||||||
|
SendMessageComposer(new GetFriendRequestsComposer());
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
UseMessageEventHook(MessengerInitEvent, onMessengerInitEvent);
|
||||||
|
|
||||||
|
const onFriendsFragmentEvent = useCallback((event: FriendListFragmentEvent) =>
|
||||||
|
{
|
||||||
|
const parser = event.getParser();
|
||||||
|
|
||||||
|
setFriends(prevValue =>
|
||||||
|
{
|
||||||
|
const newValue = [ ...prevValue ];
|
||||||
|
|
||||||
|
for(const friend of parser.fragment)
|
||||||
|
{
|
||||||
|
const index = newValue.findIndex(existingFriend => (existingFriend.id === friend.id));
|
||||||
|
const newFriend = new MessengerFriend();
|
||||||
|
newFriend.populate(friend);
|
||||||
|
|
||||||
|
if(index > -1) newValue[index] = newFriend;
|
||||||
|
else newValue.push(newFriend);
|
||||||
|
}
|
||||||
|
|
||||||
|
return newValue;
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
UseMessageEventHook(FriendListFragmentEvent, onFriendsFragmentEvent);
|
||||||
|
|
||||||
|
const onFriendsUpdateEvent = useCallback((event: FriendListUpdateEvent) =>
|
||||||
|
{
|
||||||
|
const parser = event.getParser();
|
||||||
|
|
||||||
|
setFriends(prevValue =>
|
||||||
|
{
|
||||||
|
const newValue = [ ...prevValue ];
|
||||||
|
|
||||||
|
const processUpdate = (friend: FriendParser) =>
|
||||||
|
{
|
||||||
|
const index = newValue.findIndex(existingFriend => (existingFriend.id === friend.id));
|
||||||
|
|
||||||
|
if(index === -1)
|
||||||
|
{
|
||||||
|
const newFriend = new MessengerFriend();
|
||||||
|
newFriend.populate(friend);
|
||||||
|
|
||||||
|
newValue.unshift(newFriend);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
newValue[index].populate(friend);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(const friend of parser.addedFriends) processUpdate(friend);
|
||||||
|
|
||||||
|
for(const friend of parser.updatedFriends) processUpdate(friend);
|
||||||
|
|
||||||
|
for(const removedFriendId of parser.removedFriendIds)
|
||||||
|
{
|
||||||
|
const index = newValue.findIndex(existingFriend => (existingFriend.id === removedFriendId));
|
||||||
|
|
||||||
|
if(index > -1) newValue.splice(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
return newValue;
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
UseMessageEventHook(FriendListUpdateEvent, onFriendsUpdateEvent);
|
||||||
|
|
||||||
|
const onFriendRequestsEvent = useCallback((event: FriendRequestsEvent) =>
|
||||||
|
{
|
||||||
|
const parser = event.getParser();
|
||||||
|
|
||||||
|
setRequests(prevValue =>
|
||||||
|
{
|
||||||
|
const newValue = [ ...prevValue ];
|
||||||
|
|
||||||
|
for(const request of parser.requests)
|
||||||
|
{
|
||||||
|
const index = newValue.findIndex(existing => (existing.requesterUserId === request.requesterUserId));
|
||||||
|
|
||||||
|
if(index > 0)
|
||||||
|
{
|
||||||
|
newValue[index] = CloneObject(newValue[index]);
|
||||||
|
newValue[index].populate(request);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const newRequest = new MessengerRequest();
|
||||||
|
newRequest.populate(request);
|
||||||
|
|
||||||
|
newValue.push(newRequest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return newValue;
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
UseMessageEventHook(FriendRequestsEvent, onFriendRequestsEvent);
|
||||||
|
|
||||||
|
const onNewFriendRequestEvent = useCallback((event: NewFriendRequestEvent) =>
|
||||||
|
{
|
||||||
|
const parser = event.getParser();
|
||||||
|
const request = parser.request;
|
||||||
|
|
||||||
|
setRequests(prevValue =>
|
||||||
|
{
|
||||||
|
const newRequests = [ ...prevValue ];
|
||||||
|
|
||||||
|
const index = newRequests.findIndex(existing => (existing.requesterUserId === request.requesterUserId));
|
||||||
|
|
||||||
|
if(index === -1)
|
||||||
|
{
|
||||||
|
const newRequest = new MessengerRequest();
|
||||||
|
newRequest.populate(request);
|
||||||
|
|
||||||
|
newRequests.push(newRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
return newRequests;
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
UseMessageEventHook(NewFriendRequestEvent, onNewFriendRequestEvent);
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
SendMessageComposer(new MessengerInitComposer());
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return { friends, requests, sentRequests, settings, onlineFriends, offlineFriends, getFriend, canRequestFriend, requestFriend, requestResponse, followFriend, updateRelationship };
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useFriends = () => useBetween(useFriendsState);
|
222
src/hooks/friends/useMessenger.ts
Normal file
222
src/hooks/friends/useMessenger.ts
Normal file
@ -0,0 +1,222 @@
|
|||||||
|
import { NewConsoleMessageEvent, RoomInviteErrorEvent, RoomInviteEvent, SendMessageComposer as SendMessageComposerPacket } from '@nitrots/nitro-renderer';
|
||||||
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
|
import { useBetween } from 'use-between';
|
||||||
|
import { CloneObject, GetSessionDataManager, LocalizeText, MessengerIconState, MessengerThread, MessengerThreadChat, NotificationAlertType, NotificationUtilities, PlaySound, SendMessageComposer, SoundNames } from '../../api';
|
||||||
|
import { UseMessageEventHook } from '../messages';
|
||||||
|
import { useFriends } from './useFriends';
|
||||||
|
|
||||||
|
const useMessengerState = () =>
|
||||||
|
{
|
||||||
|
const [ messageThreads, setMessageThreads ] = useState<MessengerThread[]>([]);
|
||||||
|
const [ activeThreadId, setActiveThreadId ] = useState<number>(-1);
|
||||||
|
const [ hiddenThreadIds, setHiddenThreadIds ] = useState<number[]>([]);
|
||||||
|
const [ iconState, setIconState ] = useState<number>(MessengerIconState.HIDDEN);
|
||||||
|
const { getFriend = null } = useFriends();
|
||||||
|
|
||||||
|
const visibleThreads = useMemo(() => messageThreads.filter(thread => (hiddenThreadIds.indexOf(thread.threadId) === -1)), [ messageThreads, hiddenThreadIds ]);
|
||||||
|
const activeThread = useMemo(() => ((activeThreadId > 0) && visibleThreads.find(thread => (thread.threadId === activeThreadId) || null)), [ activeThreadId, visibleThreads ]);
|
||||||
|
|
||||||
|
const getMessageThread = useCallback((userId: number) =>
|
||||||
|
{
|
||||||
|
let thread = messageThreads.find(thread => (thread.participant && (thread.participant.id === userId)));
|
||||||
|
|
||||||
|
if(thread) return thread;
|
||||||
|
|
||||||
|
const friend = getFriend(userId);
|
||||||
|
|
||||||
|
if(!friend) return null;
|
||||||
|
|
||||||
|
thread = new MessengerThread(friend);
|
||||||
|
|
||||||
|
setMessageThreads(prevValue =>
|
||||||
|
{
|
||||||
|
const newValue = [ ...prevValue ];
|
||||||
|
|
||||||
|
newValue.push(thread);
|
||||||
|
|
||||||
|
return newValue;
|
||||||
|
});
|
||||||
|
|
||||||
|
setHiddenThreadIds(prevValue =>
|
||||||
|
{
|
||||||
|
const index = prevValue.indexOf(thread.threadId);
|
||||||
|
|
||||||
|
if(index === -1) return prevValue;
|
||||||
|
|
||||||
|
const newValue = [ ...prevValue ];
|
||||||
|
|
||||||
|
newValue.splice(index, 1);
|
||||||
|
|
||||||
|
return newValue;
|
||||||
|
});
|
||||||
|
|
||||||
|
return thread;
|
||||||
|
}, [ messageThreads, getFriend ]);
|
||||||
|
|
||||||
|
const setActiveThread = useCallback((thread: MessengerThread) =>
|
||||||
|
{
|
||||||
|
if(!thread)
|
||||||
|
{
|
||||||
|
setActiveThreadId(-1);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setMessageThreads(prevValue =>
|
||||||
|
{
|
||||||
|
const newValue = [ ...prevValue ];
|
||||||
|
const index = newValue.findIndex(newThread => (newThread.threadId === thread.threadId));
|
||||||
|
|
||||||
|
if(index === -1) return prevValue;
|
||||||
|
|
||||||
|
const newThread = CloneObject(newValue[index]);
|
||||||
|
|
||||||
|
newValue[index] = newThread;
|
||||||
|
|
||||||
|
newThread.setRead();
|
||||||
|
|
||||||
|
return newValue;
|
||||||
|
});
|
||||||
|
|
||||||
|
setActiveThreadId(thread.threadId);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const closeThread = (threadId: number) =>
|
||||||
|
{
|
||||||
|
setHiddenThreadIds(prevValue =>
|
||||||
|
{
|
||||||
|
const newValue = [ ...prevValue ];
|
||||||
|
|
||||||
|
if(newValue.indexOf(threadId) >= 0) return prevValue;
|
||||||
|
|
||||||
|
newValue.push(threadId);
|
||||||
|
|
||||||
|
return newValue;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const sendMessage = (thread: MessengerThread, text: string) =>
|
||||||
|
{
|
||||||
|
if(!thread || !text || !text.length) return;
|
||||||
|
|
||||||
|
SendMessageComposer(new SendMessageComposerPacket(thread.participant.id, text));
|
||||||
|
|
||||||
|
if((messageThreads.length === 1) && (thread.groups.length === 1)) PlaySound(SoundNames.MESSENGER_NEW_THREAD);
|
||||||
|
|
||||||
|
setMessageThreads(prevValue =>
|
||||||
|
{
|
||||||
|
const newValue = [ ...prevValue ];
|
||||||
|
const index = newValue.findIndex(newThread => (newThread.threadId === thread.threadId));
|
||||||
|
|
||||||
|
if(index === -1) return prevValue;
|
||||||
|
|
||||||
|
const newThread = CloneObject(newValue[index]);
|
||||||
|
|
||||||
|
newValue[index] = newThread;
|
||||||
|
|
||||||
|
newThread.addMessage(GetSessionDataManager().userId, text, 0, null, MessengerThreadChat.CHAT);
|
||||||
|
|
||||||
|
if(activeThreadId === newThread.threadId) newThread.setRead();
|
||||||
|
|
||||||
|
return newValue;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const onNewConsoleMessageEvent = useCallback((event: NewConsoleMessageEvent) =>
|
||||||
|
{
|
||||||
|
const parser = event.getParser();
|
||||||
|
const thread = getMessageThread(parser.senderId);
|
||||||
|
|
||||||
|
if(!thread) return;
|
||||||
|
|
||||||
|
setMessageThreads(prevValue =>
|
||||||
|
{
|
||||||
|
const newValue = [ ...prevValue ];
|
||||||
|
const index = newValue.findIndex(newThread => (newThread.threadId === thread.threadId));
|
||||||
|
|
||||||
|
if(index === -1) return prevValue;
|
||||||
|
|
||||||
|
const newThread = CloneObject(newValue[index]);
|
||||||
|
|
||||||
|
newValue[index] = newThread;
|
||||||
|
|
||||||
|
newThread.addMessage(parser.senderId, parser.messageText, parser.secondsSinceSent, parser.extraData);
|
||||||
|
|
||||||
|
if(activeThreadId === newThread.threadId) newThread.setRead();
|
||||||
|
|
||||||
|
if(newThread.unreadCount > 0) PlaySound(SoundNames.MESSENGER_MESSAGE_RECEIVED);
|
||||||
|
|
||||||
|
return newValue;
|
||||||
|
});
|
||||||
|
}, [ activeThreadId, getMessageThread ]);
|
||||||
|
|
||||||
|
UseMessageEventHook(NewConsoleMessageEvent, onNewConsoleMessageEvent);
|
||||||
|
|
||||||
|
const onRoomInviteEvent = useCallback((event: RoomInviteEvent) =>
|
||||||
|
{
|
||||||
|
const parser = event.getParser();
|
||||||
|
const thread = getMessageThread(parser.senderId);
|
||||||
|
|
||||||
|
if(!thread) return;
|
||||||
|
|
||||||
|
setMessageThreads(prevValue =>
|
||||||
|
{
|
||||||
|
const newValue = [ ...prevValue ];
|
||||||
|
const index = newValue.findIndex(newThread => (newThread.threadId === thread.threadId));
|
||||||
|
|
||||||
|
if(index === -1) return prevValue;
|
||||||
|
|
||||||
|
const newThread = CloneObject(newValue[index]);
|
||||||
|
|
||||||
|
newValue[index] = newThread;
|
||||||
|
|
||||||
|
newThread.addMessage(null, parser.messageText, 0, null, MessengerThreadChat.ROOM_INVITE);
|
||||||
|
|
||||||
|
if(activeThreadId === newThread.threadId) newThread.setRead();
|
||||||
|
|
||||||
|
if(newThread.unreadCount > 0) PlaySound(SoundNames.MESSENGER_MESSAGE_RECEIVED);
|
||||||
|
|
||||||
|
return newValue;
|
||||||
|
});
|
||||||
|
}, [ activeThreadId, getMessageThread ]);
|
||||||
|
|
||||||
|
UseMessageEventHook(RoomInviteEvent, onRoomInviteEvent);
|
||||||
|
|
||||||
|
const onRoomInviteErrorEvent = useCallback((event: RoomInviteErrorEvent) =>
|
||||||
|
{
|
||||||
|
const parser = event.getParser();
|
||||||
|
const message = ((('Received room invite error: errorCode: ' + parser.errorCode) + ', recipients: ') + parser.failedRecipients);
|
||||||
|
|
||||||
|
NotificationUtilities.simpleAlert(message, NotificationAlertType.DEFAULT, null, null, LocalizeText('friendlist.alert.title'));
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
UseMessageEventHook(RoomInviteErrorEvent, onRoomInviteErrorEvent);
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
setIconState(prevValue =>
|
||||||
|
{
|
||||||
|
if(!visibleThreads.length) return MessengerIconState.HIDDEN;
|
||||||
|
|
||||||
|
let isUnread = false;
|
||||||
|
|
||||||
|
for(const thread of visibleThreads)
|
||||||
|
{
|
||||||
|
if(thread.unreadCount > 0)
|
||||||
|
{
|
||||||
|
isUnread = true;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isUnread) return MessengerIconState.UNREAD;
|
||||||
|
|
||||||
|
return MessengerIconState.SHOW;
|
||||||
|
});
|
||||||
|
}, [ visibleThreads ]);
|
||||||
|
|
||||||
|
return { messageThreads, activeThread, iconState, visibleThreads, getMessageThread, setActiveThread, closeThread, sendMessage };
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useMessenger = () => useBetween(useMessengerState);
|
@ -3,6 +3,7 @@ export * from './events';
|
|||||||
export * from './events/core';
|
export * from './events/core';
|
||||||
export * from './events/nitro';
|
export * from './events/nitro';
|
||||||
export * from './events/ui';
|
export * from './events/ui';
|
||||||
|
export * from './friends';
|
||||||
export * from './inventory';
|
export * from './inventory';
|
||||||
export * from './messages';
|
export * from './messages';
|
||||||
export * from './navigator';
|
export * from './navigator';
|
||||||
|
Loading…
x
Reference in New Issue
Block a user