nitro-react/src/components/friends/FriendsView.tsx
2022-03-11 23:06:18 -05:00

372 lines
13 KiB
TypeScript

import { AcceptFriendMessageComposer, FriendListFragmentEvent, FriendListUpdateEvent, FriendParser, FriendRequestsEvent, GetFriendRequestsComposer, MessengerInitComposer, MessengerInitEvent, NewFriendRequestEvent, RequestFriendComposer, RoomEngineObjectEvent, RoomObjectCategory, RoomObjectUserType } from '@nitrots/nitro-renderer';
import { DeclineFriendMessageComposer } from '@nitrots/nitro-renderer/src';
import { FC, useCallback, useEffect, useMemo, useState } from 'react';
import { createPortal } from 'react-dom';
import { GetRoomSession, SendMessageComposer } from '../../api';
import { FriendEnteredRoomEvent, FriendListContentEvent, FriendRequestEvent, FriendsAcceptFriendRequestEvent, FriendsDeclineFriendRequestEvent, FriendsEvent, FriendsRequestCountEvent, FriendsSendFriendRequestEvent } from '../../events';
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 { FriendsMessengerView } from './views/messenger/FriendsMessengerView';
export const FriendsView: FC<{}> = props =>
{
const [ isReady, setIsReady ] = useState(false);
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) =>
{
for(const friend of friends)
{
if(friend.id === userId) return friend;
}
return null;
}, [ friends ]);
FriendsHelper.getFriend = getFriend;
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);
if(!userData || (userData.type !== RoomObjectUserType.getTypeNumber(RoomObjectUserType.USER))) return;
const friend = getFriend(userData.webID);
if(!friend) return;
DispatchUiEvent(new FriendEnteredRoomEvent(userData.roomIndex, RoomObjectCategory.UNIT, userData.webID, userData.name, userData.type));
}, [ getFriend ]);
UseRoomEngineEvent(RoomEngineObjectEvent.ADDED, onRoomEngineObjectEvent);
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 ]);
useEffect(() =>
{
SendMessageComposer(new MessengerInitComposer());
}, []);
useEffect(() =>
{
if(!settings) return;
setIsReady(true);
}, [ settings ]);
useEffect(() =>
{
DispatchUiEvent(new FriendsRequestCountEvent(requests.length));
}, [ requests ]);
return (
<FriendsContextProvider value={ { friends, requests, settings, canRequestFriend, requestFriend, acceptFriend, declineFriend } }>
{ isReady &&
createPortal(<FriendBarView onlineFriends={ onlineFriends } />, document.getElementById('toolbar-friend-bar-container')) }
{ isVisible &&
<FriendsListView onlineFriends={ onlineFriends } offlineFriends={ offlineFriends } friendRequests={ requests } onCloseClick={ () => setIsVisible(false) } /> }
<FriendsMessengerView />
</FriendsContextProvider>
);
}