import { isEmpty } from 'lodash'; import { useRef, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { useKey } from 'react-use'; import styled from 'styled-components'; import { Avatar, AvatarSize } from '../avatar/Avatar'; import { SyncUtils, UserUtils } from '../../session/utils'; import { YourSessionIDPill, YourSessionIDSelectable } from '../basic/YourSessionIDPill'; import { useOurAvatarPath, useOurConversationUsername } from '../../hooks/useParamSelector'; import { ConversationTypeEnum } from '../../models/conversationAttributes'; import { getConversationController } from '../../session/conversations'; import { editProfileModal, updateEditProfilePictureModel } from '../../state/ducks/modalDialog'; import { getTheme } from '../../state/selectors/theme'; import { getThemeValue } from '../../themes/globals'; import { setLastProfileUpdateTimestamp } from '../../util/storage'; import { SessionQRCode } from '../SessionQRCode'; import { SessionWrapperModal } from '../SessionWrapperModal'; import { Flex } from '../basic/Flex'; import { SessionButton } from '../basic/SessionButton'; import { Spacer2XL, Spacer3XL, SpacerLG, SpacerSM, SpacerXL } from '../basic/Text'; import { CopyToClipboardButton } from '../buttons/CopyToClipboardButton'; import { SessionIconButton } from '../icon'; import { SessionInput } from '../inputs'; import { SessionSpinner } from '../loading'; import { sanitizeDisplayNameOrToast } from '../registration/utils'; const StyledEditProfileDialog = styled.div` .session-modal { width: 468px; .session-modal__body { width: calc(100% - 80px); margin: 0 auto; overflow: initial; } } .avatar-center-inner { position: relative; .qr-view-button { cursor: pointer; display: flex; align-items: center; justify-content: center; position: absolute; top: -8px; right: -8px; height: 34px; width: 34px; border-radius: 50%; background-color: var(--white-color); transition: var(--default-duration); &:hover { filter: brightness(90%); } .session-icon-button { opacity: 1; } } } input { border: none; } `; // We center the name in the modal by offsetting the pencil icon // we have a transparent border to match the dimensions of the SessionInput const StyledProfileName = styled(Flex)` margin-inline-start: calc((25px + var(--margins-sm)) * -1); padding: 8px; border: 1px solid var(--transparent-color); p { font-size: var(--font-size-xl); line-height: 1.4; margin: 0; padding: 0px; } .session-icon-button { padding: 0px; } `; const StyledSessionIdSection = styled(Flex)` .session-button { width: 160px; } `; const QRView = ({ sessionID }: { sessionID: string }) => { const theme = useSelector(getTheme); return ( ); }; const updateDisplayName = async (newName: string) => { const ourNumber = UserUtils.getOurPubKeyStrFromCache(); const conversation = await getConversationController().getOrCreateAndWait( ourNumber, ConversationTypeEnum.PRIVATE ); conversation.setSessionDisplayNameNoCommit(newName); // might be good to not trigger a sync if the name did not change await conversation.commit(); await setLastProfileUpdateTimestamp(Date.now()); await SyncUtils.forceSyncConfigurationNowIfNeeded(true); }; type ProfileAvatarProps = { avatarPath: string | null; newAvatarObjectUrl?: string | null; profileName: string | undefined; ourId: string; }; export const ProfileAvatar = (props: ProfileAvatarProps) => { const { newAvatarObjectUrl, avatarPath, profileName, ourId } = props; return ( ); }; type ProfileHeaderProps = ProfileAvatarProps & { onClick: () => void; onQRClick: () => void; }; const ProfileHeader = (props: ProfileHeaderProps) => { const { avatarPath, profileName, ourId, onClick, onQRClick } = props; return (
); }; type ProfileDialogModes = 'default' | 'edit' | 'qr'; export const EditProfileDialog = () => { const dispatch = useDispatch(); const _profileName = useOurConversationUsername() || ''; const [profileName, setProfileName] = useState(_profileName); const [updatedProfileName, setUpdateProfileName] = useState(profileName); const [profileNameError, setProfileNameError] = useState(undefined); const copyButtonRef = useRef(null); const inputRef = useRef(null); const avatarPath = useOurAvatarPath() || ''; const ourId = UserUtils.getOurPubKeyStrFromCache(); const [mode, setMode] = useState('default'); const [loading, setLoading] = useState(false); const closeDialog = (event?: any) => { if (event?.key || loading) { return; } window.inboxStore?.dispatch(editProfileModal(null)); }; const backButton = mode === 'edit' || mode === 'qr' ? [ { iconType: 'chevron', iconRotation: 90, onClick: () => { if (loading) { return; } setMode('default'); }, }, ] : undefined; const onClickOK = async () => { if (isEmpty(profileName) || !isEmpty(profileNameError)) { return; } setLoading(true); await updateDisplayName(profileName); setUpdateProfileName(profileName); setMode('default'); setLoading(false); }; const handleProfileHeaderClick = () => { if (loading) { return; } closeDialog(); dispatch( updateEditProfilePictureModel({ avatarPath, profileName, ourId, }) ); }; useKey( (event: KeyboardEvent) => { return event.key === 'c'; }, () => { if (loading) { return; } switch (mode) { case 'default': case 'qr': if (copyButtonRef.current !== null) { copyButtonRef.current.click(); } break; case 'edit': default: } } ); useKey( (event: KeyboardEvent) => { return event.key === 'v'; }, () => { if (loading) { return; } switch (mode) { case 'default': setMode('qr'); break; case 'qr': setMode('default'); break; case 'edit': default: } } ); useKey( (event: KeyboardEvent) => { return event.key === 'Enter'; }, () => { if (loading) { return; } switch (mode) { case 'default': setMode('edit'); break; case 'edit': void onClickOK(); break; case 'qr': default: } } ); useKey( (event: KeyboardEvent) => { return event.key === 'Backspace'; }, () => { if (loading) { return; } switch (mode) { case 'edit': case 'qr': if (inputRef.current !== null && document.activeElement === inputRef.current) { return; } setMode('default'); if (mode === 'edit') { setProfileNameError(undefined); setProfileName(updatedProfileName); } break; case 'default': default: } } ); useKey( (event: KeyboardEvent) => { return event.key === 'Esc' || event.key === 'Escape'; }, () => { if (loading) { return; } if (mode === 'edit') { setMode('default'); setProfileNameError(undefined); setProfileName(updatedProfileName); } else { window.inboxStore?.dispatch(editProfileModal(null)); } } ); return ( {mode === 'qr' ? ( ) : ( <> { if (loading) { return; } setMode('qr'); }} /> )} {mode === 'default' && ( { if (loading) { return; } setMode('edit'); }} dataTestId="edit-profile-icon" />

{updatedProfileName || profileName}

)} {mode === 'edit' && ( { const sanitizedName = sanitizeDisplayNameOrToast(name, setProfileNameError); setProfileName(sanitizedName); }} editable={!loading} tabIndex={0} required={true} error={profileNameError} textSize={'xl'} centerText={true} inputRef={inputRef} inputDataTestId="profile-name-input" /> )} {mode !== 'qr' ? : } {!loading ? : null} {mode === 'default' || mode === 'qr' ? ( {mode === 'default' ? ( { setMode('qr'); }} dataTestId="qr-view-profile-update" /> ) : null} ) : ( !loading && ( ) )} {!loading ? : null}
); };