Skip to content
1 change: 1 addition & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1663,6 +1663,7 @@ const CONST = {
EMOJI_NUM_PER_ROW: 8,

EMOJI_DEFAULT_SKIN_TONE: -1,
DISPLAY_PARTICIPANTS_LIMIT: 5,

// Amount of emojis to render ahead at the end of the update cycle
EMOJI_DRAW_AMOUNT: 250,
Expand Down
15 changes: 12 additions & 3 deletions src/components/DisplayNames/DisplayNamesWithTooltip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,21 @@ import {View} from 'react-native';
import Text from '@components/Text';
import Tooltip from '@components/Tooltip';
import useThemeStyles from '@hooks/useThemeStyles';
import * as ReportUtils from '@libs/ReportUtils';
import {formatReportLastMessageText} from '@libs/ReportUtils';
import DisplayNamesTooltipItem from './DisplayNamesTooltipItem';
import type DisplayNamesProps from './types';

type HTMLElementWithText = HTMLElement & RNText;

function DisplayNamesWithToolTip({shouldUseFullTitle, fullTitle, displayNamesWithTooltips, textStyles = [], numberOfLines = 1, renderAdditionalText}: DisplayNamesProps) {
function DisplayNamesWithToolTip({
shouldUseFullTitle,
fullTitle,
displayNamesWithTooltips,
shouldAddEllipsis = false,
textStyles = [],
numberOfLines = 1,
renderAdditionalText,
}: DisplayNamesProps) {
const styles = useThemeStyles();
const containerRef = useRef<HTMLElementWithText>(null);
const childRefs = useRef<HTMLElementWithText[]>([]);
Expand Down Expand Up @@ -57,7 +65,7 @@ function DisplayNamesWithToolTip({shouldUseFullTitle, fullTitle, displayNamesWit
testID={DisplayNamesWithToolTip.displayName}
>
{shouldUseFullTitle
? ReportUtils.formatReportLastMessageText(fullTitle)
? formatReportLastMessageText(fullTitle)
: displayNamesWithTooltips?.map(({displayName, accountID, avatar, login}, index) => (
// eslint-disable-next-line react/no-array-index-key
<Fragment key={index}>
Expand All @@ -72,6 +80,7 @@ function DisplayNamesWithToolTip({shouldUseFullTitle, fullTitle, displayNamesWit
childRefs={childRefs}
/>
{index < displayNamesWithTooltips.length - 1 && <Text style={textStyles}>,&nbsp;</Text>}
{shouldAddEllipsis && index === displayNamesWithTooltips.length - 1 && <Text style={textStyles}>...</Text>}
</Fragment>
))}
{renderAdditionalText?.()}
Expand Down
3 changes: 2 additions & 1 deletion src/components/DisplayNames/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import DisplayNamesWithoutTooltip from './DisplayNamesWithoutTooltip';
import DisplayNamesWithToolTip from './DisplayNamesWithTooltip';
import type DisplayNamesProps from './types';

function DisplayNames({fullTitle, tooltipEnabled, textStyles, numberOfLines, shouldUseFullTitle, displayNamesWithTooltips, renderAdditionalText}: DisplayNamesProps) {
function DisplayNames({fullTitle, tooltipEnabled, textStyles, numberOfLines, shouldAddEllipsis, shouldUseFullTitle, displayNamesWithTooltips, renderAdditionalText}: DisplayNamesProps) {
const {translate} = useLocalize();
const title = fullTitle || translate('common.hidden');

Expand Down Expand Up @@ -36,6 +36,7 @@ function DisplayNames({fullTitle, tooltipEnabled, textStyles, numberOfLines, sho
fullTitle={title}
displayNamesWithTooltips={displayNamesWithTooltips}
textStyles={textStyles}
shouldAddEllipsis={shouldAddEllipsis}
numberOfLines={numberOfLines}
renderAdditionalText={renderAdditionalText}
/>
Expand Down
3 changes: 3 additions & 0 deletions src/components/DisplayNames/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ type DisplayNamesProps = {
/** If the full title needs to be displayed */
shouldUseFullTitle?: boolean;

/** If we should add an ellipsis after the participants list */
shouldAddEllipsis?: boolean;

/** Additional Text component to render after the displayNames */
renderAdditionalText?: () => React.ReactNode;
};
Expand Down
6 changes: 4 additions & 2 deletions src/libs/ReportUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2602,8 +2602,9 @@ function getGroupChatName(participants?: SelectedParticipant[], shouldApplyLimit
Object.keys(report?.participants ?? {})
.map(Number)
.filter((accountID) => !pendingMemberAccountIDs.has(accountID.toString()));
const shouldAddEllipsis = participantAccountIDs.length > CONST.DISPLAY_PARTICIPANTS_LIMIT && shouldApplyLimit;
if (shouldApplyLimit) {
participantAccountIDs = participantAccountIDs.slice(0, 5);
participantAccountIDs = participantAccountIDs.slice(0, CONST.DISPLAY_PARTICIPANTS_LIMIT);
}
const isMultipleParticipantReport = participantAccountIDs.length > 1;

Expand All @@ -2616,7 +2617,8 @@ function getGroupChatName(participants?: SelectedParticipant[], shouldApplyLimit
.sort((first, second) => localeCompare(first ?? '', second ?? ''))
.filter(Boolean)
.join(', ')
.slice(0, CONST.REPORT_NAME_LIMIT);
.slice(0, CONST.REPORT_NAME_LIMIT)
.concat(shouldAddEllipsis ? '...' : '');
}

return translateLocal('groupChat.defaultReportName', {displayName: getDisplayNameForParticipant({accountID: participantAccountIDs.at(0)})});
Expand Down
5 changes: 4 additions & 1 deletion src/pages/home/HeaderView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,9 @@ function HeaderView({report, parentReportAction, onNavigationMenuButtonClicked,
const isSelfDM = isSelfDMReportUtils(report);
const isGroupChat = isGroupChatReportUtils(report) || isDeprecatedGroupDM(report);

const participants = getParticipantsAccountIDsForDisplay(report, false, true).slice(0, 5);
const allParticipants = getParticipantsAccountIDsForDisplay(report, false, true);
const shouldAddEllipsis = allParticipants?.length > CONST.DISPLAY_PARTICIPANTS_LIMIT;
const participants = allParticipants.slice(0, CONST.DISPLAY_PARTICIPANTS_LIMIT);
const isMultipleParticipant = participants.length > 1;

const participantPersonalDetails = getPersonalDetailsForAccountIDs(participants, personalDetails);
Expand Down Expand Up @@ -293,6 +295,7 @@ function HeaderView({report, parentReportAction, onNavigationMenuButtonClicked,
textStyles={[styles.headerText, styles.pre]}
shouldUseFullTitle={isChatRoom || isPolicyExpenseChat || isChatThread || isTaskReport || shouldUseGroupTitle}
renderAdditionalText={renderAdditionalText}
shouldAddEllipsis={shouldAddEllipsis}
/>
</CaretWrapper>
{!isEmptyObject(parentNavigationSubtitleData) && (
Expand Down
10 changes: 5 additions & 5 deletions tests/ui/GroupChatNameTests.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ describe('Tests for group chat name', () => {
return waitFor(() => expect(displayNameText?.props?.children?.[0]).toBe('A, B, C, D'));
}));

it('Should show limited names in LHN when 8 participants are present', () =>
it('Should show limited names with ellipsis in LHN when 8 participants are present', () =>
signInAndGetApp('', participantAccountIDs8).then(() => {
// Verify the sidebar links are rendered
const sidebarLinksHintText = translateLocal('sidebarScreen.listOfChats');
Expand All @@ -191,7 +191,7 @@ describe('Tests for group chat name', () => {
const displayNameHintText = translateLocal('accessibilityHints.chatUserDisplayNames');
const displayNameText = screen.queryByLabelText(displayNameHintText);

return waitFor(() => expect(displayNameText?.props?.children?.[0]).toBe('A, B, C, D, E'));
return waitFor(() => expect(displayNameText?.props?.children?.[0]).toBe('A, B, C, D, E...'));
}));

it('Check if group name shows fine for report header', () =>
Expand Down Expand Up @@ -222,7 +222,7 @@ describe('Tests for group chat name', () => {
return waitFor(() => expect(displayNameTexts).toHaveLength(1));
}));

it('Should show only 5 names when there are 8 participants in the report header', () =>
it('Should show only 5 names with ellipsis when there are 8 participants in the report header', () =>
signInAndGetApp('', participantAccountIDs8)
.then(() => {
// Verify the sidebar links are rendered
Expand All @@ -238,14 +238,14 @@ describe('Tests for group chat name', () => {
const displayNameHintText = translateLocal('accessibilityHints.chatUserDisplayNames');
const displayNameText = screen.queryByLabelText(displayNameHintText);

expect(displayNameText?.props?.children?.[0]).toBe('A, B, C, D, E');
expect(displayNameText?.props?.children?.[0]).toBe('A, B, C, D, E...');

return navigateToSidebarOption(0);
})
.then(waitForBatchedUpdates)
.then(async () => {
await act(() => transitionEndCB?.());
const name = 'A, B, C, D, E';
const name = 'A, B, C, D, E...';
const displayNameTexts = screen.queryAllByLabelText(name);
return waitFor(() => expect(displayNameTexts).toHaveLength(1));
}));
Expand Down
4 changes: 2 additions & 2 deletions tests/unit/ReportUtilsTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1321,9 +1321,9 @@ describe('ReportUtils', () => {
expect(getGroupChatName(fourParticipants)).toEqual('Four, One, Three, Two');
});

it('Should show 5 participants name if count > 5 and shouldApplyLimit is true', async () => {
it('Should show 5 participants name with ellipsis if count > 5 and shouldApplyLimit is true', async () => {
await Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, fakePersonalDetails);
expect(getGroupChatName(eightParticipants, true)).toEqual('Five, Four, One, Three, Two');
expect(getGroupChatName(eightParticipants, true)).toEqual('Five, Four, One, Three, Two...');
});

it('Should show all participants name if count > 5 and shouldApplyLimit is false', async () => {
Expand Down