From 08fb0796ae19d98119088c19deca7292e99428ae Mon Sep 17 00:00:00 2001 From: dougfabris Date: Mon, 28 Jun 2021 19:24:26 -0300 Subject: [PATCH 1/4] fix: password input --- client/views/account/ActionConfirmModal.tsx | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/client/views/account/ActionConfirmModal.tsx b/client/views/account/ActionConfirmModal.tsx index 134ee9b2b6e5..9d857c3f7418 100644 --- a/client/views/account/ActionConfirmModal.tsx +++ b/client/views/account/ActionConfirmModal.tsx @@ -6,6 +6,8 @@ import { PasswordInput, TextInput, Modal, + FieldGroup, + Field, } from '@rocket.chat/fuselage'; import React, { useState, useCallback, FC } from 'react'; @@ -45,8 +47,14 @@ const ActionConfirmModal: FC = ({ {text} - {isPassword && } - {!isPassword && } + + + + {isPassword && } + {!isPassword && } + + + @@ -54,7 +62,7 @@ const ActionConfirmModal: FC = ({ {t('Cancel')} From 1fda429d3c27958481d254ac4e9504d33636141f Mon Sep 17 00:00:00 2001 From: dougfabris Date: Wed, 30 Jun 2021 14:11:12 -0300 Subject: [PATCH 2/4] fix: logout after delete --- client/hooks/useLogout.ts | 21 +++++++++++++++++++++ client/sidebar/header/UserDropdown.js | 19 ++++++++----------- client/views/account/AccountProfilePage.js | 20 ++++++++++++++++---- 3 files changed, 45 insertions(+), 15 deletions(-) create mode 100644 client/hooks/useLogout.ts diff --git a/client/hooks/useLogout.ts b/client/hooks/useLogout.ts new file mode 100644 index 000000000000..260818e92056 --- /dev/null +++ b/client/hooks/useLogout.ts @@ -0,0 +1,21 @@ +import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import { Meteor } from 'meteor/meteor'; + +import { callbacks } from '../../app/callbacks/client'; +import { useRoute } from '../contexts/RouterContext'; +import { useUser } from '../contexts/UserContext'; + +export default function useLogout(): () => void { + const router = useRoute('home'); + const user = useUser(); + + const handleLogout = useMutableCallback(() => { + Meteor.logout(() => { + callbacks.run('afterLogoutCleanUp', user); + Meteor.call('logoutCleanUp', user); + router.push({}); + }); + }); + + return handleLogout; +} diff --git a/client/sidebar/header/UserDropdown.js b/client/sidebar/header/UserDropdown.js index 497320a17241..bfbf1bcdb922 100644 --- a/client/sidebar/header/UserDropdown.js +++ b/client/sidebar/header/UserDropdown.js @@ -1,7 +1,6 @@ import { Box, Margins, Divider, Option } from '@rocket.chat/fuselage'; import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; import { FlowRouter } from 'meteor/kadira:flow-router'; -import { Meteor } from 'meteor/meteor'; import React from 'react'; import { callbacks } from '../../../app/callbacks/client'; @@ -14,6 +13,7 @@ import { useAtLeastOnePermission } from '../../contexts/AuthorizationContext'; import { useRoute } from '../../contexts/RouterContext'; import { useSetting } from '../../contexts/SettingsContext'; import { useTranslation } from '../../contexts/TranslationContext'; +import useLogout from '../../hooks/useLogout'; import { useReactiveValue } from '../../hooks/useReactiveValue'; const ADMIN_PERMISSIONS = [ @@ -47,10 +47,11 @@ const getItems = () => AccountBox.getItems(); const UserDropdown = ({ user, onClose }) => { const t = useTranslation(); - const homeRoute = useRoute('home'); const accountRoute = useRoute('account'); const adminRoute = useRoute('admin'); + const logout = useLogout(); + const { name, username, avatarETag, status, statusText } = user; const useRealName = useSetting('UI_Use_Real_Name'); @@ -78,15 +79,6 @@ const UserDropdown = ({ user, onClose }) => { onClose(); }); - const handleLogout = useMutableCallback(() => { - Meteor.logout(() => { - callbacks.run('afterLogoutCleanUp', user); - Meteor.call('logoutCleanUp', user); - homeRoute.push({}); - popover.close(); - }); - }); - const handleMyAccount = useMutableCallback(() => { accountRoute.push({}); popover.close(); @@ -97,6 +89,11 @@ const UserDropdown = ({ user, onClose }) => { popover.close(); }); + const handleLogout = useMutableCallback(() => { + logout(); + popover.close(); + }); + const accountBoxItems = useReactiveValue(getItems); return ( diff --git a/client/views/account/AccountProfilePage.js b/client/views/account/AccountProfilePage.js index e6bae83c4afd..4d95a6b178f1 100644 --- a/client/views/account/AccountProfilePage.js +++ b/client/views/account/AccountProfilePage.js @@ -12,6 +12,7 @@ import { useToastMessageDispatch } from '../../contexts/ToastMessagesContext'; import { useTranslation } from '../../contexts/TranslationContext'; import { useUser } from '../../contexts/UserContext'; import { useForm } from '../../hooks/useForm'; +import useLogout from '../../hooks/useLogout'; import { useUpdateAvatar } from '../../hooks/useUpdateAvatar'; import AccountProfileForm from './AccountProfileForm'; import ActionConfirmModal from './ActionConfirmModal'; @@ -37,9 +38,10 @@ const AccountProfilePage = () => { const user = useUser(); - const { values, handlers, hasUnsavedChanges, commit } = useForm(getInitialValues(user)); + const { values, handlers, hasUnsavedChanges, commit } = useForm(getInitialValues(user ?? {})); const [canSave, setCanSave] = useState(true); const setModal = useSetModal(); + const logout = useLogout(); const [loggingOut, setLoggingOut] = useState(false); const logoutOtherClients = useMethod('logoutOtherClients'); @@ -114,7 +116,7 @@ const AccountProfilePage = () => { const { handleAvatar, handlePassword, handleConfirmationPassword } = handlers; - const updateAvatar = useUpdateAvatar(avatar, user._id); + const updateAvatar = useUpdateAvatar(avatar, user?._id); const onSave = useCallback(async () => { const save = async (typedPassword) => { @@ -192,6 +194,7 @@ const AccountProfilePage = () => { try { await deleteOwnAccount(SHA256(passwordOrUsername)); dispatchToastMessage({ type: 'success', message: t('User_has_been_deleted') }); + logout(); } catch (error) { if (error.error === 'user-last-owner') { const { shouldChangeOwner, shouldBeRemoved } = error.details; @@ -233,7 +236,16 @@ const AccountProfilePage = () => { text={t('If_you_are_sure_type_in_your_username')} /> )); - }, [closeModal, deleteOwnAccount, dispatchToastMessage, erasureType, localPassword, t, setModal]); + }, [ + closeModal, + deleteOwnAccount, + dispatchToastMessage, + erasureType, + localPassword, + t, + logout, + setModal, + ]); return ( @@ -249,7 +261,7 @@ const AccountProfilePage = () => { From f7c83a7123fb250b774025a2aea0e5a918380617 Mon Sep 17 00:00:00 2001 From: dougfabris Date: Thu, 1 Jul 2021 11:57:27 -0300 Subject: [PATCH 3/4] fix: insert the hook to UserContext Co-authored-by: gabriellsh <40830821+gabriellsh@users.noreply.github.com> --- client/contexts/UserContext.ts | 16 ++++++++++++++++ client/hooks/useLogout.ts | 21 --------------------- client/providers/UserProvider.tsx | 9 +++++++++ client/sidebar/header/UserDropdown.js | 2 +- client/views/account/AccountProfilePage.js | 3 +-- 5 files changed, 27 insertions(+), 24 deletions(-) delete mode 100644 client/hooks/useLogout.ts diff --git a/client/contexts/UserContext.ts b/client/contexts/UserContext.ts index 95443bae0099..5c78bbf4fc98 100644 --- a/client/contexts/UserContext.ts +++ b/client/contexts/UserContext.ts @@ -1,9 +1,11 @@ +import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; import { FilterQuery } from 'mongodb'; import { createContext, useContext, useMemo } from 'react'; import { useSubscription, Subscription, Unsubscribe } from 'use-subscription'; import { IRoom } from '../../definition/IRoom'; import { ISubscription } from '../../definition/ISubscription'; +import { useRoute } from './RouterContext'; type SubscriptionQuery = | { @@ -34,6 +36,7 @@ type UserContextValue = { userId: string | null; user: Meteor.User | null; loginWithPassword: (user: string | object, password: string) => Promise; + logout: (user: Meteor.User) => void; queryPreference: ( key: string | Mongo.ObjectID, defaultValue?: T, @@ -58,6 +61,7 @@ export const UserContext = createContext({ userId: null, user: null, loginWithPassword: async () => undefined, + logout: () => undefined, queryPreference: () => ({ getCurrentValue: (): undefined => undefined, subscribe: (): Unsubscribe => (): void => undefined, @@ -85,6 +89,18 @@ export const useLoginWithPassword = (): (( password: string, ) => Promise) => useContext(UserContext).loginWithPassword; +export const useLogout = (user: Meteor.User): (() => void) => { + const router = useRoute('home'); + const { logout } = useContext(UserContext); + + const handleLogout = useMutableCallback(() => { + logout(user); + router.push({}); + }); + + return handleLogout; +}; + export const useUserPreference = (key: string, defaultValue?: T): T | undefined => { const { queryPreference } = useContext(UserContext); const subscription = useMemo(() => queryPreference(key, defaultValue), [ diff --git a/client/hooks/useLogout.ts b/client/hooks/useLogout.ts deleted file mode 100644 index 260818e92056..000000000000 --- a/client/hooks/useLogout.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; -import { Meteor } from 'meteor/meteor'; - -import { callbacks } from '../../app/callbacks/client'; -import { useRoute } from '../contexts/RouterContext'; -import { useUser } from '../contexts/UserContext'; - -export default function useLogout(): () => void { - const router = useRoute('home'); - const user = useUser(); - - const handleLogout = useMutableCallback(() => { - Meteor.logout(() => { - callbacks.run('afterLogoutCleanUp', user); - Meteor.call('logoutCleanUp', user); - router.push({}); - }); - }); - - return handleLogout; -} diff --git a/client/providers/UserProvider.tsx b/client/providers/UserProvider.tsx index 5fe62a317de4..36618819bf7f 100644 --- a/client/providers/UserProvider.tsx +++ b/client/providers/UserProvider.tsx @@ -1,6 +1,7 @@ import { Meteor } from 'meteor/meteor'; import React, { useMemo, FC } from 'react'; +import { callbacks } from '../../app/callbacks/client'; import { Subscriptions, Rooms } from '../../app/models/client'; import { getUserPreference } from '../../app/utils/client'; import { IRoom } from '../../definition/IRoom'; @@ -29,6 +30,13 @@ const loginWithPassword = (user: string | object, password: string): Promise { + Meteor.logout(() => { + callbacks.run('afterLogoutCleanUp', user); + Meteor.call('logoutCleanUp', user); + }); +}; + const UserProvider: FC = ({ children }) => { const userId = useReactiveValue(getUserId); const user = useReactiveValue(getUser); @@ -37,6 +45,7 @@ const UserProvider: FC = ({ children }) => { userId, user, loginWithPassword, + logout, queryPreference: createReactiveSubscriptionFactory((key, defaultValue) => getUserPreference(userId, key, defaultValue), ), diff --git a/client/sidebar/header/UserDropdown.js b/client/sidebar/header/UserDropdown.js index bfbf1bcdb922..1f06b444c547 100644 --- a/client/sidebar/header/UserDropdown.js +++ b/client/sidebar/header/UserDropdown.js @@ -13,7 +13,7 @@ import { useAtLeastOnePermission } from '../../contexts/AuthorizationContext'; import { useRoute } from '../../contexts/RouterContext'; import { useSetting } from '../../contexts/SettingsContext'; import { useTranslation } from '../../contexts/TranslationContext'; -import useLogout from '../../hooks/useLogout'; +import { useLogout } from '../../contexts/UserContext'; import { useReactiveValue } from '../../hooks/useReactiveValue'; const ADMIN_PERMISSIONS = [ diff --git a/client/views/account/AccountProfilePage.js b/client/views/account/AccountProfilePage.js index 4d95a6b178f1..da4d398412c7 100644 --- a/client/views/account/AccountProfilePage.js +++ b/client/views/account/AccountProfilePage.js @@ -10,9 +10,8 @@ import { useMethod } from '../../contexts/ServerContext'; import { useSetting } from '../../contexts/SettingsContext'; import { useToastMessageDispatch } from '../../contexts/ToastMessagesContext'; import { useTranslation } from '../../contexts/TranslationContext'; -import { useUser } from '../../contexts/UserContext'; +import { useUser, useLogout } from '../../contexts/UserContext'; import { useForm } from '../../hooks/useForm'; -import useLogout from '../../hooks/useLogout'; import { useUpdateAvatar } from '../../hooks/useUpdateAvatar'; import AccountProfileForm from './AccountProfileForm'; import ActionConfirmModal from './ActionConfirmModal'; From 88989d5160391e0dc1d9fb3e0beff1b666ef64d2 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Thu, 1 Jul 2021 15:20:17 -0300 Subject: [PATCH 4/4] Fix Review --- client/contexts/UserContext.ts | 45 ++++++++++++++----------------- client/providers/UserProvider.tsx | 17 ++++++++---- 2 files changed, 32 insertions(+), 30 deletions(-) diff --git a/client/contexts/UserContext.ts b/client/contexts/UserContext.ts index 5c78bbf4fc98..ad03abc595b5 100644 --- a/client/contexts/UserContext.ts +++ b/client/contexts/UserContext.ts @@ -36,7 +36,7 @@ type UserContextValue = { userId: string | null; user: Meteor.User | null; loginWithPassword: (user: string | object, password: string) => Promise; - logout: (user: Meteor.User) => void; + logout: () => Promise; queryPreference: ( key: string | Mongo.ObjectID, defaultValue?: T, @@ -61,7 +61,7 @@ export const UserContext = createContext({ userId: null, user: null, loginWithPassword: async () => undefined, - logout: () => undefined, + logout: () => Promise.resolve(), queryPreference: () => ({ getCurrentValue: (): undefined => undefined, subscribe: (): Unsubscribe => (): void => undefined, @@ -89,12 +89,12 @@ export const useLoginWithPassword = (): (( password: string, ) => Promise) => useContext(UserContext).loginWithPassword; -export const useLogout = (user: Meteor.User): (() => void) => { +export const useLogout = (): (() => void) => { const router = useRoute('home'); const { logout } = useContext(UserContext); const handleLogout = useMutableCallback(() => { - logout(user); + logout(); router.push({}); }); @@ -103,21 +103,19 @@ export const useLogout = (user: Meteor.User): (() => void) => { export const useUserPreference = (key: string, defaultValue?: T): T | undefined => { const { queryPreference } = useContext(UserContext); - const subscription = useMemo(() => queryPreference(key, defaultValue), [ - queryPreference, - key, - defaultValue, - ]); + const subscription = useMemo( + () => queryPreference(key, defaultValue), + [queryPreference, key, defaultValue], + ); return useSubscription(subscription); }; export const useUserSubscription = (rid: string, fields: Fields): ISubscription | undefined => { const { querySubscription } = useContext(UserContext); - const subscription = useMemo(() => querySubscription({ rid }, fields), [ - querySubscription, - rid, - fields, - ]); + const subscription = useMemo( + () => querySubscription({ rid }, fields), + [querySubscription, rid, fields], + ); return useSubscription(subscription); }; @@ -132,11 +130,10 @@ export const useUserSubscriptions = ( options?: FindOptions, ): Array | [] => { const { querySubscriptions } = useContext(UserContext); - const subscription = useMemo(() => querySubscriptions(query, options), [ - querySubscriptions, - query, - options, - ]); + const subscription = useMemo( + () => querySubscriptions(query, options), + [querySubscriptions, query, options], + ); return useSubscription(subscription); }; @@ -146,11 +143,9 @@ export const useUserSubscriptionByName = ( sort?: Sort, ): ISubscription | undefined => { const { querySubscription } = useContext(UserContext); - const subscription = useMemo(() => querySubscription({ name }, fields, sort), [ - querySubscription, - name, - fields, - sort, - ]); + const subscription = useMemo( + () => querySubscription({ name }, fields, sort), + [querySubscription, name, fields, sort], + ); return useSubscription(subscription); }; diff --git a/client/providers/UserProvider.tsx b/client/providers/UserProvider.tsx index 36618819bf7f..45a91b6adf97 100644 --- a/client/providers/UserProvider.tsx +++ b/client/providers/UserProvider.tsx @@ -30,12 +30,19 @@ const loginWithPassword = (user: string | object, password: string): Promise { - Meteor.logout(() => { - callbacks.run('afterLogoutCleanUp', user); - Meteor.call('logoutCleanUp', user); +const logout = (): Promise => + new Promise((resolve) => { + const user = Meteor.user(); + + if (!user) { + return resolve(); + } + + Meteor.logout(() => { + callbacks.run('afterLogoutCleanUp', user); + Meteor.call('logoutCleanUp', user, resolve); + }); }); -}; const UserProvider: FC = ({ children }) => { const userId = useReactiveValue(getUserId);