From 22fdb50d880dae33deaf5c269c5ab41736453930 Mon Sep 17 00:00:00 2001 From: Sol Fisher Romanoff Date: Tue, 7 Feb 2023 18:36:41 +0200 Subject: [PATCH] feat: account switching --- src/boot/after_store.js | 2 +- .../account_switcher/account_switcher.js | 52 +++++++++++ .../account_switcher/account_switcher.vue | 90 +++++++++++++++++++ src/components/login_form/login_form.js | 2 +- .../oauth_callback/oauth_callback.js | 1 + .../settings_modal/settings_modal.js | 9 +- src/components/user_card/user_card.js | 10 ++- src/components/user_card/user_card.scss | 4 +- src/components/user_card/user_card.vue | 1 + src/modules/auth_flow.js | 4 +- src/modules/oauth.js | 10 +-- src/modules/users.js | 29 +++++- 12 files changed, 195 insertions(+), 19 deletions(-) create mode 100644 src/components/account_switcher/account_switcher.js create mode 100644 src/components/account_switcher/account_switcher.vue diff --git a/src/boot/after_store.js b/src/boot/after_store.js index 36b087a5..bc0e7ce3 100644 --- a/src/boot/after_store.js +++ b/src/boot/after_store.js @@ -349,7 +349,7 @@ const checkOAuthToken = async ({ store }) => { return new Promise(async (resolve, reject) => { if (store.getters.getUserToken()) { try { - await store.dispatch('loginUser', store.getters.getUserToken()) + await store.dispatch('loginUser', store.getters.getUserToken()[store.state.users.lastLoginName]) } catch (e) { console.error(e) } diff --git a/src/components/account_switcher/account_switcher.js b/src/components/account_switcher/account_switcher.js new file mode 100644 index 00000000..49ef4a34 --- /dev/null +++ b/src/components/account_switcher/account_switcher.js @@ -0,0 +1,52 @@ +import Popover from '../popover/popover.vue' +import UserAvatar from '../user_avatar/user_avatar.vue' +import RichContent from '../rich_content/rich_content.jsx' +import { map } from 'lodash' +import { library } from '@fortawesome/fontawesome-svg-core' +import { + faRightToBracket, + faUserPen +} from '@fortawesome/free-solid-svg-icons' + +library.add( + faRightToBracket, + faUserPen +) + +const AccountSwitcher = { + components: { + Popover, + UserAvatar, + RichContent + }, + computed: { + currentUser () { + return this.$store.state.users.currentUser + }, + accounts () { + return map(Object.keys(this.$store.state.oauth.userToken), username => ( + this.$store.getters.findUser(username) + )) + }, + registrationOpen () { + return this.$store.state.instance.registrationOpen + } + }, + methods: { + login () { + this.$store.commit('beginAccountSwitch') + this.$router.push({ name: 'login' }) + }, + switchAccount (username, token) { + // don't switch to same user + if (username !== this.currentUser.screen_name) { + this.$store.commit('beginAccountSwitch') + this.$store.dispatch('loginUser', this.$store.state.oauth.userToken[username]).then(() => { + this.$router.push({ name: 'friends' }) + }) + } + } + } +} + +export default AccountSwitcher diff --git a/src/components/account_switcher/account_switcher.vue b/src/components/account_switcher/account_switcher.vue new file mode 100644 index 00000000..4f8ac4bf --- /dev/null +++ b/src/components/account_switcher/account_switcher.vue @@ -0,0 +1,90 @@ + + + + + diff --git a/src/components/login_form/login_form.js b/src/components/login_form/login_form.js index 638bd812..6ca7e6c6 100644 --- a/src/components/login_form/login_form.js +++ b/src/components/login_form/login_form.js @@ -75,7 +75,7 @@ const LoginForm = { } return } - this.login(result).then(() => { + this.login({ username: this.user.username, ...result }).then(() => { this.$router.push({ name: 'friends' }) }) }) diff --git a/src/components/oauth_callback/oauth_callback.js b/src/components/oauth_callback/oauth_callback.js index a3c7b7f9..c5b1caa7 100644 --- a/src/components/oauth_callback/oauth_callback.js +++ b/src/components/oauth_callback/oauth_callback.js @@ -6,6 +6,7 @@ const oac = { if (this.code) { const { clientId, clientSecret } = this.$store.state.oauth + // XXX look at this later oauth.getToken({ clientId, clientSecret, diff --git a/src/components/settings_modal/settings_modal.js b/src/components/settings_modal/settings_modal.js index 27dab3ec..86757231 100644 --- a/src/components/settings_modal/settings_modal.js +++ b/src/components/settings_modal/settings_modal.js @@ -69,9 +69,16 @@ const SettingsModal = { this.$store.dispatch('closeSettingsModal') }, logout () { - this.$router.replace('/main/public') this.$store.dispatch('closeSettingsModal') + this.$router.replace('/main/public') this.$store.dispatch('logout') + .then(() => { + // check if logged in to other accounts + const accounts = Object.keys(this.$store.state.oauth.userToken) + if (accounts !== []) { + this.$store.dispatch('loginUser', this.$store.state.oauth.userToken[accounts[0]]) + } + }) }, peekModal () { this.$store.dispatch('togglePeekSettingsModal') diff --git a/src/components/user_card/user_card.js b/src/components/user_card/user_card.js index f7bff63f..ffbeed31 100644 --- a/src/components/user_card/user_card.js +++ b/src/components/user_card/user_card.js @@ -7,6 +7,7 @@ import AccountActions from '../account_actions/account_actions.vue' import Select from '../select/select.vue' import RichContent from 'src/components/rich_content/rich_content.jsx' import ConfirmModal from '../confirm_modal/confirm_modal.vue' +import AccountSwitcher from '../account_switcher/account_switcher.vue' import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator' import { mapGetters } from 'vuex' import { library } from '@fortawesome/fontawesome-svg-core' @@ -15,7 +16,8 @@ import { faRss, faSearchPlus, faExternalLinkAlt, - faEdit + faEdit, + faUserPlus, } from '@fortawesome/free-solid-svg-icons' library.add( @@ -23,7 +25,8 @@ library.add( faBell, faSearchPlus, faExternalLinkAlt, - faEdit + faEdit, + faUserPlus, ) export default { @@ -128,7 +131,8 @@ export default { FollowButton, Select, RichContent, - ConfirmModal + ConfirmModal, + AccountSwitcher }, methods: { refetchRelationship () { diff --git a/src/components/user_card/user_card.scss b/src/components/user_card/user_card.scss index 0a5e744e..28f4d338 100644 --- a/src/components/user_card/user_card.scss +++ b/src/components/user_card/user_card.scss @@ -110,7 +110,7 @@ min-width: 0; } - .Avatar { + a .Avatar { --_avatarShadowBox: var(--avatarShadow); --_avatarShadowFilter: var(--avatarShadowFilter); --_avatarShadowInset: var(--avatarShadowInset); @@ -151,7 +151,7 @@ } } - .external-link-button, .edit-profile-button { + .external-link-button, .edit-profile-button, .switch-account-button { cursor: pointer; width: 2.5em; text-align: center; diff --git a/src/components/user_card/user_card.vue b/src/components/user_card/user_card.vue index 289db15b..87e5c37a 100644 --- a/src/components/user_card/user_card.vue +++ b/src/components/user_card/user_card.vue @@ -56,6 +56,7 @@ :title="$t('user_card.edit_profile')" /> + { store.commit('clearCurrentUser') store.dispatch('disconnectFromSocket') - store.commit('clearToken') + store.commit('clearToken', data.username) store.dispatch('stopFetchingTimeline', 'friends') store.commit('setBackendInteractor', backendInteractorService(store.getters.getToken())) store.dispatch('stopFetchingNotifications') @@ -594,6 +602,19 @@ const users = { store.rootState.api.backendInteractor.verifyCredentials(accessToken) .then((data) => { if (!data.error) { + // clear old user + // TODO: maybe we don't need some of this + if (store.state.loggingIn) { + store.commit('clearCurrentUser') + store.dispatch('disconnectFromSocket') + store.dispatch('stopFetchingTimeline', 'friends') + store.dispatch('stopFetchingNotifications') + store.dispatch('stopFetchingConfig') + store.commit('clearNotifications') + store.commit('resetStatuses') + store.commit('endAccountSwitch') + } + const user = data // user.credentials = userCredentials user.credentials = accessToken