diff --git a/src/hooks/rooms/widgets/index.ts b/src/hooks/rooms/widgets/index.ts index 65602bf..c0f96db 100644 --- a/src/hooks/rooms/widgets/index.ts +++ b/src/hooks/rooms/widgets/index.ts @@ -7,6 +7,8 @@ export * from './useDoorbellActions'; export * from './useDoorbellState'; export * from './useDoorbellWidget'; export * from './useFilterWordsWidget'; +export * from './useFriendRequestActions'; +export * from './useFriendRequestState'; export * from './useFriendRequestWidget'; export * from './useFurniChooserActions'; export * from './useFurniChooserState'; diff --git a/src/hooks/rooms/widgets/useFriendRequestActions.ts b/src/hooks/rooms/widgets/useFriendRequestActions.ts new file mode 100644 index 0000000..d09b330 --- /dev/null +++ b/src/hooks/rooms/widgets/useFriendRequestActions.ts @@ -0,0 +1,28 @@ +import { useFriends } from '../../friends'; + +/** + * Imperative actions for the friend-request widget. Stateless — split + * from useFriendRequestState so a component that only needs to dismiss + * a request doesn't subscribe to the user-added/removed lifecycle. + * + * The actual dismissal flag lives in the shared friends store + * (via `setDismissedRequestIds`), so this hook is a thin adapter. + */ +export const useFriendRequestActions = () => +{ + const { setDismissedRequestIds = null } = useFriends(); + + return { + hideFriendRequest: (userId: number): void => + { + if(!setDismissedRequestIds) return; + + setDismissedRequestIds(prevValue => + { + if(prevValue.indexOf(userId) >= 0) return prevValue; + + return [ ...prevValue, userId ]; + }); + } + }; +}; diff --git a/src/hooks/rooms/widgets/useFriendRequestState.ts b/src/hooks/rooms/widgets/useFriendRequestState.ts new file mode 100644 index 0000000..5513a82 --- /dev/null +++ b/src/hooks/rooms/widgets/useFriendRequestState.ts @@ -0,0 +1,85 @@ +import { RoomObjectCategory, RoomObjectUserType } from '@nitrots/nitro-renderer'; +import { useEffect, useMemo, useState } from 'react'; +import { GetRoomSession, MessengerRequest } from '../../../api'; +import { useFriends } from '../../friends'; +import { useUserAddedEvent, useUserRemovedEvent } from '../engine'; + +export interface ActiveFriendRequest +{ + roomIndex: number; + request: MessengerRequest; +} + +/** + * State + event subscriptions for the friend-request room widget. + * Pure imperative action (hideFriendRequest) lives in + * useFriendRequestActions. + */ +export const useFriendRequestState = () => +{ + const [ activeRequests, setActiveRequests ] = useState([]); + const { requests = [], dismissedRequestIds = [] } = useFriends(); + + const displayedRequests = useMemo( + () => activeRequests.filter(entry => (dismissedRequestIds.indexOf(entry.request.requesterUserId) === -1)), + [ activeRequests, dismissedRequestIds ] + ); + + useUserAddedEvent(true, event => + { + if(event.category !== RoomObjectCategory.UNIT) return; + + const userData = GetRoomSession()?.userDataManager?.getUserDataByIndex(event.id); + + if(!userData || (userData.type !== RoomObjectUserType.getTypeNumber(RoomObjectUserType.USER))) return; + + const request = requests.find(r => (r.requesterUserId === userData.webID)); + + if(!request) return; + + setActiveRequests(prev => + { + if(prev.find(entry => (entry.request.requesterUserId === userData.webID))) return prev; + + return [ ...prev, { roomIndex: userData.roomIndex, request } ]; + }); + }); + + useUserRemovedEvent(true, event => + { + if(event.category !== RoomObjectCategory.UNIT) return; + + setActiveRequests(prev => + { + const index = prev.findIndex(entry => (entry.roomIndex === event.id)); + + if(index === -1) return prev; + + const next = [ ...prev ]; + next.splice(index, 1); + return next; + }); + }); + + useEffect(() => + { + const session = GetRoomSession(); + + if(!session) return; + + const next: ActiveFriendRequest[] = []; + + for(const request of requests) + { + const userData = session.userDataManager?.getUserData(request.requesterUserId); + + if(!userData) continue; + + next.push({ roomIndex: userData.roomIndex, request }); + } + + setActiveRequests(next); + }, [ requests ]); + + return { displayedRequests }; +}; diff --git a/src/hooks/rooms/widgets/useFriendRequestWidget.ts b/src/hooks/rooms/widgets/useFriendRequestWidget.ts index 22324d5..31b4250 100644 --- a/src/hooks/rooms/widgets/useFriendRequestWidget.ts +++ b/src/hooks/rooms/widgets/useFriendRequestWidget.ts @@ -1,81 +1,15 @@ -import { RoomObjectCategory, RoomObjectUserType } from '@nitrots/nitro-renderer'; -import { useEffect, useMemo, useState } from 'react'; -import { GetRoomSession, MessengerRequest } from '../../../api'; -import { useFriends } from '../../friends'; -import { useUserAddedEvent, useUserRemovedEvent } from '../engine'; +import { useFriendRequestActions } from './useFriendRequestActions'; +import { useFriendRequestState } from './useFriendRequestState'; -const useFriendRequestWidgetState = () => +/** + * @deprecated Use `useFriendRequestState` and `useFriendRequestActions` + * directly. This shim preserves the + * `{ displayedRequests, hideFriendRequest }` shape for existing consumers. + */ +export const useFriendRequestWidget = () => { - const [ activeRequests, setActiveRequests ] = useState<{ roomIndex: number, request: MessengerRequest }[]>([]); - const { requests = [], dismissedRequestIds = [], setDismissedRequestIds = null } = useFriends(); - - const displayedRequests = useMemo(() => activeRequests.filter(request => (dismissedRequestIds.indexOf(request.request.requesterUserId) === -1)), [ activeRequests, dismissedRequestIds ]); - - const hideFriendRequest = (userId: number) => - { - setDismissedRequestIds(prevValue => - { - if(prevValue.indexOf(userId) >= 0) return prevValue; - - const newValue = [ ...prevValue ]; - - newValue.push(userId); - - return newValue; - }); - }; - - useUserAddedEvent(true, event => - { - if(event.category !== RoomObjectCategory.UNIT) return; - - const userData = GetRoomSession().userDataManager.getUserDataByIndex(event.id); - - if(!userData || (userData.type !== RoomObjectUserType.getTypeNumber(RoomObjectUserType.USER))) return; - - const request = requests.find(request => (request.requesterUserId === userData.webID)); - - if(!request || activeRequests.find(request => (request.request.requesterUserId === userData.webID))) return; - - const newValue = [ ...activeRequests ]; - - newValue.push({ roomIndex: userData.roomIndex, request }); - - setActiveRequests(newValue); - }); - - useUserRemovedEvent(true, event => - { - if(event.category !== RoomObjectCategory.UNIT) return; - - const index = activeRequests.findIndex(request => (request.roomIndex === event.id)); - - if(index === -1) return; - - const newValue = [ ...activeRequests ]; - - newValue.splice(index, 1); - - setActiveRequests(newValue); - }); - - useEffect(() => - { - const newDisplayedRequests: { roomIndex: number, request: MessengerRequest }[] = []; - - for(const request of requests) - { - const userData = GetRoomSession().userDataManager.getUserData(request.requesterUserId); - - if(!userData) continue; - - newDisplayedRequests.push({ roomIndex: userData.roomIndex, request }); - } - - setActiveRequests(newDisplayedRequests); - }, [ requests ]); + const { displayedRequests } = useFriendRequestState(); + const { hideFriendRequest } = useFriendRequestActions(); return { displayedRequests, hideFriendRequest }; }; - -export const useFriendRequestWidget = useFriendRequestWidgetState;