From 9f3cd9bd461544c441386cb8a992434cb5fb2ad6 Mon Sep 17 00:00:00 2001 From: simoleo89 Date: Mon, 11 May 2026 23:00:39 +0200 Subject: [PATCH] Split useFriends into state + actions via useBetween singleton MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit useFriends backs ~16 consumers with a friend-list state (5 useStates + 6 message-event listeners) plus 4 imperative entry points (requestFriend, requestResponse, followFriend, updateRelationship). Same singleton-filter pattern as useNotification / useWiredTools / useTranslation. - useFriendsStore (internal, was useFriendsState) — the previous body untouched. - useFriendsState (public, read-only) — friends arrays, settings, derived onlineFriends / offlineFriends, getFriend lookup, canRequestFriend guard, plus setDismissedRequestIds (UI-local 'hide banner' state). - useFriendsActions (public, imperative) — requestFriend, requestResponse, followFriend, updateRelationship. - useFriends (deprecated shim) — composes both, preserving the historical full-shape return. --- src/hooks/friends/useFriends.ts | 78 ++++++++++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 2 deletions(-) diff --git a/src/hooks/friends/useFriends.ts b/src/hooks/friends/useFriends.ts index fb4b639..4eee569 100644 --- a/src/hooks/friends/useFriends.ts +++ b/src/hooks/friends/useFriends.ts @@ -5,7 +5,14 @@ import { CloneObject, LocalizeText, MessengerFriend, MessengerRequest, Messenger import { useMessageEvent } from '../events'; import { useNotification } from '../notification'; -const useFriendsState = () => +/** + * Internal singleton store for friend-list state + actions. Public + * consumers should use useFriendsState (read-only — friends arrays, + * settings, derived online/offline split) or useFriendsActions + * (imperative — request / response / follow / update). useFriends is + * the legacy shim that composes both. + */ +const useFriendsStore = () => { const [ friends, setFriends ] = useState([]); const [ requests, setRequests ] = useState([]); @@ -255,4 +262,71 @@ const useFriendsState = () => return { friends, requests, sentRequests, dismissedRequestIds, setDismissedRequestIds, settings, onlineFriends, offlineFriends, getFriend, canRequestFriend, requestFriend, requestResponse, followFriend, updateRelationship }; }; -export const useFriends = () => useBetween(useFriendsState); +/** + * Read-only slice of the friends store: the friend list itself + * (friends, requests, sentRequests, dismissedRequestIds, settings) + * plus the derived online/offline splits and the lookup helpers + * (getFriend, canRequestFriend) that don't mutate state. + * + * setDismissedRequestIds is exposed here because most consumers that + * read dismissedRequestIds also need to mutate it (it's UI-local + * "I've already hidden this banner" state, not server-driven). + */ +export const useFriendsState = () => +{ + const { + friends, + requests, + sentRequests, + dismissedRequestIds, + setDismissedRequestIds, + settings, + onlineFriends, + offlineFriends, + getFriend, + canRequestFriend + } = useBetween(useFriendsStore); + + return { + friends, + requests, + sentRequests, + dismissedRequestIds, + setDismissedRequestIds, + settings, + onlineFriends, + offlineFriends, + getFriend, + canRequestFriend + }; +}; + +/** + * Imperative slice of the friends store: request a new friendship, + * respond to an incoming request, follow a friend, update an existing + * relationship. + */ +export const useFriendsActions = () => +{ + const { + requestFriend, + requestResponse, + followFriend, + updateRelationship + } = useBetween(useFriendsStore); + + return { + requestFriend, + requestResponse, + followFriend, + updateRelationship + }; +}; + +/** + * @deprecated Prefer `useFriendsState` (read-only friends list) and + * `useFriendsActions` (request / follow / update) directly. This shim + * composes both into the historical `useFriends()` shape so the 16 + * existing consumers keep working unchanged. + */ +export const useFriends = () => useBetween(useFriendsStore);