diff --git a/app/controllers/api/v1/profiles_controller.rb b/app/controllers/api/v1/profiles_controller.rb index 20b8e7ae8..cbf801e82 100644 --- a/app/controllers/api/v1/profiles_controller.rb +++ b/app/controllers/api/v1/profiles_controller.rb @@ -18,6 +18,10 @@ class Api::V1::ProfilesController < Api::BaseController head :ok end + def auto_offline + @user.account_users.find_by!(account_id: auto_offline_params[:account_id]).update!(auto_offline: auto_offline_params[:auto_offline] || false) + end + def availability @user.account_users.find_by!(account_id: availability_params[:account_id]).update!(availability: availability_params[:availability]) end @@ -37,6 +41,10 @@ class Api::V1::ProfilesController < Api::BaseController params.require(:profile).permit(:account_id, :availability) end + def auto_offline_params + params.require(:profile).permit(:account_id, :auto_offline) + end + def profile_params params.require(:profile).permit( :email, diff --git a/app/javascript/dashboard/api/auth.js b/app/javascript/dashboard/api/auth.js index ef1762f46..19ba40a42 100644 --- a/app/javascript/dashboard/api/auth.js +++ b/app/javascript/dashboard/api/auth.js @@ -144,6 +144,12 @@ export default { }); }, + updateAutoOffline(accountId, autoOffline = false) { + return axios.post(endPoints('autoOffline').url, { + profile: { account_id: accountId, auto_offline: autoOffline }, + }); + }, + deleteAvatar() { return axios.delete(endPoints('deleteAvatar').url); }, diff --git a/app/javascript/dashboard/api/endPoints.js b/app/javascript/dashboard/api/endPoints.js index 8deb8d56a..678386d50 100644 --- a/app/javascript/dashboard/api/endPoints.js +++ b/app/javascript/dashboard/api/endPoints.js @@ -16,6 +16,9 @@ const endPoints = { availabilityUpdate: { url: '/api/v1/profile/availability', }, + autoOffline: { + url: '/api/v1/profile/auto_offline', + }, logout: { url: 'auth/sign_out', }, diff --git a/app/javascript/dashboard/components/layout/AvailabilityStatus.vue b/app/javascript/dashboard/components/layout/AvailabilityStatus.vue index 1c70e6755..0a2698a9a 100644 --- a/app/javascript/dashboard/components/layout/AvailabilityStatus.vue +++ b/app/javascript/dashboard/components/layout/AvailabilityStatus.vue @@ -18,12 +18,35 @@ + +
+ + + + {{ $t('SIDEBAR.SET_AUTO_OFFLINE.TEXT') }} + +
+ + +
+ diff --git a/app/javascript/dashboard/i18n/locale/en/conversation.json b/app/javascript/dashboard/i18n/locale/en/conversation.json index 37cc53c68..efb07d806 100644 --- a/app/javascript/dashboard/i18n/locale/en/conversation.json +++ b/app/javascript/dashboard/i18n/locale/en/conversation.json @@ -41,6 +41,10 @@ "NO_RESPONSE": "No response", "RATING_TITLE": "Rating", "FEEDBACK_TITLE": "Feedback", + "CARD": { + "SHOW_LABELS": "Show labels", + "HIDE_LABELS": "Hide labels" + }, "HEADER": { "RESOLVE_ACTION": "Resolve", "REOPEN_ACTION": "Reopen", diff --git a/app/javascript/dashboard/i18n/locale/en/settings.json b/app/javascript/dashboard/i18n/locale/en/settings.json index f6c6e51c9..25979f659 100644 --- a/app/javascript/dashboard/i18n/locale/en/settings.json +++ b/app/javascript/dashboard/i18n/locale/en/settings.json @@ -99,7 +99,9 @@ }, "AVAILABILITY": { "LABEL": "Availability", - "STATUSES_LIST": ["Online", "Busy", "Offline"] + "STATUSES_LIST": ["Online", "Busy", "Offline"], + "SET_AVAILABILITY_SUCCESS": "Availability has been set successfully", + "SET_AVAILABILITY_ERROR": "Couldn't set availability, please try again" }, "EMAIL": { "LABEL": "Your email address", @@ -222,6 +224,10 @@ "CATEGORY": "Category", "CATEGORY_EMPTY_MESSAGE": "No categories found" }, + "SET_AUTO_OFFLINE": { + "TEXT": "Mark offline automatically", + "INFO_TEXT": "Let the system automatically mark you offline when you aren't using the app or dashboard." + }, "DOCS": "Read docs" }, "BILLING_SETTINGS": { diff --git a/app/javascript/dashboard/routes/dashboard/helpcenter/components/HelpCenterLayout.vue b/app/javascript/dashboard/routes/dashboard/helpcenter/components/HelpCenterLayout.vue index b4626e108..8c806f23b 100644 --- a/app/javascript/dashboard/routes/dashboard/helpcenter/components/HelpCenterLayout.vue +++ b/app/javascript/dashboard/routes/dashboard/helpcenter/components/HelpCenterLayout.vue @@ -40,6 +40,7 @@ :portals="portals" :active-portal-slug="selectedPortalSlug" :active-locale="selectedLocaleInPortal" + @fetch-portal="fetchPortalAndItsCategories" @close-popover="closePortalPopover" /> { - this.$store.dispatch('categories/index', { - portalSlug: this.portal.slug, - }); - }); + async fetchPortalAndItsCategories() { + await this.$store.dispatch('portals/index'); + const { + slug, + config: { allowed_locales: allowedLocales }, + } = this.portal; + const selectedPortalParam = { + portalSlug: slug, + locale: allowedLocales[0].code, + }; + this.$store.dispatch('portals/show', selectedPortalParam); + this.$store.dispatch('categories/index', selectedPortalParam); }, async onClickDeletePortal() { const { slug } = this.selectedPortalForDelete; diff --git a/app/javascript/dashboard/routes/dashboard/helpcenter/components/PortalPopover.vue b/app/javascript/dashboard/routes/dashboard/helpcenter/components/PortalPopover.vue index 67d1b33f1..729c641e7 100644 --- a/app/javascript/dashboard/routes/dashboard/helpcenter/components/PortalPopover.vue +++ b/app/javascript/dashboard/routes/dashboard/helpcenter/components/PortalPopover.vue @@ -36,7 +36,8 @@ :active-portal-slug="activePortalSlug" :active-locale="activeLocale" :active="portal.slug === activePortalSlug" - @open-portal-page="onPortalSelect" + @open-portal-page="closePortalPopover" + @fetch-portal="fetchPortalAndItsCategories" /> @@ -69,15 +70,15 @@ export default { closePortalPopover() { this.$emit('close-popover'); }, - onPortalSelect() { - this.$emit('close-popover'); - }, openPortalPage() { this.closePortalPopover(); this.$router.push({ name: 'list_all_portals', }); }, + fetchPortalAndItsCategories() { + this.$emit('fetch-portal'); + }, }, }; diff --git a/app/javascript/dashboard/routes/dashboard/helpcenter/components/PortalSettingsBasicForm.vue b/app/javascript/dashboard/routes/dashboard/helpcenter/components/PortalSettingsBasicForm.vue index e13c60061..4e430da5d 100644 --- a/app/javascript/dashboard/routes/dashboard/helpcenter/components/PortalSettingsBasicForm.vue +++ b/app/javascript/dashboard/routes/dashboard/helpcenter/components/PortalSettingsBasicForm.vue @@ -16,7 +16,7 @@ {{ $t('HELP_CENTER.PORTAL.ADD.LOGO.LABEL') }}
- +
@@ -91,7 +91,7 @@ export default { currentPortalSlug() { return this.$route.params.portalSlug; }, - categoryByLocaleCode() { + categoriesByLocaleCode() { return this.$store.getters['categories/categoriesByLocaleCode']( this.currentLocaleCode ); @@ -131,6 +131,12 @@ export default { closeEditCategoryModal() { this.showEditCategoryModal = false; }, + async fetchCategoriesByPortalSlugAndLocale(localeCode) { + await this.$store.dispatch('categories/index', { + portalSlug: this.currentPortalSlug, + locale: localeCode, + }); + }, async deleteCategory(categoryId) { try { await this.$store.dispatch('categories/delete', { @@ -152,6 +158,7 @@ export default { changeCurrentCategory(event) { const localeCode = event.target.value; this.currentLocaleCode = localeCode; + this.fetchCategoriesByPortalSlugAndLocale(localeCode); }, }, }; diff --git a/app/javascript/dashboard/store/modules/auth.js b/app/javascript/dashboard/store/modules/auth.js index 17806959b..e19d8d34c 100644 --- a/app/javascript/dashboard/store/modules/auth.js +++ b/app/javascript/dashboard/store/modules/auth.js @@ -48,6 +48,14 @@ export const getters = { return currentAccount.availability; }, + getCurrentUserAutoOffline($state, $getters) { + const { accounts = [] } = $state.currentUser; + const [currentAccount = {}] = accounts.filter( + account => account.id === $getters.getCurrentAccountId + ); + return currentAccount.auto_offline; + }, + getCurrentAccountId(_, __, rootState) { if (rootState.route.params && rootState.route.params.accountId) { return Number(rootState.route.params.accountId); @@ -174,6 +182,15 @@ export const actions = { } }, + updateAutoOffline: async ({ commit }, { accountId, autoOffline }) => { + try { + const response = await authAPI.updateAutoOffline(accountId, autoOffline); + commit(types.SET_CURRENT_USER, response.data); + } catch (error) { + // Ignore error + } + }, + setCurrentUserAvailability({ commit, state: $state }, data) { if (data[$state.currentUser.id]) { commit(types.SET_CURRENT_USER_AVAILABILITY, data[$state.currentUser.id]); diff --git a/app/javascript/dashboard/store/modules/helpCenterArticles/actions.js b/app/javascript/dashboard/store/modules/helpCenterArticles/actions.js index e62901835..3ab840105 100644 --- a/app/javascript/dashboard/store/modules/helpCenterArticles/actions.js +++ b/app/javascript/dashboard/store/modules/helpCenterArticles/actions.js @@ -41,11 +41,11 @@ export const actions = { portalSlug, articleObj, }); - const { id: articleId, portal } = payload; + const { id: articleId } = payload; commit(types.ADD_ARTICLE, payload); commit(types.ADD_ARTICLE_ID, articleId); commit(types.ADD_ARTICLE_FLAG, articleId); - dispatch('portals/updatePortal', portal, { root: true }); + dispatch('portals/updatePortal', portalSlug, { root: true }); return articleId; } catch (error) { return throwErrorMessage(error); diff --git a/app/javascript/dashboard/store/modules/specs/auth/actions.spec.js b/app/javascript/dashboard/store/modules/specs/auth/actions.spec.js index 6c1c85996..c933333be 100644 --- a/app/javascript/dashboard/store/modules/specs/auth/actions.spec.js +++ b/app/javascript/dashboard/store/modules/specs/auth/actions.spec.js @@ -88,6 +88,38 @@ describe('#actions', () => { }); }); + describe('#updateAutoOffline', () => { + it('sends correct actions if API is success', async () => { + axios.post.mockResolvedValue({ + data: { + id: 1, + name: 'John', + accounts: [ + { + account_id: 1, + auto_offline: false, + }, + ], + }, + headers: { expiry: 581842904 }, + }); + await actions.updateAutoOffline( + { commit, dispatch }, + { autoOffline: false, accountId: 1 } + ); + expect(commit.mock.calls).toEqual([ + [ + types.default.SET_CURRENT_USER, + { + id: 1, + name: 'John', + accounts: [{ account_id: 1, auto_offline: false }], + }, + ], + ]); + }); + }); + describe('#updateUISettings', () => { it('sends correct actions if API is success', async () => { axios.put.mockResolvedValue({ diff --git a/app/javascript/shared/components/ui/dropdown/DropdownHeader.vue b/app/javascript/shared/components/ui/dropdown/DropdownHeader.vue index d96865abd..c3719ada4 100644 --- a/app/javascript/shared/components/ui/dropdown/DropdownHeader.vue +++ b/app/javascript/shared/components/ui/dropdown/DropdownHeader.vue @@ -1,6 +1,7 @@