mirror of
https://github.com/lux-tel/session-desktop.git
synced 2026-10-30 20:33:24 +00:00
329 lines
10 KiB
TypeScript
329 lines
10 KiB
TypeScript
import { CSSProperties } from 'react';
|
|
import clsx from 'clsx';
|
|
|
|
import {
|
|
useConversationRealName,
|
|
useConversationUsernameNoFallback,
|
|
useIsPrivate,
|
|
useIsPublic,
|
|
useNickname,
|
|
} from '../../../hooks/useParamSelector';
|
|
import { Emojify } from '../Emojify';
|
|
import { PubKey } from '../../../session/types';
|
|
import { tr } from '../../../localization/localeTools';
|
|
import { isUsAnySogsFromCache } from '../../../session/apis/open_group_api/sogsv3/knownBlindedkeys';
|
|
import type { ContactNameContext } from './ContactNameContext';
|
|
import { useProBadgeOnClickCb } from '../../menuAndSettingsHooks/useProBadgeOnClickCb';
|
|
import { useCurrentUserHasPro, useShowProBadgeFor } from '../../../hooks/useHasPro';
|
|
import { ProIconButton } from '../../buttons/ProButton';
|
|
import { useMessageIdFromContext } from '../../../contexts/MessageIdContext';
|
|
import { useMessageDirection } from '../../../state/selectors';
|
|
import { useShowUserDetailsCbFromConversation } from '../../menuAndSettingsHooks/useShowUserDetailsCb';
|
|
import { assertUnreachable } from '../../../types/sqlSharedTypes';
|
|
|
|
/**
|
|
* In some contexts, we want to bold the name of the contact.
|
|
*/
|
|
function isBoldProfileNameCtx(ctx: ContactNameContext) {
|
|
// We are doing this as a switch instead of an array so we have to be explicit anytime we add a new context,
|
|
// thanks to the assertUnreachable below
|
|
switch (ctx) {
|
|
case 'conversation-list-item':
|
|
case 'quoted-message-composition':
|
|
case 'message-author':
|
|
case 'message-info-author':
|
|
case 'member-list-item':
|
|
case 'member-list-item-mention-row':
|
|
case 'contact-list-row':
|
|
return true;
|
|
case 'quote-author':
|
|
case 'conversation-list-item-search':
|
|
case 'react-list-modal':
|
|
case 'message-search-result-conversation':
|
|
case 'message-search-result-from':
|
|
return false;
|
|
default:
|
|
assertUnreachable(ctx, 'isBoldProfileNameCtx');
|
|
throw new Error('isBoldProfileNameCtx: unreachable');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* In some contexts, we want to show the pubkey of the contact.
|
|
*/
|
|
function isShowPubkeyCtx(ctx: ContactNameContext, isBlinded: boolean) {
|
|
// We are doing this as a switch instead of an array so we have to be explicit anytime we add a new context,
|
|
// thanks to the assertUnreachable below
|
|
switch (ctx) {
|
|
case 'message-author':
|
|
return true;
|
|
case 'message-info-author':
|
|
if (isBlinded) {
|
|
// we specifically don't want to show the pubkey for blinded senders in message info.
|
|
return false;
|
|
}
|
|
return true;
|
|
case 'member-list-item':
|
|
case 'member-list-item-mention-row':
|
|
case 'contact-list-row':
|
|
case 'quote-author':
|
|
case 'conversation-list-item':
|
|
case 'quoted-message-composition':
|
|
case 'conversation-list-item-search':
|
|
case 'react-list-modal':
|
|
case 'message-search-result-conversation':
|
|
case 'message-search-result-from':
|
|
return false;
|
|
default:
|
|
assertUnreachable(ctx, 'isShowPubkeyCtx');
|
|
throw new Error('isShowPubkeyCtx: unreachable');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* In some contexts, we want to rename "Note To Self" to "You".
|
|
*/
|
|
function isShowNtsIsYouCtx(ctx: ContactNameContext) {
|
|
// We are doing this as a switch instead of an array so we have to be explicit anytime we add a new context,
|
|
// thanks to the assertUnreachable below
|
|
switch (ctx) {
|
|
case 'message-author':
|
|
case 'quote-author':
|
|
case 'quoted-message-composition':
|
|
case 'react-list-modal':
|
|
case 'member-list-item':
|
|
case 'member-list-item-mention-row':
|
|
case 'message-info-author':
|
|
case 'message-search-result-from':
|
|
return true;
|
|
case 'contact-list-row':
|
|
case 'message-search-result-conversation':
|
|
case 'conversation-list-item':
|
|
case 'conversation-list-item-search':
|
|
return false;
|
|
default:
|
|
assertUnreachable(ctx, 'isShowNtsIsYouCtx');
|
|
throw new Error('isShowNtsIsYouCtx: unreachable');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Usually, we'd allow the name to be multiline. but in some contexts we want to force it to be single line.
|
|
*/
|
|
function isForceSingleLineCtx(ctx: ContactNameContext) {
|
|
// We are doing this as a switch instead of an array so we have to be explicit anytime we add a new context,
|
|
// thanks to the assertUnreachable below
|
|
switch (ctx) {
|
|
case 'message-info-author':
|
|
case 'member-list-item':
|
|
case 'member-list-item-mention-row':
|
|
case 'contact-list-row':
|
|
return true;
|
|
case 'message-author':
|
|
case 'quote-author':
|
|
case 'quoted-message-composition':
|
|
case 'react-list-modal':
|
|
case 'message-search-result-conversation':
|
|
case 'message-search-result-from':
|
|
case 'conversation-list-item':
|
|
case 'conversation-list-item-search':
|
|
return false;
|
|
default:
|
|
assertUnreachable(ctx, 'isForceSingleLineCtx');
|
|
throw new Error('isForceSingleLineCtx: unreachable');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Usually, we'd allow the name to be multiline. but in some contexts we want to force it to be single line.
|
|
*/
|
|
function isShowUPMOnClickCtx(ctx: ContactNameContext) {
|
|
// We are doing this as a switch instead of an array so we have to be explicit anytime we add a new context,
|
|
// thanks to the assertUnreachable below
|
|
switch (ctx) {
|
|
case 'message-info-author':
|
|
return true;
|
|
case 'member-list-item':
|
|
case 'member-list-item-mention-row':
|
|
case 'contact-list-row':
|
|
case 'message-author':
|
|
case 'quote-author':
|
|
case 'quoted-message-composition':
|
|
case 'react-list-modal':
|
|
case 'message-search-result-conversation':
|
|
case 'message-search-result-from':
|
|
case 'conversation-list-item':
|
|
case 'conversation-list-item-search':
|
|
return false;
|
|
default:
|
|
assertUnreachable(ctx, 'isForceSingleLineCtx');
|
|
throw new Error('isForceSingleLineCtx: unreachable');
|
|
}
|
|
}
|
|
|
|
const commonNameStyles: CSSProperties = {
|
|
minWidth: 0,
|
|
textOverflow: 'ellipsis',
|
|
overflow: 'hidden',
|
|
fontWeight: 'bold',
|
|
fontSize: 'var(--font-size-md)',
|
|
};
|
|
|
|
const forceSingleLineStyle: CSSProperties = {
|
|
whiteSpace: 'nowrap',
|
|
};
|
|
|
|
const boldStyles: CSSProperties = {
|
|
fontWeight: 'bold',
|
|
};
|
|
|
|
function allowShowUPMForNtsCtx(ctx: ContactNameContext) {
|
|
// We are doing this as a switch instead of an array so we have to be explicit anytime we add a new context,
|
|
// thanks to the assertUnreachable below
|
|
switch (ctx) {
|
|
case 'message-info-author':
|
|
case 'member-list-item':
|
|
case 'member-list-item-mention-row':
|
|
case 'contact-list-row':
|
|
case 'message-author':
|
|
case 'quote-author':
|
|
case 'quoted-message-composition':
|
|
case 'react-list-modal':
|
|
case 'message-search-result-conversation':
|
|
case 'message-search-result-from':
|
|
case 'conversation-list-item':
|
|
case 'conversation-list-item-search':
|
|
return false;
|
|
default:
|
|
assertUnreachable(ctx, 'isForceSingleLineCtx');
|
|
throw new Error('isForceSingleLineCtx: unreachable');
|
|
}
|
|
}
|
|
|
|
export const ContactName = ({
|
|
pubkey,
|
|
module,
|
|
contactNameContext,
|
|
conversationId,
|
|
style,
|
|
extraNameStyle,
|
|
}: {
|
|
pubkey: string;
|
|
module?:
|
|
| 'module-conversation__user'
|
|
| 'module-message-search-result__header__name'
|
|
| 'module-message__author';
|
|
contactNameContext: ContactNameContext;
|
|
conversationId?: string;
|
|
style?: CSSProperties;
|
|
extraNameStyle?: CSSProperties;
|
|
}) => {
|
|
const prefix = module || 'module-contact-name';
|
|
const isPublic = useIsPublic(conversationId);
|
|
const shortPubkey = PubKey.shorten(pubkey);
|
|
const isBlinded = PubKey.isBlinded(pubkey);
|
|
|
|
const isMe = isUsAnySogsFromCache(pubkey);
|
|
|
|
const noFallback = useConversationUsernameNoFallback(pubkey);
|
|
const realName = useConversationRealName(pubkey);
|
|
const nickname = useNickname(pubkey);
|
|
const isPrivate = useIsPrivate(pubkey);
|
|
const currentUserHasPro = useCurrentUserHasPro();
|
|
|
|
const msgId = useMessageIdFromContext();
|
|
|
|
const msgDirection = useMessageDirection(msgId);
|
|
|
|
const displayName = isMe
|
|
? // we want to show "You" instead of "Note to Self" in some places (like quotes)
|
|
tr(isShowNtsIsYouCtx(contactNameContext) ? 'you' : 'noteToSelf')
|
|
: // we want to show the realName in brackets if a nickname is set for search results
|
|
contactNameContext === 'conversation-list-item-search' && nickname && realName
|
|
? `${nickname} (${realName})`
|
|
: noFallback;
|
|
|
|
const shouldShowShortenPkAsName = !displayName;
|
|
|
|
const shouldShowPubkey =
|
|
!shouldShowShortenPkAsName &&
|
|
!isMe &&
|
|
isPublic &&
|
|
isShowPubkeyCtx(contactNameContext, isBlinded);
|
|
const boldProfileName = isBoldProfileNameCtx(contactNameContext);
|
|
const forceSingleLine = isForceSingleLineCtx(contactNameContext);
|
|
|
|
const displayedName = shouldShowShortenPkAsName ? shortPubkey : displayName;
|
|
|
|
const userHasPro = useShowProBadgeFor(pubkey);
|
|
|
|
const showConversationSettingsCb = useShowUserDetailsCbFromConversation(
|
|
pubkey,
|
|
allowShowUPMForNtsCtx(contactNameContext)
|
|
);
|
|
|
|
const showProBadge = useProBadgeOnClickCb({
|
|
context: 'contact-name',
|
|
args: {
|
|
userHasPro,
|
|
isMe,
|
|
contactNameContext,
|
|
currentUserHasPro,
|
|
isBlinded: PubKey.isBlinded(pubkey),
|
|
},
|
|
});
|
|
|
|
let mergedNameStyle: CSSProperties = commonNameStyles;
|
|
if (forceSingleLine) {
|
|
mergedNameStyle = {
|
|
...mergedNameStyle,
|
|
...forceSingleLineStyle,
|
|
};
|
|
}
|
|
if (boldProfileName) {
|
|
mergedNameStyle = {
|
|
...mergedNameStyle,
|
|
...boldStyles,
|
|
};
|
|
}
|
|
mergedNameStyle = {
|
|
...mergedNameStyle,
|
|
...extraNameStyle,
|
|
};
|
|
|
|
return (
|
|
<span
|
|
className={clsx(prefix)}
|
|
dir="auto"
|
|
data-testid={`${prefix}__profile-name` as const}
|
|
style={{
|
|
textOverflow: 'inherit',
|
|
display: 'flex',
|
|
flexDirection: 'row',
|
|
gap: 'var(--margins-xs)',
|
|
maxWidth: '100%',
|
|
...style,
|
|
}}
|
|
onClick={(isShowUPMOnClickCtx(contactNameContext) && showConversationSettingsCb) || undefined}
|
|
>
|
|
{displayedName ? (
|
|
<div style={mergedNameStyle} className={`${prefix}__profile-name`}>
|
|
<Emojify text={displayedName} sizeClass="small" isGroup={!isPrivate} />
|
|
</div>
|
|
) : null}
|
|
{showProBadge.show ? (
|
|
<ProIconButton
|
|
iconSize={'small'}
|
|
style={{
|
|
backgroundColor:
|
|
msgDirection === 'outgoing' ? 'var(--white-color)' : 'var(--primary-color)',
|
|
}}
|
|
dataTestId="pro-badge-contact-name"
|
|
onClick={showProBadge.cb}
|
|
/>
|
|
) : null}
|
|
{shouldShowPubkey ? <div className={`${prefix}__profile-number`}>{shortPubkey}</div> : null}
|
|
</span>
|
|
);
|
|
};
|