Skip to content

Commit

Permalink
ui: Show "(guest)" indicator on guest users' names, when realm settin…
Browse files Browse the repository at this point in the history
…g on

Fixes: #5804
  • Loading branch information
chrisbobbe committed Jan 5, 2024
1 parent ee39d54 commit 9171d7d
Show file tree
Hide file tree
Showing 23 changed files with 464 additions and 39 deletions.
3 changes: 2 additions & 1 deletion src/__tests__/lib/exampleData.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ type UserOrBotPropertiesArgs = {|
email?: string,
full_name?: string,
avatar_url?: AvatarURL,
role?: Role,
|};

/**
Expand Down Expand Up @@ -161,7 +162,7 @@ const userOrBotProperties = (args: UserOrBotPropertiesArgs) => {

email: args.email ?? `${randName}@example.org`,
full_name: args.full_name ?? `${randName} User`,
role: Role.Member,
role: args.role ?? Role.Member,
timezone: 'UTC',
user_id,
});
Expand Down
5 changes: 3 additions & 2 deletions src/account-info/AccountDetails.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import PresenceStatusIndicator from '../common/PresenceStatusIndicator';
import { getDisplayEmailForUser } from '../selectors';
import { Role } from '../api/permissionsTypes';
import ZulipTextIntl from '../common/ZulipTextIntl';
import { getFullNameText } from '../users/userSelectors';
import { getFullNameReactText } from '../users/userSelectors';

const componentStyles = createStyleSheet({
componentListItem: {
Expand Down Expand Up @@ -69,6 +69,7 @@ export default function AccountDetails(props: Props): Node {
state => getUserStatus(state, props.user.user_id).status_emoji,
);
const realm = useSelector(state => state.realm);
const { enableGuestUserIndicator } = realm;
const displayEmail = getDisplayEmailForUser(realm, user);

return (
Expand All @@ -86,7 +87,7 @@ export default function AccountDetails(props: Props): Node {
<ZulipTextIntl
selectable
style={[styles.largerText, componentStyles.boldText]}
text={getFullNameText({ user })}
text={getFullNameReactText({ user, enableGuestUserIndicator })}
/>
</View>
{displayEmail !== null && showEmail && (
Expand Down
6 changes: 4 additions & 2 deletions src/account-info/AccountDetailsScreen.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ import AccountDetails from './AccountDetails';
import ZulipText from '../common/ZulipText';
import ActivityText from '../title/ActivityText';
import { doNarrow } from '../actions';
import { getFullNameText, getUserIsActive, tryGetUserForId } from '../users/userSelectors';
import { getFullNameReactText, getUserIsActive, tryGetUserForId } from '../users/userSelectors';
import { nowInTimeZone } from '../utils/date';
import CustomProfileFields from './CustomProfileFields';
import { getRealm } from '../directSelectors';

const styles = createStyleSheet({
errorText: {
Expand Down Expand Up @@ -54,6 +55,7 @@ export default function AccountDetailsScreen(props: Props): Node {
const dispatch = useDispatch();
const user = useSelector(state => tryGetUserForId(state, props.route.params.userId));
const isActive = useSelector(state => getUserIsActive(state, props.route.params.userId));
const enableGuestUserIndicator = useSelector(state => getRealm(state).enableGuestUserIndicator);

const handleChatPress = useCallback(() => {
invariant(user, 'Callback handleChatPress is used only if user is known');
Expand All @@ -80,7 +82,7 @@ export default function AccountDetailsScreen(props: Props): Node {
}

return (
<Screen title={getFullNameText({ user })}>
<Screen title={getFullNameReactText({ user, enableGuestUserIndicator })}>
<AccountDetails user={user} showEmail showStatus />
<View style={styles.itemWrapper}>
<ActivityText style={globalStyles.largerText} user={user} />
Expand Down
10 changes: 8 additions & 2 deletions src/action-sheets/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -999,10 +999,16 @@ export const showPmConversationActionSheet = (args: {|
navigation: AppNavigationMethods,
_: GetText,
|},
backgroundData: $ReadOnly<{ ownUser: User, allUsersById: Map<UserId, UserOrBot>, ... }>,
backgroundData: $ReadOnly<{
ownUser: User,
allUsersById: Map<UserId, UserOrBot>,
enableGuestUserIndicator: boolean,
...
}>,
pmKeyRecipients: PmKeyRecipients,
|}): void => {
const { showActionSheetWithOptions, callbacks, backgroundData, pmKeyRecipients } = args;
const { enableGuestUserIndicator } = backgroundData;
showActionSheet({
showActionSheetWithOptions,
// TODO(ios-14.5): Check for Intl.ListFormat support in all environments
Expand All @@ -1012,7 +1018,7 @@ export const showPmConversationActionSheet = (args: {|
.map(userId => {
const user = backgroundData.allUsersById.get(userId);
invariant(user, 'allUsersById incomplete; could not show PM action sheet');
return callbacks._(getFullNameText({ user }));
return callbacks._(getFullNameText({ user, enableGuestUserIndicator }));
})
.sort()
.join(', '),
Expand Down
11 changes: 9 additions & 2 deletions src/compose/ComposeBox.js
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ const ComposeBox: React$AbstractComponent<Props, ImperativeHandle> = forwardRef(
const stream = useSelector(state => getStreamInNarrow(state, props.narrow));
const streamsById = useSelector(getStreamsById);
const videoChatProvider = useSelector(getVideoChatProvider);
const mandatoryTopics = useSelector(state => getRealm(state).mandatoryTopics);
const { mandatoryTopics, enableGuestUserIndicator } = useSelector(getRealm);

const mentionWarnings = React.useRef<React$ElementRef<typeof MentionWarnings> | null>(null);

Expand Down Expand Up @@ -714,7 +714,14 @@ const ComposeBox: React$AbstractComponent<Props, ImperativeHandle> = forwardRef(
return <AnnouncementOnly />;
}

const placeholder = getComposeInputPlaceholder(narrow, ownUserId, allUsersById, streamsById, _);
const placeholder = getComposeInputPlaceholder(
narrow,
ownUserId,
allUsersById,
streamsById,
enableGuestUserIndicator,
_,
);

const SubmitButtonIcon = isEditing ? IconDone : IconSend;

Expand Down
6 changes: 4 additions & 2 deletions src/compose/MentionWarnings.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { showToast } from '../utils/info';
import MentionedUserNotSubscribed from '../message/MentionedUserNotSubscribed';
import { makeUserId } from '../api/idTypes';
import { getFullNameText } from '../users/userSelectors';
import { getRealm } from '../directSelectors';

type Props = $ReadOnly<{|
narrow: Narrow,
Expand Down Expand Up @@ -43,6 +44,7 @@ function MentionWarningsInner(props: Props, ref): Node {

const auth = useSelector(getAuth);
const allUsersById = useSelector(getAllUsersById);
const enableGuestUserIndicator = useSelector(state => getRealm(state).enableGuestUserIndicator);

const [unsubscribedMentions, setUnsubscribedMentions] = useState<$ReadOnlyArray<UserId>>([]);

Expand Down Expand Up @@ -87,11 +89,11 @@ function MentionWarningsInner(props: Props, ref): Node {
(mentionedUser: UserOrBot) => {
showToast(
_('Couldn’t load information about {fullName}', {
fullName: _(getFullNameText({ user: mentionedUser })),
fullName: _(getFullNameText({ user: mentionedUser, enableGuestUserIndicator })),
}),
);
},
[_],
[enableGuestUserIndicator, _],
);

useImperativeHandle(
Expand Down
5 changes: 5 additions & 0 deletions src/compose/__tests__/getComposeInputPlaceholder-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ describe('getComposeInputPlaceholder', () => {
ownUserId,
usersById,
streamsById,
false,
mock_,
);
expect(placeholder).toEqual({
Expand All @@ -39,6 +40,7 @@ describe('getComposeInputPlaceholder', () => {
ownUserId,
usersById,
streamsById,
false,
mock_,
);
expect(placeholder).toEqual({ text: 'Jot down something' });
Expand All @@ -51,6 +53,7 @@ describe('getComposeInputPlaceholder', () => {
ownUserId,
usersById,
streamsById,
false,
mock_,
);
expect(placeholder).toEqual({
Expand All @@ -66,6 +69,7 @@ describe('getComposeInputPlaceholder', () => {
ownUserId,
usersById,
streamsById,
false,
mock_,
);
expect(placeholder).toEqual({ text: 'Reply' });
Expand All @@ -78,6 +82,7 @@ describe('getComposeInputPlaceholder', () => {
ownUserId,
usersById,
streamsById,
false,
mock_,
);
expect(placeholder).toEqual({ text: 'Message group' });
Expand Down
3 changes: 2 additions & 1 deletion src/compose/getComposeInputPlaceholder.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export default (
ownUserId: UserId,
allUsersById: Map<UserId, UserOrBot>,
streamsById: Map<number, Stream>,
enableGuestUserIndicator: boolean,
_: GetText,
): LocalizableText =>
caseNarrowDefault(
Expand All @@ -30,7 +31,7 @@ export default (

return {
text: 'Message {recipient}',
values: { recipient: _(getFullNameText({ user })) },
values: { recipient: _(getFullNameText({ user, enableGuestUserIndicator })) },
};
},
stream: streamId => {
Expand Down
6 changes: 4 additions & 2 deletions src/lightbox/LightboxHeader.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import UserAvatarWithPresence from '../common/UserAvatarWithPresence';
import { Icon } from '../common/Icons';
import { OfflineNoticePlaceholder } from '../boot/OfflineNoticeProvider';
import { useSelector } from '../react-redux';
import { getFullNameText, tryGetUserForId } from '../users/userSelectors';
import { getFullNameReactText, tryGetUserForId } from '../users/userSelectors';
import { getRealm } from '../directSelectors';
import type { Message } from '../api/modelTypes';
import ZulipText from '../common/ZulipText';
import ZulipTextIntl from '../common/ZulipTextIntl';
Expand Down Expand Up @@ -58,6 +59,7 @@ export default function LightboxHeader(props: Props): Node {
const subheader = `${displayDate} at ${time}`;

const sender = useSelector(state => tryGetUserForId(state, senderId));
const enableGuestUserIndicator = useSelector(state => getRealm(state).enableGuestUserIndicator);

return (
<SafeAreaView mode="padding" edges={['top']}>
Expand All @@ -69,7 +71,7 @@ export default function LightboxHeader(props: Props): Node {
<ZulipTextIntl
style={styles.name}
numberOfLines={1}
text={getFullNameText({ user: sender })}
text={getFullNameReactText({ user: sender, enableGuestUserIndicator })}
/>
) : (
<ZulipText style={styles.name} numberOfLines={1} text={message.sender_full_name} />
Expand Down
10 changes: 8 additions & 2 deletions src/message/MentionedUserNotSubscribed.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import ZulipButton from '../common/ZulipButton';
import ZulipTextIntl from '../common/ZulipTextIntl';
import { getAuth } from '../selectors';
import { kWarningColor } from '../styles/constants';
import { getFullNameText } from '../users/userSelectors';
import { getFullNameReactText } from '../users/userSelectors';
import { getRealm } from '../directSelectors';

type Props = $ReadOnly<{|
user: UserOrBot,
Expand Down Expand Up @@ -56,6 +57,7 @@ const styles = createStyleSheet({
export default function MentionedUserNotSubscribed(props: Props): Node {
const { user, stream, onDismiss } = props;
const auth = useSelector(getAuth);
const enableGuestUserIndicator = useSelector(state => getRealm(state).enableGuestUserIndicator);

const handleDismiss = useCallback(() => {
onDismiss(user);
Expand All @@ -75,7 +77,11 @@ export default function MentionedUserNotSubscribed(props: Props): Node {
text: '{username} will not be notified unless you subscribe them to this stream.',
values: {
username: (
<ZulipTextIntl inheritColor inheritFontSize text={getFullNameText({ user })} />
<ZulipTextIntl
inheritColor
inheritFontSize
text={getFullNameReactText({ user, enableGuestUserIndicator })}
/>
),
},
}}
Expand Down
13 changes: 10 additions & 3 deletions src/pm-conversations/GroupPmConversationItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,12 @@ import Touchable from '../common/Touchable';
import UnreadCount from '../common/UnreadCount';
import { getMutedUsers } from '../selectors';
import { TranslationContext } from '../boot/TranslationProvider';
import { getFullNameOrMutedUserText } from '../users/userSelectors';
import {
getFullNameOrMutedUserReactText,
getFullNameOrMutedUserText,
} from '../users/userSelectors';
import ZulipTextIntl from '../common/ZulipTextIntl';
import { getRealm } from '../directSelectors';

const componentStyles = createStyleSheet({
text: {
Expand Down Expand Up @@ -43,7 +47,10 @@ export default function GroupPmConversationItem<U: $ReadOnlyArray<UserOrBot>>(

const _ = useContext(TranslationContext);
const mutedUsers = useSelector(getMutedUsers);
const names = users.map(user => _(getFullNameOrMutedUserText({ user, mutedUsers })));
const enableGuestUserIndicator = useSelector(state => getRealm(state).enableGuestUserIndicator);
const names = users.map(user =>
_(getFullNameOrMutedUserText({ user, mutedUsers, enableGuestUserIndicator })),
);

const namesReact = [];
users.forEach((user, i) => {
Expand All @@ -57,7 +64,7 @@ export default function GroupPmConversationItem<U: $ReadOnlyArray<UserOrBot>>(
key={`${user.user_id}`}
inheritColor
inheritFontSize
text={getFullNameOrMutedUserText({ user, mutedUsers })}
text={getFullNameOrMutedUserReactText({ user, mutedUsers, enableGuestUserIndicator })}
/>,
);
});
Expand Down
6 changes: 4 additions & 2 deletions src/title/TitlePrivate.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ import Touchable from '../common/Touchable';
import ViewPlaceholder from '../common/ViewPlaceholder';
import UserAvatarWithPresence from '../common/UserAvatarWithPresence';
import ActivityText from './ActivityText';
import { getFullNameText, tryGetUserForId } from '../users/userSelectors';
import { getFullNameReactText, tryGetUserForId } from '../users/userSelectors';
import { useNavigation } from '../react-navigation';
import ZulipTextIntl from '../common/ZulipTextIntl';
import { getRealm } from '../directSelectors';

type Props = $ReadOnly<{|
userId: UserId,
Expand All @@ -29,6 +30,7 @@ const componentStyles = createStyleSheet({
export default function TitlePrivate(props: Props): Node {
const { userId, color } = props;
const user = useSelector(state => tryGetUserForId(state, userId));
const enableGuestUserIndicator = useSelector(state => getRealm(state).enableGuestUserIndicator);
const navigation = useNavigation();
if (!user) {
return null;
Expand All @@ -52,7 +54,7 @@ export default function TitlePrivate(props: Props): Node {
style={[styles.navTitle, { color }]}
numberOfLines={1}
ellipsizeMode="tail"
text={getFullNameText({ user })}
text={getFullNameReactText({ user, enableGuestUserIndicator })}
/>
<ActivityText style={[styles.navSubtitle, { color }]} user={user} />
</View>
Expand Down
12 changes: 10 additions & 2 deletions src/user-picker/AvatarItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ import ComponentWithOverlay from '../common/ComponentWithOverlay';
import Touchable from '../common/Touchable';
import { createStyleSheet } from '../styles';
import { IconCancel } from '../common/Icons';
import { getFullNameText } from '../users/userSelectors';
import { getFullNameReactText } from '../users/userSelectors';
import ZulipTextIntl from '../common/ZulipTextIntl';
import { useSelector } from '../react-redux';
import { getRealm } from '../directSelectors';

const styles = createStyleSheet({
wrapper: {
Expand Down Expand Up @@ -40,6 +42,9 @@ type Props = $ReadOnly<{|
*/
export default function AvatarItem(props: Props): Node {
const { user, onPress } = props;

const enableGuestUserIndicator = useSelector(state => getRealm(state).enableGuestUserIndicator);

const handlePress = React.useCallback(() => {
onPress(user.user_id);
}, [onPress, user.user_id]);
Expand All @@ -57,7 +62,10 @@ export default function AvatarItem(props: Props): Node {
</ComponentWithOverlay>
</Touchable>
<View style={styles.textFrame}>
<ZulipTextIntl style={styles.text} text={getFullNameText({ user })} />
<ZulipTextIntl
style={styles.text}
text={getFullNameReactText({ user, enableGuestUserIndicator })}
/>
</View>
</View>
);
Expand Down
Loading

0 comments on commit 9171d7d

Please sign in to comment.