mirror of
https://github.com/lingble/chatwoot.git
synced 2025-11-01 03:27:52 +00:00
chore: Ability to change default account (#5393)
Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com> Co-authored-by: Tejaswini Chile <tejaswini@chatwoot.com>
This commit is contained in:
@@ -22,6 +22,11 @@ class Api::V1::ProfilesController < Api::BaseController
|
|||||||
@user.account_users.find_by!(account_id: availability_params[:account_id]).update!(availability: availability_params[:availability])
|
@user.account_users.find_by!(account_id: availability_params[:account_id]).update!(availability: availability_params[:availability])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def set_active_account
|
||||||
|
@user.account_users.find_by(account_id: profile_params[:account_id]).update(active_at: Time.now.utc)
|
||||||
|
head :ok
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def set_user
|
def set_user
|
||||||
@@ -39,6 +44,7 @@ class Api::V1::ProfilesController < Api::BaseController
|
|||||||
:display_name,
|
:display_name,
|
||||||
:avatar,
|
:avatar,
|
||||||
:message_signature,
|
:message_signature,
|
||||||
|
:account_id,
|
||||||
ui_settings: {}
|
ui_settings: {}
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -87,6 +87,9 @@ export default {
|
|||||||
},
|
},
|
||||||
async initializeAccount() {
|
async initializeAccount() {
|
||||||
await this.$store.dispatch('accounts/get');
|
await this.$store.dispatch('accounts/get');
|
||||||
|
this.$store.dispatch('setActiveAccount', {
|
||||||
|
accountId: this.currentAccountId,
|
||||||
|
});
|
||||||
const {
|
const {
|
||||||
locale,
|
locale,
|
||||||
latest_chatwoot_version: latestChatwootVersion,
|
latest_chatwoot_version: latestChatwootVersion,
|
||||||
|
|||||||
@@ -147,4 +147,13 @@ export default {
|
|||||||
deleteAvatar() {
|
deleteAvatar() {
|
||||||
return axios.delete(endPoints('deleteAvatar').url);
|
return axios.delete(endPoints('deleteAvatar').url);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setActiveAccount({ accountId }) {
|
||||||
|
const urlData = endPoints('setActiveAccount');
|
||||||
|
return axios.put(urlData.url, {
|
||||||
|
profile: {
|
||||||
|
account_id: accountId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -40,6 +40,10 @@ const endPoints = {
|
|||||||
deleteAvatar: {
|
deleteAvatar: {
|
||||||
url: '/api/v1/profile/avatar',
|
url: '/api/v1/profile/avatar',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setActiveAccount: {
|
||||||
|
url: '/api/v1/profile/set_active_account',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default page => {
|
export default page => {
|
||||||
|
|||||||
@@ -8,25 +8,33 @@
|
|||||||
:header-title="$t('SIDEBAR_ITEMS.CHANGE_ACCOUNTS')"
|
:header-title="$t('SIDEBAR_ITEMS.CHANGE_ACCOUNTS')"
|
||||||
:header-content="$t('SIDEBAR_ITEMS.SELECTOR_SUBTITLE')"
|
:header-content="$t('SIDEBAR_ITEMS.SELECTOR_SUBTITLE')"
|
||||||
/>
|
/>
|
||||||
<div
|
<div class="account-selector--wrap">
|
||||||
v-for="account in currentUser.accounts"
|
<div
|
||||||
:key="account.id"
|
v-for="account in currentUser.accounts"
|
||||||
class="account-selector"
|
:key="account.id"
|
||||||
>
|
class="account-selector"
|
||||||
<a :href="`/app/accounts/${account.id}/dashboard`">
|
>
|
||||||
<fluent-icon
|
<button
|
||||||
v-if="account.id === accountId"
|
class="button expanded clear link"
|
||||||
class="selected--account"
|
@click="onChangeAccount(account.id)"
|
||||||
icon="checkmark-circle"
|
>
|
||||||
type="solid"
|
<span class="button__content">
|
||||||
size="24"
|
<label :for="account.name" class="account-details--wrap">
|
||||||
/>
|
<div class="account--name">{{ account.name }}</div>
|
||||||
<label :for="account.name" class="account--details">
|
<div class="account--role">{{ account.role }}</div>
|
||||||
<div class="account--name">{{ account.name }}</div>
|
</label>
|
||||||
<div class="account--role">{{ account.role }}</div>
|
</span>
|
||||||
</label>
|
<fluent-icon
|
||||||
</a>
|
v-show="account.id === accountId"
|
||||||
|
class="selected--account"
|
||||||
|
icon="checkmark-circle"
|
||||||
|
type="solid"
|
||||||
|
size="24"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
v-if="globalConfig.createNewAccountFromDashboard"
|
v-if="globalConfig.createNewAccountFromDashboard"
|
||||||
class="modal-footer delete-item"
|
class="modal-footer delete-item"
|
||||||
@@ -58,5 +66,40 @@ export default {
|
|||||||
globalConfig: 'globalConfig/get',
|
globalConfig: 'globalConfig/get',
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
methods: {
|
||||||
|
onChangeAccount(accountId) {
|
||||||
|
const accountUrl = `/app/accounts/${accountId}/dashboard`;
|
||||||
|
window.location.href = accountUrl;
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.account-selector--wrap {
|
||||||
|
margin-top: var(--space-normal);
|
||||||
|
}
|
||||||
|
.account-selector {
|
||||||
|
padding-top: 0;
|
||||||
|
padding-bottom: 0;
|
||||||
|
.button {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: var(--space-one) var(--space-normal);
|
||||||
|
.account-details--wrap {
|
||||||
|
text-align: left;
|
||||||
|
.account--name {
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: var(--font-size-medium);
|
||||||
|
font-weight: var(--font-weight-medium);
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account--role {
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: var(--font-size-mini);
|
||||||
|
text-transform: capitalize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ export const frontendURL = (path, params) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getSSOAccountPath = ({ ssoAccountId, user }) => {
|
const getSSOAccountPath = ({ ssoAccountId, user }) => {
|
||||||
const { accounts = [] } = user || {};
|
const { accounts = [], account_id = null } = user || {};
|
||||||
const ssoAccount = accounts.find(
|
const ssoAccount = accounts.find(
|
||||||
account => account.id === Number(ssoAccountId)
|
account => account.id === Number(ssoAccountId)
|
||||||
);
|
);
|
||||||
@@ -14,7 +14,9 @@ const getSSOAccountPath = ({ ssoAccountId, user }) => {
|
|||||||
if (ssoAccount) {
|
if (ssoAccount) {
|
||||||
accountPath = `accounts/${ssoAccountId}`;
|
accountPath = `accounts/${ssoAccountId}`;
|
||||||
} else if (accounts.length) {
|
} else if (accounts.length) {
|
||||||
accountPath = `accounts/${accounts[0].id}`;
|
// If the account id is not found, redirect to the first account
|
||||||
|
const accountId = account_id || accounts[0].id;
|
||||||
|
accountPath = `accounts/${accountId}`;
|
||||||
}
|
}
|
||||||
return accountPath;
|
return accountPath;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -179,6 +179,14 @@ export const actions = {
|
|||||||
commit(types.SET_CURRENT_USER_AVAILABILITY, data[$state.currentUser.id]);
|
commit(types.SET_CURRENT_USER_AVAILABILITY, data[$state.currentUser.id]);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setActiveAccount: async (_, { accountId }) => {
|
||||||
|
try {
|
||||||
|
await authAPI.setActiveAccount({ accountId });
|
||||||
|
} catch (error) {
|
||||||
|
// Ignore error
|
||||||
|
}
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// mutations
|
// mutations
|
||||||
|
|||||||
@@ -165,4 +165,15 @@ describe('#actions', () => {
|
|||||||
expect(commit.mock.calls).toEqual([]);
|
expect(commit.mock.calls).toEqual([]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('#setActiveAccount', () => {
|
||||||
|
it('sends correct mutations if account id is available', async () => {
|
||||||
|
actions.setActiveAccount(
|
||||||
|
{
|
||||||
|
commit,
|
||||||
|
},
|
||||||
|
{ accountId: 1 }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -182,6 +182,7 @@ Rails.application.routes.draw do
|
|||||||
delete :avatar, on: :collection
|
delete :avatar, on: :collection
|
||||||
member do
|
member do
|
||||||
post :availability
|
post :availability
|
||||||
|
put :set_active_account
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -195,4 +195,27 @@ RSpec.describe 'Profile API', type: :request do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'PUT /api/v1/profile/set_active_account' do
|
||||||
|
context 'when it is an unauthenticated user' do
|
||||||
|
it 'returns unauthorized' do
|
||||||
|
put '/api/v1/profile/set_active_account'
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:unauthorized)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when it is an authenticated user' do
|
||||||
|
let(:agent) { create(:user, password: 'Test123!', account: account, role: :agent) }
|
||||||
|
|
||||||
|
it 'updates the last active account id' do
|
||||||
|
put '/api/v1/profile/set_active_account',
|
||||||
|
params: { profile: { account_id: account.id } },
|
||||||
|
headers: agent.create_new_auth_token,
|
||||||
|
as: :json
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:success)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user