diff --git a/app/controllers/api/v1/widget/contacts_controller.rb b/app/controllers/api/v1/widget/contacts_controller.rb index ad818d7ac..135d2ced3 100644 --- a/app/controllers/api/v1/widget/contacts_controller.rb +++ b/app/controllers/api/v1/widget/contacts_controller.rb @@ -1,6 +1,9 @@ class Api::V1::Widget::ContactsController < Api::V1::Widget::BaseController + before_action :process_hmac + + def show; end + def update - process_hmac contact_identify_action = ContactIdentifyAction.new( contact: @contact, params: permitted_params.to_h.deep_symbolize_keys diff --git a/app/javascript/dashboard/assets/scss/_animations.scss b/app/javascript/dashboard/assets/scss/_animations.scss index 144c9fc74..3a26d5bf2 100644 --- a/app/javascript/dashboard/assets/scss/_animations.scss +++ b/app/javascript/dashboard/assets/scss/_animations.scss @@ -54,8 +54,10 @@ opacity: 0; } -.menu-slide-enter-active, .menu-slide-leave-active { - transition: all .15s $ease-in-cubic; +.menu-slide-enter-active, +.menu-slide-leave-active { + transform: translateY(0); + transition: transform 0.25s $ease-in-cubic, opacity 0.15s $ease-in-cubic; } .menu-slide-enter, .menu-slide-leave-to diff --git a/app/javascript/dashboard/assets/scss/plugins/_dropdown.scss b/app/javascript/dashboard/assets/scss/plugins/_dropdown.scss index b4dada351..9f70dec13 100644 --- a/app/javascript/dashboard/assets/scss/plugins/_dropdown.scss +++ b/app/javascript/dashboard/assets/scss/plugins/_dropdown.scss @@ -1,27 +1,42 @@ -.dropdown-pane.sleek { +.dropdown-pane { @include elegant-card; @include border-light; - padding-left: 0; - padding-right: 0; - right: -12px; - top: 48px; - width: auto; + z-index: 999; - &::before { - @include arrow(top, var(--color-border-light), 14px); - position: absolute; - right: 6px; - top: -14px; + &.dropdown-pane--open { + display: block; + visibility: visible; } - &::after { - @include arrow(top, $color-white, var(--space-slab)); - position: absolute; - right: var(--space-small); - top: -12px; + &.dropdowm--bottom { + &::before { + @include arrow(top, var(--color-border-light), 14px); + position: absolute; + right: 6px; + top: -14px; + } + + &::after { + @include arrow(top, $color-white, var(--space-slab)); + position: absolute; + right: var(--space-small); + top: -12px; + } } - .dropdown>li>a:hover { - background: var(--color-background); + &.dropdowm--top { + &::before { + @include arrow(bottom, var(--color-border-light), 14px); + bottom: -14px; + position: absolute; + right: 6px; + } + + &::after { + @include arrow(bottom, $color-white, var(--space-slab)); + bottom: -12px; + position: absolute; + right: var(--space-small); + } } } diff --git a/app/javascript/dashboard/assets/scss/widgets/_sidemenu.scss b/app/javascript/dashboard/assets/scss/widgets/_sidemenu.scss index 65abd09c7..099d32287 100644 --- a/app/javascript/dashboard/assets/scss/widgets/_sidemenu.scss +++ b/app/javascript/dashboard/assets/scss/widgets/_sidemenu.scss @@ -68,21 +68,11 @@ position: relative; .dropdown-pane { - @include elegant-card; - @include border-light; bottom: 6rem; display: block; left: 5rem; visibility: visible; width: 80%; - z-index: 999; - - &::before { - @include arrow(bottom, $color-white, $space-slab); - bottom: -$space-slab; - position: absolute; - right: $space-slab; - } } .active { diff --git a/app/javascript/dashboard/components/ChatList.vue b/app/javascript/dashboard/components/ChatList.vue index 6603a25c6..a21fb15a7 100644 --- a/app/javascript/dashboard/components/ChatList.vue +++ b/app/javascript/dashboard/components/ChatList.vue @@ -25,6 +25,7 @@ v-for="chat in conversationList" :key="chat.id" :active-label="label" + :team-id="teamId" :chat="chat" /> @@ -76,14 +77,14 @@ export default { type: [String, Number], default: 0, }, + teamId: { + type: [String, Number], + default: 0, + }, label: { type: String, default: '', }, - activeTeam: { - type: Object, - default: () => {}, - }, }, data() { return { @@ -132,7 +133,7 @@ export default { status: this.activeStatus, page: this.currentPage + 1, labels: this.label ? [this.label] : undefined, - teamId: this.activeTeam.name ? this.activeTeam.id : undefined, + teamId: this.teamId ? this.teamId : undefined, }; }, pageTitle() { @@ -149,24 +150,22 @@ export default { }, conversationList() { let conversationList = []; + const filters = this.conversationFilters; if (this.activeAssigneeTab === 'me') { - conversationList = this.mineChatsList.slice(); + conversationList = [...this.mineChatsList(filters)]; } else if (this.activeAssigneeTab === 'unassigned') { - conversationList = this.unAssignedChatsList.slice(); + conversationList = [...this.unAssignedChatsList(filters)]; } else { - conversationList = this.allChatList.slice(); + conversationList = [...this.allChatList(filters)]; } - if (!this.label) { - return conversationList; + return conversationList; + }, + activeTeam() { + if (this.teamId) { + return this.$store.getters['teams/getTeam'](this.teamId); } - - return conversationList.filter(conversation => { - const labels = this.$store.getters[ - 'conversationLabels/getConversationLabels' - ](conversation.id); - return labels.includes(this.label); - }); + return {}; }, }, watch: { diff --git a/app/javascript/dashboard/components/layout/AvailabilityStatus.vue b/app/javascript/dashboard/components/layout/AvailabilityStatus.vue index d19e3ba0e..469129339 100644 --- a/app/javascript/dashboard/components/layout/AvailabilityStatus.vue +++ b/app/javascript/dashboard/components/layout/AvailabilityStatus.vue @@ -15,25 +15,24 @@ @@ -47,9 +46,17 @@ + diff --git a/app/javascript/shared/components/ui/dropdown/DropdownMenu.vue b/app/javascript/shared/components/ui/dropdown/DropdownMenu.vue new file mode 100644 index 000000000..12a485151 --- /dev/null +++ b/app/javascript/shared/components/ui/dropdown/DropdownMenu.vue @@ -0,0 +1,21 @@ + + diff --git a/app/javascript/widget/App.vue b/app/javascript/widget/App.vue index 48e89096d..e0e08911c 100755 --- a/app/javascript/widget/App.vue +++ b/app/javascript/widget/App.vue @@ -150,6 +150,7 @@ export default { this.setPopoutDisplay(message.showPopoutButton); this.fetchAvailableAgents(websiteToken); this.setHideMessageBubble(message.hideMessageBubble); + this.$store.dispatch('contacts/get'); } else if (message.event === 'widget-visible') { this.scrollConversationToBottom(); } else if (message.event === 'set-current-url') { diff --git a/app/javascript/widget/api/contacts.js b/app/javascript/widget/api/contacts.js index a72bb4910..a246e6dc2 100644 --- a/app/javascript/widget/api/contacts.js +++ b/app/javascript/widget/api/contacts.js @@ -3,6 +3,9 @@ import { API } from 'widget/helpers/axios'; const buildUrl = endPoint => `/api/v1/${endPoint}${window.location.search}`; export default { + get() { + return API.get(buildUrl('widget/contact')); + }, update(identifier, userObject) { return API.patch(buildUrl('widget/contact'), { identifier, diff --git a/app/javascript/widget/store/modules/contacts.js b/app/javascript/widget/store/modules/contacts.js index 0ecae3a55..582b78414 100644 --- a/app/javascript/widget/store/modules/contacts.js +++ b/app/javascript/widget/store/modules/contacts.js @@ -1,7 +1,27 @@ import ContactsAPI from '../../api/contacts'; import { refreshActionCableConnector } from '../../helpers/actionCable'; +const state = { + currentUser: {}, +}; + +const SET_CURRENT_USER = 'SET_CURRENT_USER'; + +export const getters = { + getCurrentUser(_state) { + return _state.currentUser; + }, +}; + export const actions = { + get: async ({ commit }) => { + try { + const { data } = await ContactsAPI.get(); + commit(SET_CURRENT_USER, data); + } catch (error) { + // Ignore error + } + }, update: async ({ dispatch }, { identifier, user: userObject }) => { try { const user = { @@ -14,6 +34,7 @@ export const actions = { data: { pubsub_token: pubsubToken }, } = await ContactsAPI.update(identifier, user); + dispatch('get'); if (userObject.identifier_hash) { dispatch('conversation/clearConversations', {}, { root: true }); dispatch('conversation/fetchOldConversations', {}, { root: true }); @@ -33,10 +54,17 @@ export const actions = { }, }; +export const mutations = { + [SET_CURRENT_USER]($state, user) { + const { currentUser } = $state; + $state.currentUser = { ...currentUser, ...user }; + }, +}; + export default { namespaced: true, - state: {}, - getters: {}, + state, + getters, actions, - mutations: {}, + mutations, }; diff --git a/app/javascript/widget/store/modules/specs/contact/actions.spec.js b/app/javascript/widget/store/modules/specs/contact/actions.spec.js new file mode 100644 index 000000000..c16b0eb20 --- /dev/null +++ b/app/javascript/widget/store/modules/specs/contact/actions.spec.js @@ -0,0 +1,21 @@ +import { API } from 'widget/helpers/axios'; +import { actions } from '../../contacts'; + +const commit = jest.fn(); +jest.mock('widget/helpers/axios'); + +describe('#actions', () => { + describe('#update', () => { + it('sends correct actions', async () => { + const user = { + email: 'thoma@sphadikam.com', + name: 'Adu Thoma', + avatar_url: '', + identifier_hash: 'malana_hash', + }; + API.patch.mockResolvedValue({ data: { pubsub_token: 'token' } }); + await actions.update({ commit }, { identifier: 1, user }); + expect(commit.mock.calls).toEqual([]); + }); + }); +}); diff --git a/app/javascript/widget/store/modules/specs/contact/getters.spec.js b/app/javascript/widget/store/modules/specs/contact/getters.spec.js new file mode 100644 index 000000000..43b0f15d7 --- /dev/null +++ b/app/javascript/widget/store/modules/specs/contact/getters.spec.js @@ -0,0 +1,21 @@ +import { getters } from '../../contacts'; + +describe('#getters', () => { + it('getCurrentUser', () => { + const user = { + email: 'thoma@sphadikam.com', + name: 'Adu Thoma', + avatar_url: '', + identifier_hash: 'malana_hash', + }; + const state = { + currentUser: user, + }; + expect(getters.getCurrentUser(state)).toEqual({ + email: 'thoma@sphadikam.com', + name: 'Adu Thoma', + avatar_url: '', + identifier_hash: 'malana_hash', + }); + }); +}); diff --git a/app/javascript/widget/store/modules/specs/contact/mutations.spec.js b/app/javascript/widget/store/modules/specs/contact/mutations.spec.js new file mode 100644 index 000000000..fed202bf2 --- /dev/null +++ b/app/javascript/widget/store/modules/specs/contact/mutations.spec.js @@ -0,0 +1,17 @@ +import { mutations } from '../../contacts'; + +describe('#mutations', () => { + describe('#SET_CURRENT_USER', () => { + it('set current user', () => { + const user = { + email: 'thoma@sphadikam.com', + name: 'Adu Thoma', + avatar_url: '', + identifier_hash: 'malana_hash', + }; + const state = { currentUser: {} }; + mutations.SET_CURRENT_USER(state, user); + expect(state.currentUser).toEqual(user); + }); + }); +}); diff --git a/app/javascript/widget/views/Home.vue b/app/javascript/widget/views/Home.vue index 9753c5cd2..32f784ec7 100755 --- a/app/javascript/widget/views/Home.vue +++ b/app/javascript/widget/views/Home.vue @@ -114,13 +114,15 @@ export default { conversationSize: 'conversation/getConversationSize', groupedMessages: 'conversation/getGroupedConversation', isFetchingList: 'conversation/getIsFetchingList', + currentUser: 'contacts/getCurrentUser', }), currentView() { + const { email: currentUserEmail = '' } = this.currentUser; if (this.isHeaderCollapsed) { if (this.conversationSize) { return 'messageView'; } - if (this.preChatFormEnabled) { + if (this.preChatFormEnabled && !currentUserEmail) { return 'preChatFormView'; } return 'messageView'; diff --git a/app/views/api/v1/widget/contacts/show.json.jbuilder b/app/views/api/v1/widget/contacts/show.json.jbuilder new file mode 100644 index 000000000..9853ccbee --- /dev/null +++ b/app/views/api/v1/widget/contacts/show.json.jbuilder @@ -0,0 +1,3 @@ +json.id @contact.id +json.name @contact.name +json.email @contact.email diff --git a/config/app.yml b/config/app.yml index 1d82a9db3..7164aff76 100644 --- a/config/app.yml +++ b/config/app.yml @@ -1,5 +1,5 @@ shared: &shared - version: '1.14.0' + version: '1.14.1' development: <<: *shared diff --git a/config/initializers/mailer.rb b/config/initializers/mailer.rb index 2ed599105..54a22f0dc 100644 --- a/config/initializers/mailer.rb +++ b/config/initializers/mailer.rb @@ -13,16 +13,16 @@ Rails.application.configure do # Config related to smtp smtp_settings = { - domain: ENV.fetch('SMTP_DOMAIN', ''), address: ENV.fetch('SMTP_ADDRESS', 'localhost'), port: ENV.fetch('SMTP_PORT', 587) } - smtp_settings[:authentication] = ENV.fetch('SMTP_AUTHENTICATION', 'login').to_sym if ENV.fetch('SMTP_AUTHENTICATION', '').present? + smtp_settings[:authentication] = ENV.fetch('SMTP_AUTHENTICATION', 'login').to_sym if ENV['SMTP_AUTHENTICATION'].present? + smtp_settings[:domain] = ENV['SMTP_DOMAIN'] if ENV['SMTP_DOMAIN'].present? smtp_settings[:user_name] = ENV['SMTP_USERNAME'] smtp_settings[:password] = ENV['SMTP_PASSWORD'] smtp_settings[:enable_starttls_auto] = ActiveModel::Type::Boolean.new.cast(ENV.fetch('SMTP_ENABLE_STARTTLS_AUTO', true)) - smtp_settings[:openssl_verify_mode] = ENV.fetch('SMTP_OPENSSL_VERIFY_MODE', 'peer') + smtp_settings[:openssl_verify_mode] = ENV['SMTP_OPENSSL_VERIFY_MODE'] if ENV['SMTP_OPENSSL_VERIFY_MODE'].present? smtp_settings[:ssl] = ActiveModel::Type::Boolean.new.cast(ENV.fetch('SMTP_SSL', true)) if ENV['SMTP_SSL'] smtp_settings[:tls] = ActiveModel::Type::Boolean.new.cast(ENV.fetch('SMTP_TLS', true)) if ENV['SMTP_TLS'] diff --git a/config/routes.rb b/config/routes.rb index d5e1162fa..cedb58a12 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -150,7 +150,7 @@ Rails.application.routes.draw do post :transcript end end - resource :contact, only: [:update] + resource :contact, only: [:show, :update] resources :inbox_members, only: [:index] resources :labels, only: [:create, :destroy] end diff --git a/package.json b/package.json index 8257a2b8c..52174feed 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@chatwoot/chatwoot", - "version": "1.14.0", + "version": "1.14.1", "license": "MIT", "scripts": { "eslint": "eslint app/javascript --fix",