mirror of
https://github.com/lux-tel/session-desktop.git
synced 2026-10-30 20:33:24 +00:00
192 lines
6.7 KiB
TypeScript
192 lines
6.7 KiB
TypeScript
import styled from 'styled-components';
|
|
import { useEffect, useRef, useState } from 'react';
|
|
import useAsync from 'react-use/lib/useAsync';
|
|
|
|
import { Flex } from '../../basic/Flex';
|
|
import { Header } from '../../conversation/right-panel/overlay/components';
|
|
import type { WithConvoId } from '../../../session/types/with';
|
|
import { useIsMe, useIsPrivate, useIsPublic } from '../../../hooks/useParamSelector';
|
|
import { PubKey } from '../../../session/types';
|
|
import { tr } from '../../../localization/localeTools';
|
|
import { useEditProfilePictureCallback } from '../../menuAndSettingsHooks/useEditProfilePictureCallback';
|
|
import { useRoomDescription } from '../../../state/selectors/sogsRoomInfo';
|
|
import { useLibGroupDescription } from '../../../state/selectors/groups';
|
|
import { useHTMLDirection } from '../../../util/i18n/rtlSupport';
|
|
import { UsernameFallback } from './UsernameFallback';
|
|
import { ConversationTitleDialog } from './ConversationTitleDialog';
|
|
import { SessionIDNotEditable } from '../../basic/SessionIdNotEditable';
|
|
import { AccountIdPill } from '../../basic/AccountIdPill';
|
|
import { ProfileHeader } from '../user-settings/components';
|
|
import type { ProfileDialogModes } from '../user-settings/ProfileDialogModes';
|
|
import { SessionUtilUserGroups } from '../../../session/utils/libsession/libsession_utils_user_groups';
|
|
import { QRView } from '../../qrview/QrView';
|
|
|
|
function AccountId({ conversationId }: WithConvoId) {
|
|
const isPrivate = useIsPrivate(conversationId);
|
|
|
|
if (!isPrivate) {
|
|
return null;
|
|
}
|
|
|
|
if (PubKey.isBlinded(conversationId)) {
|
|
// the settings menu should not be shown in the first place
|
|
throw new Error('AccountId: Blinded conversationId');
|
|
}
|
|
|
|
return (
|
|
<SessionIDNotEditable
|
|
dataTestId="account-id"
|
|
sessionId={conversationId}
|
|
displayType="2lines"
|
|
tooltipNode={null}
|
|
style={{ color: 'var(--text-primary-color)' }}
|
|
/>
|
|
);
|
|
}
|
|
|
|
const StyledDescription = styled.div<{ $expanded: boolean }>`
|
|
color: var(--text-secondary-color);
|
|
font-size: var(--font-display-size-md);
|
|
text-align: center;
|
|
font-weight: 400;
|
|
line-height: 1.2;
|
|
background: transparent;
|
|
width: 100%;
|
|
white-space: pre-wrap;
|
|
word-break: break-word;
|
|
overflow: hidden;
|
|
-webkit-line-clamp: ${({ $expanded }) => ($expanded ? 'unset' : '2')};
|
|
display: -webkit-box;
|
|
-webkit-box-orient: vertical;
|
|
// some padding so we always have room to show the ellipsis, if needed
|
|
padding-inline: var(--margins-sm);
|
|
`;
|
|
|
|
const StyledViewMoreButton = styled.button`
|
|
color: var(--text-secondary-color);
|
|
text-align: center;
|
|
font-weight: 700;
|
|
transition-duration: var(--default-duration);
|
|
|
|
&:hover {
|
|
color: var(--text-primary-color);
|
|
}
|
|
`;
|
|
|
|
function Description({ conversationId }: WithConvoId) {
|
|
const roomDescription = useRoomDescription(conversationId);
|
|
const groupDescription = useLibGroupDescription(conversationId);
|
|
const [expanded, setExpanded] = useState(false);
|
|
const [isClamped, setIsClamped] = useState(false);
|
|
const ref = useRef<HTMLParagraphElement>(null);
|
|
|
|
const description = roomDescription || groupDescription;
|
|
|
|
// small hook to detect if View More/Less button should be shown, depending on
|
|
// if the description is overflowing the container
|
|
useEffect(() => {
|
|
const el = ref.current;
|
|
if (!el) {
|
|
return;
|
|
}
|
|
|
|
const isOverflowing = el.scrollHeight > el.clientHeight;
|
|
|
|
setIsClamped(isOverflowing);
|
|
}, [description]);
|
|
|
|
if (!description) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<StyledDescription data-testid="group-description" $expanded={expanded} ref={ref}>
|
|
{description}
|
|
</StyledDescription>
|
|
{isClamped && (
|
|
<StyledViewMoreButton onClick={() => setExpanded(!expanded)}>
|
|
{expanded ? tr('viewLess') : tr('viewMore')}
|
|
</StyledViewMoreButton>
|
|
)}
|
|
</>
|
|
);
|
|
}
|
|
|
|
export const ConversationSettingsHeader = ({ conversationId }: WithConvoId) => {
|
|
// if a nickname is set, we still want to display the real name of the user, as he defined it
|
|
const isMe = useIsMe(conversationId);
|
|
|
|
const editProfilePictureCb = useEditProfilePictureCallback({ conversationId });
|
|
const htmlDirection = useHTMLDirection();
|
|
|
|
const isPrivateUnblinded = useIsPrivate(conversationId) && !PubKey.isBlinded(conversationId);
|
|
const [mode, setMode] = useState<ProfileDialogModes>('default');
|
|
const isPublic = useIsPublic(conversationId);
|
|
const [fullUrlWithPubkey, setFullUrlWithPubkey] = useState<string | null>(null);
|
|
|
|
useAsync(async () => {
|
|
if (!conversationId || !isPublic) {
|
|
return;
|
|
}
|
|
const roomDetails = await SessionUtilUserGroups.getCommunityByConvoIdNotCached(conversationId);
|
|
if (!roomDetails) {
|
|
throw new Error(`getCommunityByFullUrl returned no result for ${conversationId}`);
|
|
}
|
|
setFullUrlWithPubkey(roomDetails.fullUrlWithPubkey);
|
|
}, [conversationId]);
|
|
|
|
const [enlargedImage, setEnlargedImage] = useState(false);
|
|
|
|
if (!conversationId) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
<Header hideCloseButton={true} paddingTop="var(--margins-xs)">
|
|
<Flex
|
|
$container={true}
|
|
$justifyContent={'center'}
|
|
$alignItems={'center'}
|
|
width={'100%'}
|
|
$flexDirection="column"
|
|
$flexGap="var(--margins-lg)"
|
|
>
|
|
{mode === 'qr' ? (
|
|
<QRView
|
|
sessionID={(isPublic && fullUrlWithPubkey && fullUrlWithPubkey) || conversationId}
|
|
onExit={() => setMode('default')}
|
|
/>
|
|
) : (
|
|
<ProfileHeader
|
|
conversationId={conversationId}
|
|
dataTestId="profile-picture"
|
|
// 1. We don't want to show the plus button for the current user
|
|
// as he needs to change his avatar through the UserSettingsModal
|
|
// 2. We don't want to show the plus button for communities as they already have a qr button.
|
|
// Editing the avatar is done through the pencil icon in the ModalHeader
|
|
onPlusAvatarClick={!isMe && !isPublic ? (editProfilePictureCb ?? null) : null}
|
|
avatarPath={null}
|
|
onQRClick={(isPrivateUnblinded && !isMe) || isPublic ? () => setMode('qr') : null}
|
|
enlargedImage={enlargedImage}
|
|
toggleEnlargedImage={() => setEnlargedImage(!enlargedImage)}
|
|
/>
|
|
)}
|
|
<Flex
|
|
$container={true}
|
|
$alignItems={'center'}
|
|
$flexDirection={'row'}
|
|
$flexGap="var(--margins-xs)"
|
|
style={{ direction: htmlDirection }}
|
|
>
|
|
<ConversationTitleDialog conversationId={conversationId} editable={true} />
|
|
</Flex>
|
|
<UsernameFallback conversationId={conversationId} />
|
|
<Description conversationId={conversationId} />
|
|
{isPrivateUnblinded ? <AccountIdPill accountType={isMe ? 'ours' : 'theirs'} /> : null}
|
|
<AccountId conversationId={conversationId} />
|
|
</Flex>
|
|
</Header>
|
|
);
|
|
};
|