From bbe2802db8dad48f408e34dd5b42d0d0407abad3 Mon Sep 17 00:00:00 2001 From: Alexander Zinchuk Date: Tue, 27 Dec 2022 02:45:40 +0100 Subject: [PATCH] Profile: Allow to reset the username (#2213) --- src/api/gramjs/methods/management.ts | 6 +++++- src/api/types/users.ts | 4 ++-- src/components/common/UsernameInput.tsx | 8 ++++--- .../management/ManageChatPrivacyType.tsx | 21 +++++++++++++++---- src/global/actions/api/settings.ts | 2 +- 5 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/api/gramjs/methods/management.ts b/src/api/gramjs/methods/management.ts index 9a22d196c..c390636e7 100644 --- a/src/api/gramjs/methods/management.ts +++ b/src/api/gramjs/methods/management.ts @@ -50,7 +50,9 @@ export async function setChatUsername( username, })); - const usernames = chat.usernames!.map((u) => (u.isEditable ? { ...u, username } : u)); + const usernames = chat.usernames + ? chat.usernames.map((u) => (u.isEditable ? { ...u, username } : u)) + : [{ username, isEditable: true, isActive: true }]; if (result) { onUpdate({ @@ -59,6 +61,8 @@ export async function setChatUsername( chat: { usernames }, }); } + + return result; } export async function updatePrivateLink({ diff --git a/src/api/types/users.ts b/src/api/types/users.ts index 075d52eec..cfb78086a 100644 --- a/src/api/types/users.ts +++ b/src/api/types/users.ts @@ -60,8 +60,8 @@ export interface ApiUserStatus { export interface ApiUsername { username: string; - isActive?: true; - isEditable?: true; + isActive?: boolean; + isEditable?: boolean; } export type ApiChatType = typeof API_CHAT_TYPES[number]; diff --git a/src/components/common/UsernameInput.tsx b/src/components/common/UsernameInput.tsx index 9a77e8417..7af92404d 100644 --- a/src/components/common/UsernameInput.tsx +++ b/src/components/common/UsernameInput.tsx @@ -19,7 +19,7 @@ type OwnProps = { isLoading?: boolean; isUsernameAvailable?: boolean; checkedUsername?: string; - onChange: (value: string | false) => void; + onChange: (value: string) => void; }; const MIN_USERNAME_LENGTH = 5; @@ -30,9 +30,11 @@ const USERNAME_REGEX = /^\D([a-zA-Z0-9_]+)$/; const runDebouncedForCheckUsername = debounce((cb) => cb(), 250, false); function isUsernameValid(username: string) { - return username.length >= MIN_USERNAME_LENGTH + return username.length === 0 || ( + username.length >= MIN_USERNAME_LENGTH && username.length <= MAX_USERNAME_LENGTH - && USERNAME_REGEX.test(username); + && USERNAME_REGEX.test(username) + ); } const UsernameInput: FC = ({ diff --git a/src/components/right/management/ManageChatPrivacyType.tsx b/src/components/right/management/ManageChatPrivacyType.tsx index 07a8fe7ed..ad13599e7 100644 --- a/src/components/right/management/ManageChatPrivacyType.tsx +++ b/src/components/right/management/ManageChatPrivacyType.tsx @@ -71,6 +71,7 @@ const ManageChatPrivacyType: FC = ({ const isPublic = useMemo(() => isChatPublic(chat), [chat]); const privateLink = chat.fullInfo?.inviteLink; + const [isProfileFieldsTouched, setIsProfileFieldsTouched] = useState(false); const [privacyType, setPrivacyType] = useState(isPublic ? 'public' : 'private'); const [editableUsername, setEditableUsername] = useState(); const [isRevokeConfirmDialogOpen, openRevokeConfirmDialog, closeRevokeConfirmDialog] = useFlag(); @@ -79,8 +80,10 @@ const ManageChatPrivacyType: FC = ({ const previousIsUsernameAvailable = usePrevious(isUsernameAvailable); const renderingIsUsernameAvailable = isUsernameAvailable ?? previousIsUsernameAvailable; - const canUpdate = Boolean( - (privacyType === 'public' && editableUsername && renderingIsUsernameAvailable) + const canUpdate = isProfileFieldsTouched && Boolean( + (privacyType === 'public' + && (editableUsername || (currentUsername && editableUsername === '')) + && renderingIsUsernameAvailable) || (privacyType === 'private' && isPublic), ); @@ -89,12 +92,21 @@ const ManageChatPrivacyType: FC = ({ onBack: onClose, }); + useEffect(() => { + setIsProfileFieldsTouched(false); + }, [currentUsername]); + useEffect(() => { if (privacyType && !privateLink) { updatePrivateLink(); } }, [privacyType, privateLink, updatePrivateLink]); + const handleUsernameChange = useCallback((value: string) => { + setEditableUsername(value); + setIsProfileFieldsTouched(true); + }, []); + const handleOptionChange = useCallback((value: string, e: ChangeEvent) => { const myChats = Object.values(getGlobal().chats.byId) .filter((l) => l.isCreator && l.usernames?.some((c) => c.isActive)); @@ -109,6 +121,7 @@ const ManageChatPrivacyType: FC = ({ return; } setPrivacyType(value as PrivacyType); + setIsProfileFieldsTouched(true); }, [maxPublicLinks, openLimitReachedModal]); const handleForwardingOptionChange = useCallback((value: string) => { @@ -216,7 +229,7 @@ const ManageChatPrivacyType: FC = ({ isLoading={isLoading} isUsernameAvailable={isUsernameAvailable} checkedUsername={checkedUsername} - onChange={setEditableUsername} + onChange={handleUsernameChange} /> {error === USERNAME_PURCHASE_ERROR && renderPurchaseLink()}

@@ -228,7 +241,7 @@ const ManageChatPrivacyType: FC = ({ )}

diff --git a/src/global/actions/api/settings.ts b/src/global/actions/api/settings.ts index f2261c8b7..09b9c9243 100644 --- a/src/global/actions/api/settings.ts +++ b/src/global/actions/api/settings.ts @@ -71,7 +71,7 @@ addActionHandler('updateProfile', async (global, actions, payload) => { } } - if (username) { + if (username !== undefined) { const result = await callApi('updateUsername', username); global = getGlobal(); const currentUser = currentUserId && selectUser(global, currentUserId);