Skip to content

Commit 1a0d9c0

Browse files
committed
presence [nfc]: Make a Redux selector for getting presence status
1 parent 41f347c commit 1a0d9c0

File tree

2 files changed

+33
-16
lines changed

2 files changed

+33
-16
lines changed

src/common/PresenceStatusIndicator.js

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,9 @@ import type { ViewStyleProp } from 'react-native/Libraries/StyleSheet/StyleSheet
66

77
import { createStyleSheet, ThemeContext } from '../styles';
88
import { useSelector } from '../react-redux';
9-
import { statusFromPresenceAndUserStatus } from '../utils/presence';
10-
import { getPresence } from '../selectors';
11-
import { getUserStatus } from '../user-statuses/userStatusesModel';
12-
import { tryGetUserForId } from '../users/userSelectors';
9+
import { getPresenceStatusForUserId } from '../utils/presence';
1310
import { ensureUnreachable } from '../types';
14-
import type { UserId, UserPresence } from '../types';
11+
import type { UserId } from '../types';
1512

1613
const styles = createStyleSheet({
1714
common: {
@@ -126,19 +123,10 @@ type Props = $ReadOnly<{|
126123
*/
127124
export default function PresenceStatusIndicator(props: Props): Node {
128125
const { userId, style, hideIfOffline, useOpaqueBackground } = props;
129-
const presence = useSelector(getPresence);
130-
const user = useSelector(state => tryGetUserForId(state, userId));
131-
const userPresence = (user && (presence[user.email]: UserPresence | void)) ?? null;
132126

133-
const userStatus = useSelector(state => getUserStatus(state, userId));
127+
const status = useSelector(state => getPresenceStatusForUserId(state, userId));
134128

135-
if (!user || !userPresence || !userPresence.aggregated) {
136-
return null;
137-
}
138-
139-
const status = statusFromPresenceAndUserStatus(userPresence, userStatus);
140-
141-
if (hideIfOffline && status === 'offline') {
129+
if (status === null || (hideIfOffline && status === 'offline')) {
142130
return null;
143131
}
144132

src/utils/presence.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ import formatDistanceToNow from 'date-fns/formatDistanceToNow';
66
import type { ClientPresence, UserPresence, PresenceStatus, UserStatus } from '../types';
77
import { ensureUnreachable } from '../types';
88
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';
914

1015
/** The relation `>=`, where `active` > `idle` > `offline`. */
1116
const 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

Comments
 (0)