mirror of
https://github.com/billsonnn/nitro-react.git
synced 2024-11-26 15:40:51 +01:00
Merge pull request #47 from billsonnn/patch/style-fixes
Patch/style fixes
This commit is contained in:
commit
a97ca4b040
@ -14,7 +14,7 @@
|
|||||||
"@nitrots/nitro-renderer": "file:../nitro-renderer",
|
"@nitrots/nitro-renderer": "file:../nitro-renderer",
|
||||||
"animate.css": "^4.1.1",
|
"animate.css": "^4.1.1",
|
||||||
"classnames": "^2.3.1",
|
"classnames": "^2.3.1",
|
||||||
"node-sass": "^5.0.0",
|
"node-sass": "^6.0.1",
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-bootstrap": "^2.0.0-alpha.2",
|
"react-bootstrap": "^2.0.0-alpha.2",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
|
@ -101,20 +101,7 @@
|
|||||||
"elephants"
|
"elephants"
|
||||||
],
|
],
|
||||||
"preload.assets.urls": [
|
"preload.assets.urls": [
|
||||||
"${images.url}/additions/user_blowkiss.png",
|
"${asset.url}/bundled/generic/avatar_additions.nitro",
|
||||||
"${images.url}/additions/user_idle_left_1.png",
|
|
||||||
"${images.url}/additions/user_idle_left_2.png",
|
|
||||||
"${images.url}/additions/user_idle_right_1.png",
|
|
||||||
"${images.url}/additions/user_idle_right_2.png",
|
|
||||||
"${images.url}/additions/user_muted.png",
|
|
||||||
"${images.url}/additions/user_muted_small.png",
|
|
||||||
"${images.url}/additions/user_typing.png",
|
|
||||||
"${images.url}/additions/number_1.png",
|
|
||||||
"${images.url}/additions/number_2.png",
|
|
||||||
"${images.url}/additions/number_3.png",
|
|
||||||
"${images.url}/additions/number_4.png",
|
|
||||||
"${images.url}/additions/number_5.png",
|
|
||||||
"${images.url}/additions/pet_experience_bubble.png",
|
|
||||||
"${images.url}/loading_icon.png",
|
"${images.url}/loading_icon.png",
|
||||||
"${images.url}/clear_icon.png",
|
"${images.url}/clear_icon.png",
|
||||||
"${images.url}/big_arrow.png"
|
"${images.url}/big_arrow.png"
|
||||||
|
@ -56,6 +56,9 @@ $help-height: 450px;
|
|||||||
$nitropedia-width: 400px;
|
$nitropedia-width: 400px;
|
||||||
$nitropedia-height: 400px;
|
$nitropedia-height: 400px;
|
||||||
|
|
||||||
|
$messenger-width: 500px;
|
||||||
|
$messenger-height: 370px;
|
||||||
|
|
||||||
.nitro-app {
|
.nitro-app {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
5
src/views/friends/common/GroupType.ts
Normal file
5
src/views/friends/common/GroupType.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export class GroupType
|
||||||
|
{
|
||||||
|
public static readonly GROUP_CHAT = 0;
|
||||||
|
public static readonly PRIVATE_CHAT = 1;
|
||||||
|
}
|
@ -1,7 +1,9 @@
|
|||||||
import { LocalizeText } from '../../../api';
|
import { LocalizeText } from '../../../api';
|
||||||
|
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
|
||||||
{
|
{
|
||||||
@ -10,35 +12,40 @@ export class MessengerThread
|
|||||||
private _participant: MessengerFriend;
|
private _participant: MessengerFriend;
|
||||||
private _groups: MessengerThreadChatGroup[];
|
private _groups: MessengerThreadChatGroup[];
|
||||||
private _lastUpdated: Date;
|
private _lastUpdated: Date;
|
||||||
private _unread: boolean;
|
private _unreadCount: number;
|
||||||
|
|
||||||
constructor(participant: MessengerFriend, isNew: boolean = true)
|
constructor(participant: MessengerFriend, isNew: boolean = true)
|
||||||
{
|
{
|
||||||
this._participant = participant;
|
this._participant = participant;
|
||||||
this._groups = [];
|
this._groups = [];
|
||||||
this._lastUpdated = new Date();
|
this._lastUpdated = new Date();
|
||||||
this._unread = false;
|
this._unreadCount = 0;
|
||||||
|
|
||||||
if(isNew)
|
if(isNew)
|
||||||
{
|
{
|
||||||
this.addMessage(-1, LocalizeText('messenger.moderationinfo'), 0, null, MessengerThreadChat.SECURITY_NOTIFICATION);
|
this.addMessage(null, LocalizeText('messenger.moderationinfo'), 0, null, MessengerThreadChat.SECURITY_NOTIFICATION);
|
||||||
|
|
||||||
this._unread = false;
|
this._unreadCount = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 group = this.getLastGroup(senderId);
|
const isGroupChat = (senderId < 0 && extraData);
|
||||||
|
const userId = isGroupChat ? getGroupChatData(extraData).userId : senderId;
|
||||||
|
|
||||||
|
const group = this.getLastGroup(userId);
|
||||||
|
|
||||||
if(!group) return;
|
if(!group) return;
|
||||||
|
|
||||||
|
if(isGroupChat) group.type = GroupType.GROUP_CHAT;
|
||||||
|
|
||||||
const chat = new MessengerThreadChat(senderId, message, secondsSinceSent, extraData, type);
|
const chat = new MessengerThreadChat(senderId, message, secondsSinceSent, extraData, type);
|
||||||
|
|
||||||
group.addChat(chat);
|
group.addChat(chat);
|
||||||
|
|
||||||
this._lastUpdated = new Date();
|
this._lastUpdated = new Date();
|
||||||
this._unread = true;
|
this._unreadCount++;
|
||||||
|
|
||||||
return chat;
|
return chat;
|
||||||
}
|
}
|
||||||
@ -58,7 +65,7 @@ export class MessengerThread
|
|||||||
|
|
||||||
public setRead(): void
|
public setRead(): void
|
||||||
{
|
{
|
||||||
this._unread = false;
|
this._unreadCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get participant(): MessengerFriend
|
public get participant(): MessengerFriend
|
||||||
@ -76,8 +83,13 @@ export class MessengerThread
|
|||||||
return this._lastUpdated;
|
return this._lastUpdated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get unreadCount(): number
|
||||||
|
{
|
||||||
|
return this._unreadCount;
|
||||||
|
}
|
||||||
|
|
||||||
public get unread(): boolean
|
public get unread(): boolean
|
||||||
{
|
{
|
||||||
return this._unread;
|
return this._unreadCount > 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,17 @@
|
|||||||
|
import { GroupType } from './GroupType';
|
||||||
import { MessengerThreadChat } from './MessengerThreadChat';
|
import { MessengerThreadChat } from './MessengerThreadChat';
|
||||||
|
|
||||||
export class MessengerThreadChatGroup
|
export class MessengerThreadChatGroup
|
||||||
{
|
{
|
||||||
private _userId: number;
|
private _userId: number;
|
||||||
private _chats: MessengerThreadChat[];
|
private _chats: MessengerThreadChat[];
|
||||||
|
private _type: number;
|
||||||
|
|
||||||
constructor(userId: number)
|
constructor(userId: number, type = GroupType.PRIVATE_CHAT)
|
||||||
{
|
{
|
||||||
this._userId = userId;
|
this._userId = userId;
|
||||||
this._chats = [];
|
this._chats = [];
|
||||||
|
this._type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public addChat(message: MessengerThreadChat): void
|
public addChat(message: MessengerThreadChat): void
|
||||||
@ -25,4 +28,14 @@ export class MessengerThreadChatGroup
|
|||||||
{
|
{
|
||||||
return this._chats;
|
return this._chats;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get type(): number
|
||||||
|
{
|
||||||
|
return this._type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set type(type: number)
|
||||||
|
{
|
||||||
|
this._type = type;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
18
src/views/friends/common/Utils.ts
Normal file
18
src/views/friends/common/Utils.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
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;
|
||||||
|
}
|
@ -11,8 +11,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.friend-bar-item-head {
|
.friend-bar-item-head {
|
||||||
|
&.avatar {
|
||||||
top: -30px;
|
top: -30px;
|
||||||
left: -30px;
|
left: -30px;
|
||||||
|
}
|
||||||
|
&.group {
|
||||||
|
top: -5px;
|
||||||
|
left: -5px;
|
||||||
|
}
|
||||||
|
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import { GetUserProfile, LocalizeText, OpenMessengerChat } from '../../../../api
|
|||||||
import { SendMessageHook } from '../../../../hooks/messages';
|
import { SendMessageHook } from '../../../../hooks/messages';
|
||||||
import { NitroLayoutBase } from '../../../../layout/base';
|
import { NitroLayoutBase } from '../../../../layout/base';
|
||||||
import { AvatarImageView } from '../../../shared/avatar-image/AvatarImageView';
|
import { AvatarImageView } from '../../../shared/avatar-image/AvatarImageView';
|
||||||
|
import { BadgeImageView } from '../../../shared/badge-image/BadgeImageView';
|
||||||
import { FriendBarItemViewProps } from './FriendBarItemView.types';
|
import { FriendBarItemViewProps } from './FriendBarItemView.types';
|
||||||
|
|
||||||
export const FriendBarItemView: FC<FriendBarItemViewProps> = props =>
|
export const FriendBarItemView: FC<FriendBarItemViewProps> = props =>
|
||||||
@ -58,8 +59,9 @@ export const FriendBarItemView: FC<FriendBarItemViewProps> = props =>
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={ elementRef } className={'btn btn-success friend-bar-item ' + (isVisible ? 'friend-bar-item-active' : '')} onClick={ event => setVisible(prevValue => !prevValue) }>
|
<div ref={ elementRef } className={'btn btn-success friend-bar-item ' + (isVisible ? 'friend-bar-item-active' : '')} onClick={ event => setVisible(prevValue => !prevValue) }>
|
||||||
<div className="friend-bar-item-head position-absolute">
|
<div className={`friend-bar-item-head position-absolute ${friend.id > 0 ? 'avatar': 'group'}`}>
|
||||||
<AvatarImageView headOnly={ true } figure={ friend.figure } direction={ 2 } />
|
{ friend.id > 0 && <AvatarImageView headOnly={ true } figure={ friend.figure } direction={ 2 } /> }
|
||||||
|
{ friend.id <= 0 && <BadgeImageView isGroup={ true } badgeCode={ friend.figure} />}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-truncate">{ friend.name }</div>
|
<div className="text-truncate">{ friend.name }</div>
|
||||||
{ isVisible &&
|
{ isVisible &&
|
||||||
|
@ -1,18 +1,31 @@
|
|||||||
import { FC } from 'react';
|
import { FC, useMemo } from 'react';
|
||||||
import { GetSessionDataManager } from '../../../../api';
|
import { GetSessionDataManager } from '../../../../api';
|
||||||
import { NitroLayoutFlex } from '../../../../layout';
|
import { NitroLayoutFlex } from '../../../../layout';
|
||||||
import { NitroLayoutBase } from '../../../../layout/base';
|
import { NitroLayoutBase } from '../../../../layout/base';
|
||||||
import { AvatarImageView } from '../../../shared/avatar-image/AvatarImageView';
|
import { AvatarImageView } from '../../../shared/avatar-image/AvatarImageView';
|
||||||
|
import { GroupType } from '../../common/GroupType';
|
||||||
import { MessengerThreadChat } from '../../common/MessengerThreadChat';
|
import { MessengerThreadChat } from '../../common/MessengerThreadChat';
|
||||||
|
import { getGroupChatData } from '../../common/Utils';
|
||||||
import { FriendsMessengerThreadGroupProps } from './FriendsMessengerThreadGroup.types';
|
import { FriendsMessengerThreadGroupProps } from './FriendsMessengerThreadGroup.types';
|
||||||
|
|
||||||
export const FriendsMessengerThreadGroup: FC<FriendsMessengerThreadGroupProps> = props =>
|
export const FriendsMessengerThreadGroup: FC<FriendsMessengerThreadGroupProps> = props =>
|
||||||
{
|
{
|
||||||
const { thread = null, group = null } = 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(!thread || !group) return null;
|
||||||
|
|
||||||
if(group.userId === -1)
|
if(!group.userId)
|
||||||
{
|
{
|
||||||
return (
|
return (
|
||||||
<div className="d-flex gap-2 w-100 justify-content-start">
|
<div className="d-flex gap-2 w-100 justify-content-start">
|
||||||
@ -33,15 +46,26 @@ export const FriendsMessengerThreadGroup: FC<FriendsMessengerThreadGroupProps> =
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NitroLayoutFlex className={ 'w-100 justify-content-' + (group.userId === 0 ? 'end' : 'start') } gap={ 2 }>
|
<NitroLayoutFlex className={ 'w-100 justify-content-' + (isOwnChat ? 'end' : 'start') } gap={ 2 }>
|
||||||
{ (group.userId > 0) &&
|
|
||||||
<NitroLayoutBase className="message-avatar flex-shrink-0">
|
<NitroLayoutBase className="message-avatar flex-shrink-0">
|
||||||
|
{ (group.type === GroupType.PRIVATE_CHAT && !isOwnChat) &&
|
||||||
<AvatarImageView figure={ thread.participant.figure } direction={ 2 } />
|
<AvatarImageView figure={ thread.participant.figure } direction={ 2 } />
|
||||||
</NitroLayoutBase> }
|
}
|
||||||
<NitroLayoutBase className={ 'bg-light text-black border-radius mb-2 rounded py-1 px-2 messages-group-' + (group.userId === 0 ? 'right' : 'left') }>
|
{ (group.type === GroupType.GROUP_CHAT && !isOwnChat) &&
|
||||||
{ group.chats.map((chat, index) => <NitroLayoutBase key={ index } className="text-break">{ chat.message }</NitroLayoutBase>) }
|
<AvatarImageView figure={ getGroupChatData(group.chats[0].extraData).figure } direction={ 2} />
|
||||||
|
}
|
||||||
</NitroLayoutBase>
|
</NitroLayoutBase>
|
||||||
{ (group.userId === 0) &&
|
<NitroLayoutBase className={ 'bg-light text-black border-radius mb-2 rounded py-1 px-2 messages-group-' + (isOwnChat ? 'right' : 'left') }>
|
||||||
|
<NitroLayoutBase className='fw-bold'>
|
||||||
|
{
|
||||||
|
(isOwnChat) && GetSessionDataManager().userName
|
||||||
|
}
|
||||||
|
{ (!isOwnChat) && ((group.type === GroupType.GROUP_CHAT) ? getGroupChatData(group.chats[0].extraData).username : thread.participant.name)
|
||||||
|
}
|
||||||
|
</NitroLayoutBase>
|
||||||
|
{ group.chats.map((chat, index) =><NitroLayoutBase key={ index } className="text-break">{ chat.message }</NitroLayoutBase>) }
|
||||||
|
</NitroLayoutBase>
|
||||||
|
{ (isOwnChat) &&
|
||||||
<NitroLayoutBase className="message-avatar flex-shrink-0">
|
<NitroLayoutBase className="message-avatar flex-shrink-0">
|
||||||
<AvatarImageView figure={ GetSessionDataManager().figure } direction={ 4 } />
|
<AvatarImageView figure={ GetSessionDataManager().figure } direction={ 4 } />
|
||||||
</NitroLayoutBase> }
|
</NitroLayoutBase> }
|
||||||
|
@ -1,34 +1,35 @@
|
|||||||
.nitro-friends-messenger {
|
.nitro-friends-messenger {
|
||||||
width: 280px;
|
width: $messenger-width;
|
||||||
resize: both;
|
height: $messenger-height;
|
||||||
|
|
||||||
|
.open-chat-entry {
|
||||||
|
position: relative;
|
||||||
|
border: 2px solid;
|
||||||
|
border-color: $light;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
border-color: #fffde9;
|
||||||
|
background-color: #ececec
|
||||||
|
}
|
||||||
|
|
||||||
.friend-head {
|
.friend-head {
|
||||||
position: relative;
|
width: 45px;
|
||||||
width: 40px;
|
height: 45px;
|
||||||
height: 40px;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
.icon {
|
|
||||||
position: absolute;
|
|
||||||
top: 1px;
|
|
||||||
right: 1px;
|
|
||||||
z-index: 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
.avatar-image {
|
.avatar-image {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
margin-left: -27px;
|
margin-left: -27px;
|
||||||
margin-top: -27px;
|
margin-top: -27px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.chat-title {
|
.chat-title {
|
||||||
margin-top: -21px;
|
margin-top: -21px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chat-messages {
|
.chat-messages {
|
||||||
height: 200px;
|
|
||||||
min-height: 200px;
|
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
|
||||||
.message-avatar {
|
.message-avatar {
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
import { FollowFriendMessageComposer, ILinkEventTracker, NewConsoleMessageEvent, SendMessageComposer } from '@nitrots/nitro-renderer';
|
import { FollowFriendMessageComposer, ILinkEventTracker, NewConsoleMessageEvent, SendMessageComposer } from '@nitrots/nitro-renderer';
|
||||||
import { FC, KeyboardEvent, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
import { FC, KeyboardEvent, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { AddEventLinkTracker, GetUserProfile, LocalizeText, RemoveLinkEventTracker } from '../../../../api';
|
import { AddEventLinkTracker, GetSessionDataManager, GetUserProfile, LocalizeText, RemoveLinkEventTracker } from '../../../../api';
|
||||||
import { MESSENGER_MESSAGE_RECEIVED, MESSENGER_NEW_THREAD, PlaySound } from '../../../../api/utils/PlaySound';
|
import { MESSENGER_MESSAGE_RECEIVED, MESSENGER_NEW_THREAD, PlaySound } from '../../../../api/utils/PlaySound';
|
||||||
import { FriendsMessengerIconEvent } from '../../../../events';
|
import { FriendsMessengerIconEvent } from '../../../../events';
|
||||||
import { BatchUpdates, CreateMessageHook, dispatchUiEvent, SendMessageHook } from '../../../../hooks';
|
import { BatchUpdates, CreateMessageHook, dispatchUiEvent, SendMessageHook } from '../../../../hooks';
|
||||||
import { NitroCardContentView, NitroCardHeaderView, NitroCardView, NitroLayoutButton, NitroLayoutButtonGroup, NitroLayoutFlex, NitroLayoutFlexColumn } from '../../../../layout';
|
import { NitroCardContentView, NitroCardHeaderView, NitroCardView, NitroLayoutButton, NitroLayoutButtonGroup, NitroLayoutFlex, NitroLayoutFlexColumn, NitroLayoutGrid, NitroLayoutGridColumn } from '../../../../layout';
|
||||||
import { NitroLayoutBase } from '../../../../layout/base';
|
import { NitroLayoutBase } from '../../../../layout/base';
|
||||||
import { AvatarImageView } from '../../../shared/avatar-image/AvatarImageView';
|
import { AvatarImageView } from '../../../shared/avatar-image/AvatarImageView';
|
||||||
|
import { BadgeImageView } from '../../../shared/badge-image/BadgeImageView';
|
||||||
|
import { ItemCountView } from '../../../shared/item-count/ItemCountView';
|
||||||
import { MessengerThread } from '../../common/MessengerThread';
|
import { MessengerThread } from '../../common/MessengerThread';
|
||||||
import { MessengerThreadChat } from '../../common/MessengerThreadChat';
|
import { MessengerThreadChat } from '../../common/MessengerThreadChat';
|
||||||
import { useFriendsContext } from '../../context/FriendsContext';
|
import { useFriendsContext } from '../../context/FriendsContext';
|
||||||
@ -14,29 +16,29 @@ import { FriendsMessengerThreadView } from '../messenger-thread/FriendsMessenger
|
|||||||
|
|
||||||
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 [messageThreads, setMessageThreads] = useState<MessengerThread[]>([]);
|
||||||
const [ activeThreadIndex, setActiveThreadIndex ] = useState(-1);
|
const [activeThreadIndex, setActiveThreadIndex] = useState(-1);
|
||||||
const [ hiddenThreadIndexes, setHiddenThreadIndexes ] = useState<number[]>([]);
|
const [hiddenThreadIndexes, setHiddenThreadIndexes] = useState<number[]>([]);
|
||||||
const [ messageText, setMessageText ] = useState('');
|
const [messageText, setMessageText] = useState('');
|
||||||
const [ updateValue, setUpdateValue ] = useState({});
|
const [updateValue, setUpdateValue] = useState({});
|
||||||
const { friends = [] } = useFriendsContext();
|
const { friends = [] } = useFriendsContext();
|
||||||
const messagesBox = useRef<HTMLDivElement>();
|
const messagesBox = useRef<HTMLDivElement>();
|
||||||
|
|
||||||
const followFriend = useCallback(() =>
|
const followFriend = useCallback(() =>
|
||||||
{
|
{
|
||||||
SendMessageHook(new FollowFriendMessageComposer(messageThreads[activeThreadIndex].participant.id));
|
SendMessageHook(new FollowFriendMessageComposer(messageThreads[activeThreadIndex].participant.id));
|
||||||
}, [ messageThreads, activeThreadIndex ]);
|
}, [messageThreads, activeThreadIndex]);
|
||||||
|
|
||||||
const openProfile = useCallback(() =>
|
const openProfile = useCallback(() =>
|
||||||
{
|
{
|
||||||
GetUserProfile(messageThreads[activeThreadIndex].participant.id);
|
GetUserProfile(messageThreads[activeThreadIndex].participant.id);
|
||||||
}, [ messageThreads, activeThreadIndex ]);
|
}, [messageThreads, activeThreadIndex]);
|
||||||
|
|
||||||
const getFriend = useCallback((userId: number) =>
|
const getFriend = useCallback((userId: number) =>
|
||||||
{
|
{
|
||||||
return ((friends.find(friend => (friend.id === userId))) || null);
|
return ((friends.find(friend => (friend.id === userId))) || null);
|
||||||
}, [ friends ]);
|
}, [friends]);
|
||||||
|
|
||||||
const visibleThreads = useMemo(() =>
|
const visibleThreads = useMemo(() =>
|
||||||
{
|
{
|
||||||
@ -46,9 +48,9 @@ export const FriendsMessengerView: FC<{}> = props =>
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}, [ messageThreads, hiddenThreadIndexes ]);
|
}, [messageThreads, hiddenThreadIndexes]);
|
||||||
|
|
||||||
const getMessageThreadWithIndex = useCallback<(userId: number) => [ number, MessengerThread ]>((userId: number) =>
|
const getMessageThreadWithIndex = useCallback<(userId: number) => [number, MessengerThread]>((userId: number) =>
|
||||||
{
|
{
|
||||||
if(messageThreads.length > 0)
|
if(messageThreads.length > 0)
|
||||||
{
|
{
|
||||||
@ -64,7 +66,7 @@ export const FriendsMessengerView: FC<{}> = props =>
|
|||||||
{
|
{
|
||||||
setHiddenThreadIndexes(prevValue =>
|
setHiddenThreadIndexes(prevValue =>
|
||||||
{
|
{
|
||||||
const newIndexes = [ ...prevValue ];
|
const newIndexes = [...prevValue];
|
||||||
|
|
||||||
newIndexes.splice(hiddenIndex, 1);
|
newIndexes.splice(hiddenIndex, 1);
|
||||||
|
|
||||||
@ -72,34 +74,34 @@ export const FriendsMessengerView: FC<{}> = props =>
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return [ i, thread ];
|
return [i, thread];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const friend = getFriend(userId);
|
const friend = getFriend(userId);
|
||||||
|
|
||||||
if(!friend) return [ -1, null ];
|
if(!friend) return [-1, null];
|
||||||
|
|
||||||
const thread = new MessengerThread(friend);
|
const thread = new MessengerThread(friend);
|
||||||
const newThreads = [ ...messageThreads, thread ];
|
const newThreads = [...messageThreads, thread];
|
||||||
|
|
||||||
setMessageThreads(newThreads);
|
setMessageThreads(newThreads);
|
||||||
|
|
||||||
return [ (newThreads.length - 1), thread ];
|
return [(newThreads.length - 1), thread];
|
||||||
}, [ messageThreads, hiddenThreadIndexes, getFriend ]);
|
}, [messageThreads, hiddenThreadIndexes, getFriend]);
|
||||||
|
|
||||||
const onNewConsoleMessageEvent = useCallback((event: NewConsoleMessageEvent) =>
|
const onNewConsoleMessageEvent = useCallback((event: NewConsoleMessageEvent) =>
|
||||||
{
|
{
|
||||||
const parser = event.getParser();
|
const parser = event.getParser();
|
||||||
const [ threadIndex, thread ] = getMessageThreadWithIndex(parser.senderId);
|
const [threadIndex, thread] = getMessageThreadWithIndex(parser.senderId);
|
||||||
|
|
||||||
if((threadIndex === -1) || !thread) return;
|
if((threadIndex === -1) || !thread) return;
|
||||||
|
|
||||||
thread.addMessage(parser.senderId, parser.messageText, parser.secondsSinceSent, parser.extraData);
|
thread.addMessage(parser.senderId, parser.messageText, parser.secondsSinceSent, parser.extraData);
|
||||||
|
|
||||||
setMessageThreads(prevValue => [ ...prevValue ]);
|
setMessageThreads(prevValue => [...prevValue]);
|
||||||
}, [ getMessageThreadWithIndex ]);
|
}, [getMessageThreadWithIndex]);
|
||||||
|
|
||||||
CreateMessageHook(NewConsoleMessageEvent, onNewConsoleMessageEvent);
|
CreateMessageHook(NewConsoleMessageEvent, onNewConsoleMessageEvent);
|
||||||
|
|
||||||
@ -117,21 +119,21 @@ export const FriendsMessengerView: FC<{}> = props =>
|
|||||||
|
|
||||||
if(messageThreads.length === 1 && thread.groups.length === 1) PlaySound(MESSENGER_NEW_THREAD);
|
if(messageThreads.length === 1 && thread.groups.length === 1) PlaySound(MESSENGER_NEW_THREAD);
|
||||||
|
|
||||||
thread.addMessage(0, messageText, 0, null, MessengerThreadChat.CHAT);
|
thread.addMessage(GetSessionDataManager().userId, messageText, 0, null, MessengerThreadChat.CHAT);
|
||||||
|
|
||||||
BatchUpdates(() =>
|
BatchUpdates(() =>
|
||||||
{
|
{
|
||||||
setMessageThreads(prevValue => [ ...prevValue ]);
|
setMessageThreads(prevValue => [...prevValue]);
|
||||||
setMessageText('');
|
setMessageText('');
|
||||||
});
|
});
|
||||||
}, [ messageThreads, activeThreadIndex, messageText ]);
|
}, [messageThreads, activeThreadIndex, messageText]);
|
||||||
|
|
||||||
const onKeyDown = useCallback((event: KeyboardEvent<HTMLInputElement>) =>
|
const onKeyDown = useCallback((event: KeyboardEvent<HTMLInputElement>) =>
|
||||||
{
|
{
|
||||||
if(event.key !== 'Enter') return;
|
if(event.key !== 'Enter') return;
|
||||||
|
|
||||||
sendMessage();
|
sendMessage();
|
||||||
}, [ sendMessage ]);
|
}, [sendMessage]);
|
||||||
|
|
||||||
const linkReceived = useCallback((url: string) =>
|
const linkReceived = useCallback((url: string) =>
|
||||||
{
|
{
|
||||||
@ -146,7 +148,7 @@ export const FriendsMessengerView: FC<{}> = props =>
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const [ threadIndex ] = getMessageThreadWithIndex(parseInt(parts[2]));
|
const [threadIndex] = getMessageThreadWithIndex(parseInt(parts[2]));
|
||||||
|
|
||||||
if(threadIndex === -1) return;
|
if(threadIndex === -1) return;
|
||||||
|
|
||||||
@ -155,13 +157,13 @@ export const FriendsMessengerView: FC<{}> = props =>
|
|||||||
setActiveThreadIndex(threadIndex);
|
setActiveThreadIndex(threadIndex);
|
||||||
setIsVisible(true);
|
setIsVisible(true);
|
||||||
});
|
});
|
||||||
}, [ getMessageThreadWithIndex ]);
|
}, [getMessageThreadWithIndex]);
|
||||||
|
|
||||||
const closeThread = useCallback((threadIndex: number) =>
|
const closeThread = useCallback((threadIndex: number) =>
|
||||||
{
|
{
|
||||||
setHiddenThreadIndexes(prevValue =>
|
setHiddenThreadIndexes(prevValue =>
|
||||||
{
|
{
|
||||||
const values = [ ...prevValue ];
|
const values = [...prevValue];
|
||||||
|
|
||||||
if(values.indexOf(threadIndex) === -1) values.push(threadIndex);
|
if(values.indexOf(threadIndex) === -1) values.push(threadIndex);
|
||||||
|
|
||||||
@ -179,19 +181,19 @@ export const FriendsMessengerView: FC<{}> = props =>
|
|||||||
AddEventLinkTracker(linkTracker);
|
AddEventLinkTracker(linkTracker);
|
||||||
|
|
||||||
return () => RemoveLinkEventTracker(linkTracker);
|
return () => RemoveLinkEventTracker(linkTracker);
|
||||||
}, [ linkReceived ]);
|
}, [linkReceived]);
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
if(!isVisible) return;
|
if(!isVisible) return;
|
||||||
|
|
||||||
if(activeThreadIndex === -1) setActiveThreadIndex(0);
|
if(activeThreadIndex === -1) setActiveThreadIndex(0);
|
||||||
}, [ isVisible, activeThreadIndex ]);
|
}, [isVisible, activeThreadIndex]);
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
if(hiddenThreadIndexes.indexOf(activeThreadIndex) >= 0) setActiveThreadIndex(0);
|
if(hiddenThreadIndexes.indexOf(activeThreadIndex) >= 0) setActiveThreadIndex(0);
|
||||||
}, [ activeThreadIndex, hiddenThreadIndexes ]);
|
}, [activeThreadIndex, hiddenThreadIndexes]);
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
@ -205,7 +207,7 @@ export const FriendsMessengerView: FC<{}> = props =>
|
|||||||
activeThread.setRead();
|
activeThread.setRead();
|
||||||
setUpdateValue({});
|
setUpdateValue({});
|
||||||
}
|
}
|
||||||
}, [ isVisible, messageThreads, activeThreadIndex ]);
|
}, [isVisible, messageThreads, activeThreadIndex]);
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
@ -222,7 +224,7 @@ export const FriendsMessengerView: FC<{}> = props =>
|
|||||||
|
|
||||||
for(const thread of visibleThreads)
|
for(const thread of visibleThreads)
|
||||||
{
|
{
|
||||||
if(thread.unread)
|
if(thread.unreadCount > 0)
|
||||||
{
|
{
|
||||||
isUnread = true;
|
isUnread = true;
|
||||||
|
|
||||||
@ -233,63 +235,71 @@ export const FriendsMessengerView: FC<{}> = props =>
|
|||||||
if(isUnread) PlaySound(MESSENGER_MESSAGE_RECEIVED);
|
if(isUnread) PlaySound(MESSENGER_MESSAGE_RECEIVED);
|
||||||
|
|
||||||
dispatchUiEvent(new FriendsMessengerIconEvent(FriendsMessengerIconEvent.UPDATE_ICON, isUnread ? FriendsMessengerIconEvent.UNREAD_ICON : FriendsMessengerIconEvent.SHOW_ICON));
|
dispatchUiEvent(new FriendsMessengerIconEvent(FriendsMessengerIconEvent.UPDATE_ICON, isUnread ? FriendsMessengerIconEvent.UNREAD_ICON : FriendsMessengerIconEvent.SHOW_ICON));
|
||||||
}, [ visibleThreads, updateValue ]);
|
}, [visibleThreads, updateValue]);
|
||||||
|
|
||||||
if(!isVisible) return null;
|
if(!isVisible) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NitroCardView className="nitro-friends-messenger" uniqueKey="nitro-friends-messenger" simple={ true }>
|
<NitroCardView className="nitro-friends-messenger" uniqueKey="nitro-friends-messenger" simple={true}>
|
||||||
<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>
|
||||||
<NitroLayoutFlex gap={ 2 } overflow="auto">
|
<NitroLayoutGrid>
|
||||||
{ visibleThreads && (visibleThreads.length > 0) && visibleThreads.map((thread, index) =>
|
<NitroLayoutGridColumn size={ 4 }>
|
||||||
|
<NitroLayoutBase className='text-black fw-bold fs-5'>{LocalizeText('toolbar.icon.label.messenger')}</NitroLayoutBase>
|
||||||
|
<NitroLayoutFlexColumn className='h-100 overflow-auto'>
|
||||||
|
{visibleThreads && (visibleThreads.length > 0) && visibleThreads.map((thread, index) =>
|
||||||
{
|
{
|
||||||
const messageThreadIndex = messageThreads.indexOf(thread);
|
const messageThreadIndex = messageThreads.indexOf(thread);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={ index } className="position-relative friend-head rounded flex-shrink-0 cursor-pointer bg-muted" onClick={ event => setActiveThreadIndex(messageThreadIndex) }>
|
<NitroLayoutFlex key={index} className={`open-chat-entry p-1 cursor-pointer rounded ${activeThreadIndex === messageThreadIndex ? 'active' : ''}`} onClick={event => setActiveThreadIndex(messageThreadIndex)}>
|
||||||
{ thread.unread &&
|
{thread.unread &&
|
||||||
<NitroLayoutBase className="position-absolute nitro-friends-spritesheet icon-new-message top-1 end-1 z-index-1" /> }
|
<ItemCountView count={ thread.unreadCount }/>
|
||||||
<AvatarImageView figure={ thread.participant.figure } headOnly={ true } direction={ 3 } />
|
}
|
||||||
|
<div className="friend-head rounded flex-shrink-0">
|
||||||
|
|
||||||
|
{thread.participant.id > 0 && <AvatarImageView figure={thread.participant.figure} headOnly={true} direction={3} />}
|
||||||
|
{thread.participant.id <= 0 && <BadgeImageView isGroup={true} badgeCode={thread.participant.figure} />}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
<NitroLayoutBase className='d-flex text-truncate text-black ms-1 align-items-center'>{thread.participant.name}</NitroLayoutBase>
|
||||||
|
</NitroLayoutFlex>
|
||||||
);
|
);
|
||||||
}) }
|
})}
|
||||||
</NitroLayoutFlex>
|
</NitroLayoutFlexColumn>
|
||||||
<NitroLayoutFlex className="align-items-center my-1" position="relative">
|
</NitroLayoutGridColumn>
|
||||||
{ (activeThreadIndex >= 0) &&
|
<NitroLayoutGridColumn size={ 8 }>
|
||||||
<NitroLayoutBase className="text-black bg-light pe-2 flex-none">
|
{(activeThreadIndex >= 0) &&
|
||||||
{ LocalizeText('messenger.window.separator', [ 'FRIEND_NAME' ], [ messageThreads[activeThreadIndex].participant.name ]) }
|
|
||||||
</NitroLayoutBase> }
|
|
||||||
<hr className="bg-dark m-0 w-100" />
|
|
||||||
</NitroLayoutFlex>
|
|
||||||
{ (activeThreadIndex >= 0) &&
|
|
||||||
<>
|
<>
|
||||||
<NitroLayoutFlex className="mb-2" gap={ 2 }>
|
<NitroLayoutBase className='mb-2 text-black text-center fw-bold fs-6'>{LocalizeText('messenger.window.separator', ['FRIEND_NAME'], [messageThreads[activeThreadIndex].participant.name])}</NitroLayoutBase>
|
||||||
|
<NitroLayoutFlex className="mb-2" gap={2}>
|
||||||
<NitroLayoutButtonGroup>
|
<NitroLayoutButtonGroup>
|
||||||
<NitroLayoutButton variant="primary" size="sm" onClick={ followFriend }>
|
<NitroLayoutButton variant="primary" size="sm" onClick={followFriend}>
|
||||||
<NitroLayoutBase className="nitro-friends-spritesheet icon-follow" />
|
<NitroLayoutBase className="nitro-friends-spritesheet icon-follow" />
|
||||||
</NitroLayoutButton>
|
</NitroLayoutButton>
|
||||||
<NitroLayoutButton variant="primary" size="sm" onClick={ openProfile }>
|
<NitroLayoutButton variant="primary" size="sm" onClick={openProfile}>
|
||||||
<NitroLayoutBase className="nitro-friends-spritesheet icon-profile-sm" />
|
<NitroLayoutBase className="nitro-friends-spritesheet icon-profile-sm" />
|
||||||
</NitroLayoutButton>
|
</NitroLayoutButton>
|
||||||
</NitroLayoutButtonGroup>
|
</NitroLayoutButtonGroup>
|
||||||
<NitroLayoutButton variant="danger" size="sm" onClick={ openProfile }>
|
<NitroLayoutButton variant="danger" size="sm" onClick={openProfile}>
|
||||||
{ LocalizeText('messenger.window.button.report') }
|
{LocalizeText('messenger.window.button.report')}
|
||||||
</NitroLayoutButton>
|
</NitroLayoutButton>
|
||||||
<NitroLayoutButton className="ms-auto" variant="primary" size="sm" onClick={ event => closeThread(activeThreadIndex) }>
|
<NitroLayoutButton className="ms-auto" variant="primary" size="sm" onClick={event => closeThread(activeThreadIndex)}>
|
||||||
<NitroLayoutBase className="fas fa-times" />
|
<NitroLayoutBase className="fas fa-times" />
|
||||||
</NitroLayoutButton>
|
</NitroLayoutButton>
|
||||||
</NitroLayoutFlex>
|
</NitroLayoutFlex>
|
||||||
<NitroLayoutFlexColumn innerRef={ messagesBox } className="bg-muted p-2 rounded chat-messages mb-2">
|
<NitroLayoutFlexColumn innerRef={messagesBox} className="bg-muted p-2 rounded chat-messages mb-2 h-100 w-100">
|
||||||
<FriendsMessengerThreadView thread={ messageThreads[activeThreadIndex] } />
|
<FriendsMessengerThreadView thread={messageThreads[activeThreadIndex]} />
|
||||||
</NitroLayoutFlexColumn>
|
</NitroLayoutFlexColumn>
|
||||||
<NitroLayoutFlex gap={ 2 }>
|
<NitroLayoutFlex gap={2}>
|
||||||
<input type="text" className="form-control form-control-sm" 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" placeholder={LocalizeText('messenger.window.input.default', ['FRIEND_NAME'], [messageThreads[activeThreadIndex].participant.name])} value={messageText} onChange={event => setMessageText(event.target.value)} onKeyDown={onKeyDown} />
|
||||||
<NitroLayoutButton variant="success" size="sm" onClick={ sendMessage }>
|
<NitroLayoutButton variant="success" size="sm" onClick={sendMessage}>
|
||||||
{ LocalizeText('widgets.chatinput.say') }
|
{LocalizeText('widgets.chatinput.say')}
|
||||||
</NitroLayoutButton>
|
</NitroLayoutButton>
|
||||||
</NitroLayoutFlex>
|
</NitroLayoutFlex>
|
||||||
</> }
|
</>}
|
||||||
|
</NitroLayoutGridColumn>
|
||||||
|
</NitroLayoutGrid>
|
||||||
</NitroCardContentView>
|
</NitroCardContentView>
|
||||||
</NitroCardView>
|
</NitroCardView>
|
||||||
);
|
);
|
||||||
|
@ -27,7 +27,7 @@ export const GroupSharedTabColorsView: FC<{}> = props =>
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
}, [ groupColors, groupColorsA, groupColorsB ]);
|
}, [dispatchGroupsState, groupColors, groupColorsA, groupColorsB]);
|
||||||
|
|
||||||
const getGroupColor = useCallback((colorIndex: number) =>
|
const getGroupColor = useCallback((colorIndex: number) =>
|
||||||
{
|
{
|
||||||
@ -63,7 +63,7 @@ export const GroupSharedTabColorsView: FC<{}> = props =>
|
|||||||
<div className="fw-bold">{ LocalizeText('group.edit.color.primary.color') }</div>
|
<div className="fw-bold">{ LocalizeText('group.edit.color.primary.color') }</div>
|
||||||
<div className="d-flex align-items-center gap-2">
|
<div className="d-flex align-items-center gap-2">
|
||||||
<div className="row row-cols-18 g-0 gap-1 w-100 h-100 overflow-auto">
|
<div className="row row-cols-18 g-0 gap-1 w-100 h-100 overflow-auto">
|
||||||
{ groupColorsA && groupColorsA.map((item, index) =>
|
{ groupColors && groupColorsA && groupColorsA.map((item, index) =>
|
||||||
{
|
{
|
||||||
return <div key={ index } className={ 'color-swatch cursor-pointer' + classNames({ ' active': groupColors[selectingColorIndex] === item.id }) } style={{ backgroundColor: '#' + item.color }} onClick={ () => selectColor(item.id) }></div>
|
return <div key={ index } className={ 'color-swatch cursor-pointer' + classNames({ ' active': groupColors[selectingColorIndex] === item.id }) } style={{ backgroundColor: '#' + item.color }} onClick={ () => selectColor(item.id) }></div>
|
||||||
}) }
|
}) }
|
||||||
|
Loading…
Reference in New Issue
Block a user