mirror of
https://github.com/billsonnn/nitro-react.git
synced 2024-11-26 23:50:52 +01:00
Room invite + friend deletion
This commit is contained in:
parent
9666a4103a
commit
77819a7e2b
@ -92,5 +92,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
.nitro-friends-room-invite {
|
||||
width: $friends-list-width;
|
||||
}
|
||||
|
||||
.nitro-friends-remove-confirmation {
|
||||
width: $friends-list-width;
|
||||
}
|
||||
|
||||
@import "./views/friend-bar/FriendBarView";
|
||||
@import "./views/messenger/FriendsMessengerView";
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { FollowFriendMessageComposer, SetRelationshipStatusComposer } from '@nitrots/nitro-renderer';
|
||||
import classNames from 'classnames';
|
||||
import { FC, useCallback, useState } from 'react';
|
||||
import { LocalizeText, OpenMessengerChat } from '../../../../api';
|
||||
import { SendMessageHook } from '../../../../hooks';
|
||||
@ -9,7 +10,7 @@ import { FriendsGroupItemViewProps } from './FriendsGroupItemView.types';
|
||||
|
||||
export const FriendsGroupItemView: FC<FriendsGroupItemViewProps> = props =>
|
||||
{
|
||||
const { friend = null, selected = false, children = null, ...rest } = props;
|
||||
const { friend = null, selected = false, selectFriend = null, children = null, ...rest } = props;
|
||||
|
||||
const [ isExpanded, setIsExpanded ] = useState<boolean>(false);
|
||||
|
||||
@ -20,8 +21,10 @@ export const FriendsGroupItemView: FC<FriendsGroupItemViewProps> = props =>
|
||||
SendMessageHook(new FollowFriendMessageComposer(friend.id));
|
||||
}, [ friend ]);
|
||||
|
||||
const openMessengerChat = useCallback(() =>
|
||||
const openMessengerChat = useCallback((e) =>
|
||||
{
|
||||
e.stopPropagation();
|
||||
|
||||
if(!friend) return;
|
||||
|
||||
OpenMessengerChat(friend.id);
|
||||
@ -40,8 +43,16 @@ export const FriendsGroupItemView: FC<FriendsGroupItemViewProps> = props =>
|
||||
}
|
||||
}, [ friend ]);
|
||||
|
||||
const updateRelationship = useCallback((type: number) =>
|
||||
const initUpdateRelationship = useCallback((e) =>
|
||||
{
|
||||
e.stopPropagation();
|
||||
setIsExpanded(true);
|
||||
}, []);
|
||||
|
||||
const updateRelationship = useCallback((e, type: number) =>
|
||||
{
|
||||
e.stopPropagation();
|
||||
|
||||
if(type !== friend.relationshipStatus) SendMessageHook(new SetRelationshipStatusComposer(friend.id, type));
|
||||
|
||||
setIsExpanded(false);
|
||||
@ -50,8 +61,10 @@ export const FriendsGroupItemView: FC<FriendsGroupItemViewProps> = props =>
|
||||
if(!friend) return null;
|
||||
|
||||
return (
|
||||
<NitroLayoutFlex className="px-2 py-1 align-items-center" gap={ 1 } { ...rest }>
|
||||
<UserProfileIconView userId={ friend.id } />
|
||||
<NitroLayoutFlex className={ 'px-2 py-1 align-items-center' + classNames({ ' bg-primary text-white': selected }) } gap={ 1 } { ...rest } onClick={ selectFriend }>
|
||||
<div onClick={ (e) => e.stopPropagation() }>
|
||||
<UserProfileIconView userId={ friend.id } />
|
||||
</div>
|
||||
<div>{ friend.name }</div>
|
||||
<NitroLayoutFlex className="ms-auto align-items-center" gap={ 1 }>
|
||||
{ !isExpanded &&
|
||||
@ -60,14 +73,14 @@ export const FriendsGroupItemView: FC<FriendsGroupItemViewProps> = props =>
|
||||
<NitroLayoutBase onClick={ followFriend } className="nitro-friends-spritesheet icon-follow cursor-pointer" title={ LocalizeText('friendlist.tip.follow') } /> }
|
||||
{ friend.online &&
|
||||
<NitroLayoutBase className="nitro-friends-spritesheet icon-chat cursor-pointer" onClick={ openMessengerChat } title={ LocalizeText('friendlist.tip.im') } /> }
|
||||
<NitroLayoutBase className={ `nitro-friends-spritesheet icon-${ getCurrentRelationshipName() } cursor-pointer` }onClick={ event => setIsExpanded(true) } title={ LocalizeText('infostand.link.relationship') } />
|
||||
<NitroLayoutBase className={ `nitro-friends-spritesheet icon-${ getCurrentRelationshipName() } cursor-pointer` } onClick={ initUpdateRelationship } title={ LocalizeText('infostand.link.relationship') } />
|
||||
</> }
|
||||
{ isExpanded &&
|
||||
<>
|
||||
<NitroLayoutBase className="nitro-friends-spritesheet icon-heart cursor-pointer" onClick={ () => updateRelationship(MessengerFriend.RELATIONSHIP_HEART) } />
|
||||
<NitroLayoutBase className="nitro-friends-spritesheet icon-smile cursor-pointer" onClick={ () => updateRelationship(MessengerFriend.RELATIONSHIP_SMILE) } />
|
||||
<NitroLayoutBase className="nitro-friends-spritesheet icon-bobba cursor-pointer" onClick={ () => updateRelationship(MessengerFriend.RELATIONSHIP_BOBBA) } />
|
||||
<NitroLayoutBase className="nitro-friends-spritesheet icon-none cursor-pointer" onClick={ () => updateRelationship(MessengerFriend.RELATIONSHIP_NONE) } />
|
||||
<NitroLayoutBase className="nitro-friends-spritesheet icon-heart cursor-pointer" onClick={ (e) => updateRelationship(e, MessengerFriend.RELATIONSHIP_HEART) } />
|
||||
<NitroLayoutBase className="nitro-friends-spritesheet icon-smile cursor-pointer" onClick={ (e) => updateRelationship(e, MessengerFriend.RELATIONSHIP_SMILE) } />
|
||||
<NitroLayoutBase className="nitro-friends-spritesheet icon-bobba cursor-pointer" onClick={ (e) => updateRelationship(e, MessengerFriend.RELATIONSHIP_BOBBA) } />
|
||||
<NitroLayoutBase className="nitro-friends-spritesheet icon-none cursor-pointer" onClick={ (e) => updateRelationship(e, MessengerFriend.RELATIONSHIP_NONE) } />
|
||||
</> }
|
||||
</NitroLayoutFlex>
|
||||
{ children }
|
||||
|
@ -5,4 +5,5 @@ export interface FriendsGroupItemViewProps extends NitroLayoutFlexProps
|
||||
{
|
||||
friend: MessengerFriend;
|
||||
selected?: boolean;
|
||||
selectFriend: () => void;
|
||||
}
|
||||
|
@ -4,15 +4,15 @@ import { FriendsGroupViewProps } from './FriendsGroupView.types';
|
||||
|
||||
export const FriendsGroupView: FC<FriendsGroupViewProps> = props =>
|
||||
{
|
||||
const { list = null } = props;
|
||||
const { list = null, selectedFriendsIds = null, selectFriend = null } = props;
|
||||
|
||||
if(!list) return null;
|
||||
|
||||
return (
|
||||
<>
|
||||
{ list.map((item, index) =>
|
||||
{ selectedFriendsIds && list && list.map((item, index) =>
|
||||
{
|
||||
return <FriendsGroupItemView key={ index } friend={ item } />;
|
||||
return <FriendsGroupItemView key={ index } friend={ item } selected={ selectedFriendsIds.includes(item.id) } selectFriend={ () => selectFriend(item.id) } />;
|
||||
}) }
|
||||
</>
|
||||
);
|
||||
|
@ -3,4 +3,6 @@ import { MessengerFriend } from '../../common/MessengerFriend';
|
||||
export interface FriendsGroupViewProps
|
||||
{
|
||||
list: MessengerFriend[];
|
||||
selectedFriendsIds: number[];
|
||||
selectFriend: (userId: number) => void;
|
||||
}
|
||||
|
@ -1,9 +1,13 @@
|
||||
import { FC, useEffect, useState } from 'react';
|
||||
import { RemoveFriendComposer, SendRoomInviteComposer } from '@nitrots/nitro-renderer';
|
||||
import { FC, useCallback, useMemo, useState } from 'react';
|
||||
import { LocalizeText } from '../../../../api';
|
||||
import { SendMessageHook } from '../../../../hooks';
|
||||
import { NitroCardAccordionSetView, NitroCardAccordionView, NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../../../layout';
|
||||
import { MessengerFriend } from '../../common/MessengerFriend';
|
||||
import { FriendsGroupView } from '../friends-group/FriendsGroupView';
|
||||
import { FriendsRemoveConfirmationView } from '../friends-remove-confirmation/FriendsRemoveConfirmationView';
|
||||
import { FriendsRequestView } from '../friends-request/FriendsRequestView';
|
||||
import { FriendsRoomInviteView } from '../friends-room-invite/FriendsRoomInviteView';
|
||||
import { FriendsSearchView } from '../friends-search/FriendsSearchView';
|
||||
import { FriendsListViewProps } from './FriendsListView.types';
|
||||
|
||||
@ -13,39 +17,107 @@ const MODE_SEARCH: number = 1;
|
||||
export const FriendsListView: FC<FriendsListViewProps> = props =>
|
||||
{
|
||||
const { onlineFriends = [], offlineFriends = [], friendRequests = [], onCloseClick = null } = props;
|
||||
const [ selectedFriends, setSelectedFriends ] = useState<MessengerFriend[]>([]);
|
||||
const [ mode, setMode ] = useState<number>(0);
|
||||
|
||||
useEffect(() =>
|
||||
const [ selectedFriendsIds, setSelectedFriendsIds ] = useState<number[]>([]);
|
||||
const [ mode, setMode ] = useState<number>(0);
|
||||
|
||||
const [ showRoomInvite, setShowRoomInvite ] = useState<boolean>(false);
|
||||
const [ showRemoveFriendsConfirmation, setShowRemoveFriendsConfirmation ] = useState<boolean>(false);
|
||||
|
||||
const removeFriendsText = useMemo(() =>
|
||||
{
|
||||
setSelectedFriends([]);
|
||||
}, [ onlineFriends, offlineFriends ]);
|
||||
if(!selectedFriendsIds || !selectedFriendsIds.length) return '';
|
||||
|
||||
const userNames: string[] = [];
|
||||
|
||||
for(const userId of selectedFriendsIds)
|
||||
{
|
||||
let existingFriend: MessengerFriend = onlineFriends.find(f => f.id === userId);
|
||||
|
||||
if(!existingFriend) existingFriend = offlineFriends.find(f => f.id === userId);
|
||||
|
||||
if(!existingFriend) continue;
|
||||
|
||||
userNames.push(existingFriend.name);
|
||||
}
|
||||
|
||||
return LocalizeText('friendlist.removefriendconfirm.userlist', ['user_names'], [userNames.join(', ')]);
|
||||
}, [offlineFriends, onlineFriends, selectedFriendsIds]);
|
||||
|
||||
const selectFriend = useCallback((userId: number) =>
|
||||
{
|
||||
if(userId < 0) return;
|
||||
|
||||
const existingUserIdIndex: number = selectedFriendsIds.indexOf(userId);
|
||||
|
||||
if(existingUserIdIndex > -1)
|
||||
{
|
||||
const clonedFriend = [...selectedFriendsIds];
|
||||
clonedFriend.splice(existingUserIdIndex, 1)
|
||||
|
||||
setSelectedFriendsIds([...clonedFriend]);
|
||||
}
|
||||
else
|
||||
{
|
||||
setSelectedFriendsIds([...selectedFriendsIds, userId]);
|
||||
}
|
||||
}, [ selectedFriendsIds, setSelectedFriendsIds ]);
|
||||
|
||||
const sendRoomInvite = useCallback((message: string) =>
|
||||
{
|
||||
if(selectedFriendsIds.length === 0 || !message || message.length === 0) return;
|
||||
|
||||
SendMessageHook(new SendRoomInviteComposer(message, ...selectedFriendsIds));
|
||||
setShowRoomInvite(false);
|
||||
}, [ selectedFriendsIds, setShowRoomInvite ]);
|
||||
|
||||
const removeSelectedFriends = useCallback(() =>
|
||||
{
|
||||
if(selectedFriendsIds.length === 0) return;
|
||||
|
||||
SendMessageHook(new RemoveFriendComposer(...selectedFriendsIds));
|
||||
setSelectedFriendsIds([]);
|
||||
setShowRemoveFriendsConfirmation(false);
|
||||
}, [ selectedFriendsIds ]);
|
||||
|
||||
return (
|
||||
<NitroCardView className="nitro-friends" uniqueKey="nitro-friends">
|
||||
<NitroCardHeaderView headerText={ LocalizeText('friendlist.friends') } onCloseClick={ onCloseClick } />
|
||||
<NitroCardTabsView>
|
||||
<NitroCardTabsItemView isActive={ (mode === MODE_FRIENDS) } count={ friendRequests.length } onClick={ event => setMode(MODE_FRIENDS) }>
|
||||
{ LocalizeText('friendlist.friends') }
|
||||
</NitroCardTabsItemView>
|
||||
<NitroCardTabsItemView isActive={ (mode === MODE_SEARCH) } onClick={ event => setMode(MODE_SEARCH) }>
|
||||
{ LocalizeText('generic.search') }
|
||||
</NitroCardTabsItemView>
|
||||
</NitroCardTabsView>
|
||||
<NitroCardContentView className="p-0 text-black">
|
||||
{ (mode === MODE_FRIENDS) &&
|
||||
<NitroCardAccordionView>
|
||||
<NitroCardAccordionSetView headerText={ LocalizeText('friendlist.friends') + ` (${onlineFriends.length})` } isExpanded={ true }>
|
||||
<FriendsGroupView list={ onlineFriends } />
|
||||
</NitroCardAccordionSetView>
|
||||
<NitroCardAccordionSetView headerText={ LocalizeText('friendlist.friends.offlinecaption') + ` (${offlineFriends.length})` }>
|
||||
<FriendsGroupView list={ offlineFriends } />
|
||||
</NitroCardAccordionSetView>
|
||||
<FriendsRequestView requests={ friendRequests } />
|
||||
</NitroCardAccordionView> }
|
||||
{ (mode === MODE_SEARCH) &&
|
||||
<FriendsSearchView /> }
|
||||
</NitroCardContentView>
|
||||
</NitroCardView>
|
||||
<>
|
||||
<NitroCardView className="nitro-friends" uniqueKey="nitro-friends">
|
||||
<NitroCardHeaderView headerText={ LocalizeText('friendlist.friends') } onCloseClick={ onCloseClick } />
|
||||
<NitroCardTabsView>
|
||||
<NitroCardTabsItemView isActive={ (mode === MODE_FRIENDS) } count={ friendRequests.length } onClick={ event => setMode(MODE_FRIENDS) }>
|
||||
{ LocalizeText('friendlist.friends') }
|
||||
</NitroCardTabsItemView>
|
||||
<NitroCardTabsItemView isActive={ (mode === MODE_SEARCH) } onClick={ event => setMode(MODE_SEARCH) }>
|
||||
{ LocalizeText('generic.search') }
|
||||
</NitroCardTabsItemView>
|
||||
</NitroCardTabsView>
|
||||
<NitroCardContentView className="p-0 text-black">
|
||||
{ (mode === MODE_FRIENDS) &&
|
||||
<>
|
||||
<NitroCardAccordionView className="overflow-y-auto">
|
||||
<NitroCardAccordionSetView headerText={ LocalizeText('friendlist.friends') + ` (${onlineFriends.length})` } isExpanded={ true }>
|
||||
<FriendsGroupView list={ onlineFriends } selectedFriendsIds={ selectedFriendsIds } selectFriend={ selectFriend } />
|
||||
</NitroCardAccordionSetView>
|
||||
<NitroCardAccordionSetView headerText={ LocalizeText('friendlist.friends.offlinecaption') + ` (${offlineFriends.length})` }>
|
||||
<FriendsGroupView list={ offlineFriends } selectedFriendsIds={ selectedFriendsIds } selectFriend={ selectFriend } />
|
||||
</NitroCardAccordionSetView>
|
||||
<FriendsRequestView requests={ friendRequests } />
|
||||
</NitroCardAccordionView>
|
||||
{ selectedFriendsIds && selectedFriendsIds.length > 0 && <div className="d-flex gap-2 p-2">
|
||||
<button className="btn btn-primary w-100" onClick={ () => setShowRoomInvite(true) }>Invite</button>
|
||||
<button className="btn btn-danger w-100" onClick={ () => setShowRemoveFriendsConfirmation(true) }>Delete</button>
|
||||
</div> }
|
||||
</>
|
||||
}
|
||||
{ (mode === MODE_SEARCH) &&
|
||||
<FriendsSearchView /> }
|
||||
</NitroCardContentView>
|
||||
</NitroCardView>
|
||||
{ showRoomInvite &&
|
||||
<FriendsRoomInviteView selectedFriendsIds={ selectedFriendsIds } onCloseClick={ () => setShowRoomInvite(false) } sendRoomInvite={ sendRoomInvite } /> }
|
||||
{ showRemoveFriendsConfirmation &&
|
||||
<FriendsRemoveConfirmationView selectedFriendsIds={ selectedFriendsIds } removeFriendsText={ removeFriendsText } onCloseClick={ () => setShowRemoveFriendsConfirmation(false) } removeSelectedFriends={ removeSelectedFriends } /> }
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -0,0 +1,22 @@
|
||||
import { FC } from 'react';
|
||||
import { LocalizeText } from '../../../../api';
|
||||
import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout';
|
||||
import { FriendsRemoveConfirmationViewProps } from './FriendsRemoveConfirmationView.types';
|
||||
|
||||
export const FriendsRemoveConfirmationView: FC<FriendsRemoveConfirmationViewProps> = props =>
|
||||
{
|
||||
const { selectedFriendsIds = null, removeFriendsText = null, removeSelectedFriends = null, onCloseClick = null } = props;
|
||||
|
||||
return (
|
||||
<NitroCardView className="nitro-friends-remove-confirmation" uniqueKey="nitro-friends-remove-confirmation" simple={ true }>
|
||||
<NitroCardHeaderView headerText={ LocalizeText('friendlist.removefriendconfirm.title') } onCloseClick={ onCloseClick } />
|
||||
<NitroCardContentView className="text-black d-flex flex-column gap-3">
|
||||
<div>{ removeFriendsText }</div>
|
||||
<div className="d-flex gap-2">
|
||||
<button className="btn btn-danger w-100" disabled={ selectedFriendsIds.length === 0 } onClick={ removeSelectedFriends }>{ LocalizeText('generic.ok') }</button>
|
||||
<button className="btn btn-primary w-100" onClick={ onCloseClick }>{ LocalizeText('generic.cancel') }</button>
|
||||
</div>
|
||||
</NitroCardContentView>
|
||||
</NitroCardView>
|
||||
);
|
||||
};
|
@ -0,0 +1,7 @@
|
||||
export interface FriendsRemoveConfirmationViewProps
|
||||
{
|
||||
selectedFriendsIds: number[];
|
||||
removeFriendsText: string;
|
||||
removeSelectedFriends: () => void;
|
||||
onCloseClick: () => void;
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
import { FC, useState } from 'react';
|
||||
import { LocalizeText } from '../../../../api';
|
||||
import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout';
|
||||
import { FriendsRoomInviteViewProps } from './FriendsRoomInviteView.types';
|
||||
|
||||
export const FriendsRoomInviteView: FC<FriendsRoomInviteViewProps> = props =>
|
||||
{
|
||||
const { selectedFriendsIds = null, onCloseClick = null, sendRoomInvite = null } = props;
|
||||
|
||||
const [ roomInviteMessage, setRoomInviteMessage ] = useState<string>('');
|
||||
|
||||
return (
|
||||
<NitroCardView className="nitro-friends-room-invite" uniqueKey="nitro-friends-room-invite" simple={ true }>
|
||||
<NitroCardHeaderView headerText={ LocalizeText('friendlist.invite.title') } onCloseClick={ onCloseClick } />
|
||||
<NitroCardContentView className="text-black d-flex flex-column gap-2">
|
||||
{ LocalizeText('friendlist.invite.summary', ['count'], [selectedFriendsIds.length.toString()]) }
|
||||
<textarea className="form-control" value={roomInviteMessage} onChange={e => setRoomInviteMessage(e.target.value)}></textarea>
|
||||
<div className="bg-muted rounded text-center p-2">{ LocalizeText('friendlist.invite.note') }</div>
|
||||
<div className="d-flex gap-2">
|
||||
<button className="btn btn-success w-100" disabled={ roomInviteMessage.length === 0 || selectedFriendsIds.length === 0 } onClick={ () => sendRoomInvite(roomInviteMessage) }>{ LocalizeText('friendlist.invite.send') }</button>
|
||||
<button className="btn btn-primary w-100" onClick={ onCloseClick }>{ LocalizeText('generic.cancel') }</button>
|
||||
</div>
|
||||
</NitroCardContentView>
|
||||
</NitroCardView>
|
||||
);
|
||||
};
|
@ -0,0 +1,6 @@
|
||||
export interface FriendsRoomInviteViewProps
|
||||
{
|
||||
selectedFriendsIds: number[];
|
||||
onCloseClick: () => void;
|
||||
sendRoomInvite: (message: string) => void;
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
import { FollowFriendMessageComposer, ILinkEventTracker, NewConsoleMessageEvent, SendMessageComposer } from '@nitrots/nitro-renderer';
|
||||
import { FollowFriendMessageComposer, ILinkEventTracker, NewConsoleMessageEvent, RoomInviteEvent, SendMessageComposer } from '@nitrots/nitro-renderer';
|
||||
import { FC, KeyboardEvent, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { AddEventLinkTracker, GetSessionDataManager, GetUserProfile, LocalizeText, RemoveLinkEventTracker } from '../../../../api';
|
||||
import { MESSENGER_MESSAGE_RECEIVED, MESSENGER_NEW_THREAD, PlaySound } from '../../../../api/utils/PlaySound';
|
||||
@ -105,6 +105,21 @@ export const FriendsMessengerView: FC<{}> = props =>
|
||||
|
||||
CreateMessageHook(NewConsoleMessageEvent, onNewConsoleMessageEvent);
|
||||
|
||||
const onRoomInviteEvent = useCallback((event: RoomInviteEvent) =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
|
||||
const [threadIndex, thread] = getMessageThreadWithIndex(parser.senderId);
|
||||
|
||||
if((threadIndex === -1) || !thread) return;
|
||||
|
||||
thread.addMessage(parser.senderId, parser.messageText, 0, null, MessengerThreadChat.ROOM_INVITE);
|
||||
|
||||
setMessageThreads(prevValue => [...prevValue]);
|
||||
}, [getMessageThreadWithIndex]);
|
||||
|
||||
CreateMessageHook(RoomInviteEvent, onRoomInviteEvent);
|
||||
|
||||
const sendMessage = useCallback(() =>
|
||||
{
|
||||
if(!messageText || !messageText.length) return;
|
||||
|
@ -119,7 +119,7 @@ export const RoomToolsWidgetView: FC<{}> = props =>
|
||||
<div className="h4 text-muted m-0">{ roomOwner }</div>
|
||||
</div>
|
||||
{ roomTags && roomTags.length > 0 && <div className="d-flex gap-2">
|
||||
{ roomTags.map(tag =>
|
||||
{ roomTags.map((tag: string) =>
|
||||
{
|
||||
return <div className="rounded bg-primary text-white p-1 text-sm">#{ tag }</div>
|
||||
}) }
|
||||
|
Loading…
Reference in New Issue
Block a user