Profile: Allow to reset the username (#2213)

This commit is contained in:
Alexander Zinchuk 2022-12-27 02:45:40 +01:00
parent dd49420851
commit bbe2802db8
5 changed files with 30 additions and 11 deletions

View File

@ -50,7 +50,9 @@ export async function setChatUsername(
username, 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) { if (result) {
onUpdate({ onUpdate({
@ -59,6 +61,8 @@ export async function setChatUsername(
chat: { usernames }, chat: { usernames },
}); });
} }
return result;
} }
export async function updatePrivateLink({ export async function updatePrivateLink({

View File

@ -60,8 +60,8 @@ export interface ApiUserStatus {
export interface ApiUsername { export interface ApiUsername {
username: string; username: string;
isActive?: true; isActive?: boolean;
isEditable?: true; isEditable?: boolean;
} }
export type ApiChatType = typeof API_CHAT_TYPES[number]; export type ApiChatType = typeof API_CHAT_TYPES[number];

View File

@ -19,7 +19,7 @@ type OwnProps = {
isLoading?: boolean; isLoading?: boolean;
isUsernameAvailable?: boolean; isUsernameAvailable?: boolean;
checkedUsername?: string; checkedUsername?: string;
onChange: (value: string | false) => void; onChange: (value: string) => void;
}; };
const MIN_USERNAME_LENGTH = 5; const MIN_USERNAME_LENGTH = 5;
@ -30,9 +30,11 @@ const USERNAME_REGEX = /^\D([a-zA-Z0-9_]+)$/;
const runDebouncedForCheckUsername = debounce((cb) => cb(), 250, false); const runDebouncedForCheckUsername = debounce((cb) => cb(), 250, false);
function isUsernameValid(username: string) { 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.length <= MAX_USERNAME_LENGTH
&& USERNAME_REGEX.test(username); && USERNAME_REGEX.test(username)
);
} }
const UsernameInput: FC<OwnProps> = ({ const UsernameInput: FC<OwnProps> = ({

View File

@ -71,6 +71,7 @@ const ManageChatPrivacyType: FC<OwnProps & StateProps> = ({
const isPublic = useMemo(() => isChatPublic(chat), [chat]); const isPublic = useMemo(() => isChatPublic(chat), [chat]);
const privateLink = chat.fullInfo?.inviteLink; const privateLink = chat.fullInfo?.inviteLink;
const [isProfileFieldsTouched, setIsProfileFieldsTouched] = useState(false);
const [privacyType, setPrivacyType] = useState<PrivacyType>(isPublic ? 'public' : 'private'); const [privacyType, setPrivacyType] = useState<PrivacyType>(isPublic ? 'public' : 'private');
const [editableUsername, setEditableUsername] = useState(); const [editableUsername, setEditableUsername] = useState();
const [isRevokeConfirmDialogOpen, openRevokeConfirmDialog, closeRevokeConfirmDialog] = useFlag(); const [isRevokeConfirmDialogOpen, openRevokeConfirmDialog, closeRevokeConfirmDialog] = useFlag();
@ -79,8 +80,10 @@ const ManageChatPrivacyType: FC<OwnProps & StateProps> = ({
const previousIsUsernameAvailable = usePrevious(isUsernameAvailable); const previousIsUsernameAvailable = usePrevious(isUsernameAvailable);
const renderingIsUsernameAvailable = isUsernameAvailable ?? previousIsUsernameAvailable; const renderingIsUsernameAvailable = isUsernameAvailable ?? previousIsUsernameAvailable;
const canUpdate = Boolean( const canUpdate = isProfileFieldsTouched && Boolean(
(privacyType === 'public' && editableUsername && renderingIsUsernameAvailable) (privacyType === 'public'
&& (editableUsername || (currentUsername && editableUsername === ''))
&& renderingIsUsernameAvailable)
|| (privacyType === 'private' && isPublic), || (privacyType === 'private' && isPublic),
); );
@ -89,12 +92,21 @@ const ManageChatPrivacyType: FC<OwnProps & StateProps> = ({
onBack: onClose, onBack: onClose,
}); });
useEffect(() => {
setIsProfileFieldsTouched(false);
}, [currentUsername]);
useEffect(() => { useEffect(() => {
if (privacyType && !privateLink) { if (privacyType && !privateLink) {
updatePrivateLink(); updatePrivateLink();
} }
}, [privacyType, privateLink, updatePrivateLink]); }, [privacyType, privateLink, updatePrivateLink]);
const handleUsernameChange = useCallback((value: string) => {
setEditableUsername(value);
setIsProfileFieldsTouched(true);
}, []);
const handleOptionChange = useCallback((value: string, e: ChangeEvent<HTMLInputElement>) => { const handleOptionChange = useCallback((value: string, e: ChangeEvent<HTMLInputElement>) => {
const myChats = Object.values(getGlobal().chats.byId) const myChats = Object.values(getGlobal().chats.byId)
.filter((l) => l.isCreator && l.usernames?.some((c) => c.isActive)); .filter((l) => l.isCreator && l.usernames?.some((c) => c.isActive));
@ -109,6 +121,7 @@ const ManageChatPrivacyType: FC<OwnProps & StateProps> = ({
return; return;
} }
setPrivacyType(value as PrivacyType); setPrivacyType(value as PrivacyType);
setIsProfileFieldsTouched(true);
}, [maxPublicLinks, openLimitReachedModal]); }, [maxPublicLinks, openLimitReachedModal]);
const handleForwardingOptionChange = useCallback((value: string) => { const handleForwardingOptionChange = useCallback((value: string) => {
@ -216,7 +229,7 @@ const ManageChatPrivacyType: FC<OwnProps & StateProps> = ({
isLoading={isLoading} isLoading={isLoading}
isUsernameAvailable={isUsernameAvailable} isUsernameAvailable={isUsernameAvailable}
checkedUsername={checkedUsername} checkedUsername={checkedUsername}
onChange={setEditableUsername} onChange={handleUsernameChange}
/> />
{error === USERNAME_PURCHASE_ERROR && renderPurchaseLink()} {error === USERNAME_PURCHASE_ERROR && renderPurchaseLink()}
<p className="section-info" dir="auto"> <p className="section-info" dir="auto">
@ -228,7 +241,7 @@ const ManageChatPrivacyType: FC<OwnProps & StateProps> = ({
<ManageUsernames <ManageUsernames
chatId={chat.id} chatId={chat.id}
usernames={chat.usernames!} usernames={chat.usernames!}
onEditUsername={setEditableUsername} onEditUsername={handleUsernameChange}
/> />
)} )}
<div className="section" dir={lang.isRtl ? 'rtl' : undefined}> <div className="section" dir={lang.isRtl ? 'rtl' : undefined}>

View File

@ -71,7 +71,7 @@ addActionHandler('updateProfile', async (global, actions, payload) => {
} }
} }
if (username) { if (username !== undefined) {
const result = await callApi('updateUsername', username); const result = await callApi('updateUsername', username);
global = getGlobal(); global = getGlobal();
const currentUser = currentUserId && selectUser(global, currentUserId); const currentUser = currentUserId && selectUser(global, currentUserId);