diff --git a/src/views/friends/FriendsView.tsx b/src/views/friends/FriendsView.tsx index 768698c2..429f201b 100644 --- a/src/views/friends/FriendsView.tsx +++ b/src/views/friends/FriendsView.tsx @@ -3,7 +3,7 @@ import { DeclineFriendMessageComposer } from '@nitrots/nitro-renderer/src'; import { FC, useCallback, useEffect, useMemo, useState } from 'react'; import { createPortal } from 'react-dom'; import { GetRoomSession } from '../../api'; -import { FriendEnteredRoomEvent, FriendListContentEvent, FriendsEvent, FriendsRequestCountEvent } from '../../events'; +import { FriendEnteredRoomEvent, FriendListContentEvent, FriendRequestEvent, FriendsAcceptFriendRequestEvent, FriendsDeclineFriendRequestEvent, FriendsEvent, FriendsRequestCountEvent } from '../../events'; import { FriendsSendFriendRequestEvent } from '../../events/friends/FriendsSendFriendRequestEvent'; import { CreateMessageHook, useRoomEngineEvent } from '../../hooks'; import { dispatchUiEvent, useUiEvent } from '../../hooks/events/ui/ui-event'; @@ -71,18 +71,17 @@ export const FriendsView: FC<{}> = props => { setRequests(prevValue => { - const newRequests: MessengerRequest[] = []; + const newRequests: MessengerRequest[] = [ ...prevValue ]; - for(const request of prevValue) + const index = newRequests.findIndex(request => (request.requesterUserId === userId)); + + if(index >= 0) { - if(request.requesterUserId !== userId) - { - newRequests.push(request); - } - else - { - SendMessageHook(new AcceptFriendMessageComposer(request.id)); - } + SendMessageHook(new AcceptFriendMessageComposer(newRequests[index].id)); + + dispatchUiEvent(new FriendRequestEvent(FriendRequestEvent.ACCEPTED, userId)); + + newRequests.splice(index, 1); } return newRequests; @@ -97,22 +96,23 @@ export const FriendsView: FC<{}> = props => { SendMessageHook(new DeclineFriendMessageComposer(true)); + for(const request of prevValue) dispatchUiEvent(new FriendRequestEvent(FriendRequestEvent.DECLINED, request.requesterUserId)); + return []; } else { - const newRequests: MessengerRequest[] = []; + const newRequests: MessengerRequest[] = [ ...prevValue ]; - for(const request of prevValue) + const index = newRequests.findIndex(request => (request.requesterUserId === userId)); + + if(index >= 0) { - if(request.requesterUserId !== userId) - { - newRequests.push(request); - } - else - { - SendMessageHook(new DeclineFriendMessageComposer(false, request.id)); - } + SendMessageHook(new DeclineFriendMessageComposer(false, newRequests[index].id)); + + dispatchUiEvent(new FriendRequestEvent(FriendRequestEvent.DECLINED, userId)); + + newRequests.splice(index, 1); } return newRequests; @@ -237,10 +237,15 @@ export const FriendsView: FC<{}> = props => { const newRequests = [ ...prevValue ]; - const newRequest = new MessengerRequest(); - newRequest.populate(request); + const index = newRequests.findIndex(existing => (existing.requesterUserId === request.requesterUserId)); - newRequests.push(newRequest); + if(index === -1) + { + const newRequest = new MessengerRequest(); + newRequest.populate(request); + + newRequests.push(newRequest); + } return newRequests; }); @@ -273,6 +278,20 @@ export const FriendsView: FC<{}> = props => 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(); diff --git a/src/views/friends/views/friends-request/FriendsRequestView.tsx b/src/views/friends/views/friends-request/FriendsRequestView.tsx index d2ac8bc7..262cb24d 100644 --- a/src/views/friends/views/friends-request/FriendsRequestView.tsx +++ b/src/views/friends/views/friends-request/FriendsRequestView.tsx @@ -14,9 +14,9 @@ export const FriendsRequestView: FC = props => return ( - { requests.map(request => + { requests.map((request, index) => { - return + return }) } declineFriend(-1, true) }> diff --git a/src/views/room/widgets/RoomWidgets.scss b/src/views/room/widgets/RoomWidgets.scss index 6c2a2f2b..46b5281c 100644 --- a/src/views/room/widgets/RoomWidgets.scss +++ b/src/views/room/widgets/RoomWidgets.scss @@ -1,11 +1,12 @@ @import './avatar-info/AvatarInfoWidgetView'; @import './chat/ChatWidgetView'; @import './chat-input/ChatInputView'; +@import './choosers/ChooserWidgetView'; @import './context-menu/ContextMenu'; @import './doorbell/DoorbellWidgetView'; +@import './friend-request/FriendRequestDialogView'; @import './furniture/FurnitureWidgets'; @import './infostand/InfoStandWidgetView'; @import './object-location/ObjectLocationView'; @import './room-tools/RoomToolsWidgetView'; -@import './choosers/ChooserWidgetView'; @import './word-quiz/WordQuizWidgetView'; diff --git a/src/views/room/widgets/RoomWidgetsView.tsx b/src/views/room/widgets/RoomWidgetsView.tsx index b311b9d5..0521523a 100644 --- a/src/views/room/widgets/RoomWidgetsView.tsx +++ b/src/views/room/widgets/RoomWidgetsView.tsx @@ -1,7 +1,8 @@ import { RoomEngineEvent, RoomEngineObjectEvent, RoomEngineRoomAdEvent, RoomEngineTriggerWidgetEvent, RoomEngineUseProductEvent, RoomId, RoomObjectCategory, RoomObjectOperationType, RoomObjectVariable, RoomSessionChatEvent, RoomSessionDanceEvent, RoomSessionDimmerPresetsEvent, RoomSessionDoorbellEvent, RoomSessionErrorMessageEvent, RoomSessionEvent, RoomSessionFriendRequestEvent, RoomSessionPetInfoUpdateEvent, RoomSessionPollEvent, RoomSessionPresentEvent, RoomSessionUserBadgesEvent, RoomSessionWordQuizEvent, RoomZoomEvent } from '@nitrots/nitro-renderer'; import { FC, useCallback } from 'react'; import { CanManipulateFurniture, GetRoomEngine, GetSessionDataManager, IsFurnitureSelectionDisabled, LocalizeText, ProcessRoomObjectOperation, RoomWidgetFurniToWidgetMessage, RoomWidgetUpdateRoomEngineEvent, RoomWidgetUpdateRoomObjectEvent } from '../../../api'; -import { useRoomEngineEvent, useRoomSessionManagerEvent } from '../../../hooks/events'; +import { FriendRequestEvent } from '../../../events'; +import { useRoomEngineEvent, useRoomSessionManagerEvent, useUiEvent } from '../../../hooks'; import { NotificationAlertType } from '../../notification-center/common/NotificationAlertType'; import { NotificationUtilities } from '../../notification-center/common/NotificationUtilities'; import { useRoomContext } from '../context/RoomContext'; @@ -11,6 +12,7 @@ import { ChatWidgetView } from './chat/ChatWidgetView'; import { FurniChooserWidgetView } from './choosers/FurniChooserWidgetView'; import { UserChooserWidgetView } from './choosers/UserChooserWidgetView'; import { DoorbellWidgetView } from './doorbell/DoorbellWidgetView'; +import { FriendRequestWidgetView } from './friend-request/FriendRequestWidgetView'; import { FurnitureWidgetsView } from './furniture/FurnitureWidgetsView'; import { InfoStandWidgetView } from './infostand/InfoStandWidgetView'; import { RoomThumbnailWidgetView } from './room-thumbnail/RoomThumbnailWidgetView'; @@ -275,6 +277,8 @@ export const RoomWidgetsView: FC<{}> = props => useRoomSessionManagerEvent(RoomSessionPollEvent.OFFER, onRoomSessionEvent); useRoomSessionManagerEvent(RoomSessionPollEvent.ERROR, onRoomSessionEvent); useRoomSessionManagerEvent(RoomSessionPollEvent.CONTENT, onRoomSessionEvent); + useUiEvent(FriendRequestEvent.ACCEPTED, onRoomSessionEvent); + useUiEvent(FriendRequestEvent.DECLINED, onRoomSessionEvent); const onRoomSessionErrorMessageEvent = useCallback((event: RoomSessionErrorMessageEvent) => { @@ -357,6 +361,7 @@ export const RoomWidgetsView: FC<{}> = props => + ); } diff --git a/src/views/room/widgets/friend-request/FriendRequestDialogView.scss b/src/views/room/widgets/friend-request/FriendRequestDialogView.scss new file mode 100644 index 00000000..f6ea6f32 --- /dev/null +++ b/src/views/room/widgets/friend-request/FriendRequestDialogView.scss @@ -0,0 +1,4 @@ +.nitro-friend-request-dialog { + width: unset; + max-width: 200px; +} diff --git a/src/views/room/widgets/friend-request/FriendRequestDialogView.tsx b/src/views/room/widgets/friend-request/FriendRequestDialogView.tsx new file mode 100644 index 00000000..1b9d4a82 --- /dev/null +++ b/src/views/room/widgets/friend-request/FriendRequestDialogView.tsx @@ -0,0 +1,47 @@ +import { FC, useCallback } from 'react'; +import { LocalizeText, RoomWidgetFriendRequestMessage } from '../../../../api'; +import { NitroLayoutButton, NitroLayoutFlex, NitroLayoutFlexColumn } from '../../../../layout'; +import { NitroLayoutBase } from '../../../../layout/base'; +import { useRoomContext } from '../../context/RoomContext'; +import { UserLocationView } from '../user-location/UserLocationView'; +import { FriendRequestDialogViewProps } from './FriendRequestDialogView.types'; + +export const FriendRequestDialogView: FC = props => +{ + const { requestId = -1, userId = -1, userName = null, close = null } = props; + const { widgetHandler = null } = useRoomContext(); + + const accept = useCallback(() => + { + widgetHandler.processWidgetMessage(new RoomWidgetFriendRequestMessage(RoomWidgetFriendRequestMessage.ACCEPT, requestId)); + + close(); + }, [ requestId, widgetHandler, close ]); + + const decline = useCallback(() => + { + widgetHandler.processWidgetMessage(new RoomWidgetFriendRequestMessage(RoomWidgetFriendRequestMessage.ACCEPT, requestId)); + + close(); + }, [ requestId, widgetHandler, close ]); + + return ( + + + + + { LocalizeText('widget.friendrequest.from', [ 'username' ], [ userName ]) } + + + + { LocalizeText('widget.friendrequest.decline') } + + + { LocalizeText('widget.friendrequest.accept') } + + + + + + ); +} diff --git a/src/views/room/widgets/friend-request/FriendRequestDialogView.types.ts b/src/views/room/widgets/friend-request/FriendRequestDialogView.types.ts new file mode 100644 index 00000000..c9deed82 --- /dev/null +++ b/src/views/room/widgets/friend-request/FriendRequestDialogView.types.ts @@ -0,0 +1,7 @@ +export interface FriendRequestDialogViewProps +{ + requestId: number; + userId: number; + userName: string; + close: () => void; +} diff --git a/src/views/room/widgets/friend-request/FriendRequestWidgetView.tsx b/src/views/room/widgets/friend-request/FriendRequestWidgetView.tsx new file mode 100644 index 00000000..9a0bf147 --- /dev/null +++ b/src/views/room/widgets/friend-request/FriendRequestWidgetView.tsx @@ -0,0 +1,70 @@ +import { FC, useCallback, useState } from 'react'; +import { RoomWidgetUpdateFriendRequestEvent } from '../../../../api'; +import { CreateEventDispatcherHook } from '../../../../hooks'; +import { useRoomContext } from '../../context/RoomContext'; +import { FriendRequestDialogView } from './FriendRequestDialogView'; + +export const FriendRequestWidgetView: FC<{}> = props => +{ + const [ friendRequests, setFriendRequests ] = useState<{ requestId: number, userId: number, userName: string }[]>([]); + const { eventDispatcher = null } = useRoomContext(); + + const showFriendRequest = useCallback((requestId: number, userId: number, userName: string) => + { + const index = friendRequests.findIndex(value => (value.userId === userId)); + + if(index >= 0) return; + + setFriendRequests(prevValue => + { + const newValue = [ ...prevValue ]; + + newValue.push({ requestId, userId, userName }); + + return newValue; + }); + }, [ friendRequests ]); + + const hideFriendRequest = useCallback((requestId: number) => + { + const index = friendRequests.findIndex(value => (value.requestId === requestId)); + + if(index === -1) return; + + 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: + showFriendRequest(event.requestId, event.userId, event.userName); + return; + case RoomWidgetUpdateFriendRequestEvent.HIDE_FRIEND_REQUEST: + hideFriendRequest(event.requestId); + return; + } + }, [ showFriendRequest, hideFriendRequest ]); + + CreateEventDispatcherHook(RoomWidgetUpdateFriendRequestEvent.SHOW_FRIEND_REQUEST, eventDispatcher, onRoomWidgetUpdateFriendRequestEvent); + CreateEventDispatcherHook(RoomWidgetUpdateFriendRequestEvent.HIDE_FRIEND_REQUEST, eventDispatcher, onRoomWidgetUpdateFriendRequestEvent); + + if(!friendRequests.length) return null; + + return ( + <> + { friendRequests.map((request, index) => + { + return hideFriendRequest(request.userId) } /> + }) } + + ); +} diff --git a/src/views/room/widgets/object-location/ObjectLocationView.tsx b/src/views/room/widgets/object-location/ObjectLocationView.tsx index 8e10a54b..c7df0d2a 100644 --- a/src/views/room/widgets/object-location/ObjectLocationView.tsx +++ b/src/views/room/widgets/object-location/ObjectLocationView.tsx @@ -1,10 +1,11 @@ import { FC, useCallback, useEffect, useRef, useState } from 'react'; import { GetNitroInstance, GetRoomEngine, GetRoomSession } from '../../../../api'; +import { NitroLayoutBase } from '../../../../layout/base'; import { ObjectLocationViewProps } from './ObjectLocationView.types'; export const ObjectLocationView: FC = props => { - const { objectId = -1, category = -1, noFollow = false, children = null } = props; + const { objectId = -1, category = -1, noFollow = false, children = null, ...rest } = props; const [ pos, setPos ] = useState<{ x: number, y: number }>({ x: -1, y: -1 }); const elementRef = useRef(); @@ -50,8 +51,8 @@ export const ObjectLocationView: FC = props => }, [ updatePosition, noFollow ]); return ( -
-1 ? 'visible' : 'invisible') } style={ { left: pos.x, top: pos.y } }> + -1 ? 'visible' : 'invisible') } style={ { left: pos.x, top: pos.y } } { ...rest }> { children } -
+ ); } diff --git a/src/views/room/widgets/object-location/ObjectLocationView.types.ts b/src/views/room/widgets/object-location/ObjectLocationView.types.ts index 8c29df71..0da23b4b 100644 --- a/src/views/room/widgets/object-location/ObjectLocationView.types.ts +++ b/src/views/room/widgets/object-location/ObjectLocationView.types.ts @@ -1,4 +1,6 @@ -export interface ObjectLocationViewProps +import { NitroLayoutBaseProps } from '../../../../layout/base'; + +export interface ObjectLocationViewProps extends NitroLayoutBaseProps { objectId: number; category: number; diff --git a/src/views/room/widgets/user-location/UserLocationView.tsx b/src/views/room/widgets/user-location/UserLocationView.tsx new file mode 100644 index 00000000..c8dd2364 --- /dev/null +++ b/src/views/room/widgets/user-location/UserLocationView.tsx @@ -0,0 +1,19 @@ +import { RoomObjectCategory } from '@nitrots/nitro-renderer'; +import { FC } from 'react'; +import { useRoomContext } from '../../context/RoomContext'; +import { ObjectLocationView } from '../object-location/ObjectLocationView'; +import { UserLocationViewProps } from './UserLocationView.types'; + +export const UserLocationView: FC = props => +{ + const { userId = -1, ...rest } = props; + const { roomSession = null } = useRoomContext(); + + if((userId === -1) || !roomSession) return null; + + const userData = roomSession.userDataManager.getUserData(userId); + + if(!userData) return null; + + return ; +} diff --git a/src/views/room/widgets/user-location/UserLocationView.types.ts b/src/views/room/widgets/user-location/UserLocationView.types.ts new file mode 100644 index 00000000..d5951e2b --- /dev/null +++ b/src/views/room/widgets/user-location/UserLocationView.types.ts @@ -0,0 +1,6 @@ +import { NitroLayoutBaseProps } from '../../../../layout/base'; + +export interface UserLocationViewProps extends NitroLayoutBaseProps +{ + userId: number; +}