@@ -6,6 +6,11 @@ import formatDistanceToNow from 'date-fns/formatDistanceToNow';
6
6
import type { ClientPresence , UserPresence , PresenceStatus , UserStatus } from '../types' ;
7
7
import { ensureUnreachable } from '../types' ;
8
8
import { 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' ;
9
14
10
15
/** The relation `>=`, where `active` > `idle` > `offline`. */
11
16
const presenceStatusGeq = ( a : PresenceStatus , b : PresenceStatus ) : boolean => {
@@ -118,3 +123,27 @@ export const statusFromPresenceAndUserStatus = (
118
123
userStatus : UserStatus ,
119
124
) : PresenceStatus | 'unavailable' = >
120
125
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