@@ -6,6 +6,11 @@ import formatDistanceToNow from 'date-fns/formatDistanceToNow';
66import type { ClientPresence , UserPresence , PresenceStatus , UserStatus } from '../types' ;
77import { ensureUnreachable } from '../types' ;
88import { objectEntries } from '../flowPonyfill' ;
9+ import type { PerAccountState } from '../reduxTypes' ;
10+ import type { UserId } from '../api/idTypes' ;
11+ import { getPresence } from '../directSelectors' ;
12+ import { tryGetUserForId } from '../users/userSelectors' ;
13+ import { getUserStatus } from '../user-statuses/userStatusesModel' ;
914
1015/** The relation `>=`, where `active` > `idle` > `offline`. */
1116const presenceStatusGeq = ( a : PresenceStatus , b : PresenceStatus ) : boolean => {
@@ -118,3 +123,27 @@ export const statusFromPresenceAndUserStatus = (
118123 userStatus : UserStatus ,
119124) : PresenceStatus | 'unavailable' = >
120125 userStatus . away ? 'unavailable' : statusFromPresence ( presence ) ;
126+
127+ /**
128+ * Get a user's overall presence status, aggregated from all their devices.
129+ *
130+ * Gives null when we're missing data to determine this, such as when the
131+ * user doesn't exist.
132+ */
133+ export const getPresenceStatusForUserId = (
134+ state : PerAccountState ,
135+ userId : UserId ,
136+ ) : PresenceStatus | 'unavailable' | null => {
137+ const presence = getPresence ( state ) ;
138+ const user = tryGetUserForId ( state , userId ) ;
139+ if ( ! user ) {
140+ return null ;
141+ }
142+ const userPresence = ( presence [ user . email ] : UserPresence | void ) ;
143+ if ( ! userPresence || ! userPresence . aggregated ) {
144+ return null ;
145+ }
146+ const userStatus = getUserStatus ( state , userId ) ;
147+
148+ return statusFromPresenceAndUserStatus ( userPresence , userStatus ) ;
149+ } ;
0 commit comments