@@ -1,9 +1,17 @@
|
||||
<template>
|
||||
<div class="medium-3 bg-white contact--panel">
|
||||
<span class="close-button" @click="onClose">
|
||||
<div
|
||||
class="small-12 medium-3 bg-white contact--panel"
|
||||
:class="{ 'border-left': showAvatar }"
|
||||
>
|
||||
<span v-if="showAvatar" class="close-button" @click="onClose">
|
||||
<i class="ion-android-close close-icon" />
|
||||
</span>
|
||||
<contact-info show-new-message :contact="contact" @panel-close="onClose" />
|
||||
<contact-info
|
||||
:show-avatar="showAvatar"
|
||||
show-new-message
|
||||
:contact="contact"
|
||||
@panel-close="onClose"
|
||||
/>
|
||||
<accordion-item
|
||||
:title="$t('CONTACT_PANEL.SIDEBAR_SECTIONS.CUSTOM_ATTRIBUTES')"
|
||||
:is-open="isContactSidebarItemOpen('is_ct_custom_attr_open')"
|
||||
@@ -61,6 +69,10 @@ export default {
|
||||
type: Function,
|
||||
default: () => {},
|
||||
},
|
||||
showAvatar: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
hasContactAttributes() {
|
||||
@@ -85,7 +97,7 @@ export default {
|
||||
overflow-y: auto;
|
||||
overflow: auto;
|
||||
position: relative;
|
||||
border-left: 1px solid var(--color-border);
|
||||
border-right: 1px solid var(--color-border);
|
||||
}
|
||||
|
||||
.close-button {
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
<script>
|
||||
import { mixin as clickaway } from 'vue-clickaway';
|
||||
import { VeTable } from 'vue-easytable';
|
||||
import flag from 'country-code-emoji';
|
||||
|
||||
import Spinner from 'shared/components/Spinner.vue';
|
||||
import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue';
|
||||
@@ -94,10 +95,10 @@ export default {
|
||||
...item,
|
||||
phone_number: item.phone_number || '---',
|
||||
company: additional.company_name || '---',
|
||||
location: additional.location || '---',
|
||||
profiles: additional.social_profiles || {},
|
||||
city: additional.city || '---',
|
||||
country: additional.country || '---',
|
||||
country: additional.country,
|
||||
countryCode: additional.country_code,
|
||||
conversationsCount: item.conversations_count || '---',
|
||||
last_activity_at: lastActivityAt
|
||||
? this.dynamicTime(lastActivityAt)
|
||||
@@ -128,12 +129,17 @@ export default {
|
||||
status={row.availability_status}
|
||||
/>
|
||||
<div class="user-block">
|
||||
<h6 class="sub-block-title user-name text-truncate">
|
||||
{row.name}
|
||||
<h6 class="sub-block-title text-truncate">
|
||||
<router-link
|
||||
to={`/app/accounts/${this.$route.params.accountId}/contacts/${row.id}`}
|
||||
class="user-name"
|
||||
>
|
||||
{row.name}
|
||||
</router-link>
|
||||
</h6>
|
||||
<span class="button clear small link">
|
||||
<button class="button clear small link view-details--button">
|
||||
{this.$t('CONTACTS_PAGE.LIST.VIEW_DETAILS')}
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</woot-button>
|
||||
@@ -186,6 +192,16 @@ export default {
|
||||
key: 'country',
|
||||
title: this.$t('CONTACTS_PAGE.LIST.TABLE_HEADER.COUNTRY'),
|
||||
align: 'left',
|
||||
renderBodyCell: ({ row }) => {
|
||||
if (row.country) {
|
||||
return (
|
||||
<div class="text-truncate">
|
||||
{`${flag(row.countryCode)} ${row.country}`}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return '---';
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'profiles',
|
||||
@@ -281,10 +297,15 @@ export default {
|
||||
|
||||
.user-name {
|
||||
font-size: var(--font-size-small);
|
||||
font-weight: var(--font-weight-medium);
|
||||
margin: 0;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.view-details--button {
|
||||
color: var(--color-body);
|
||||
}
|
||||
|
||||
.user-email {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@@ -1,81 +1,136 @@
|
||||
<template>
|
||||
<div class="contact-manage-view">
|
||||
<contacts-header
|
||||
:search-query="searchQuery"
|
||||
:on-search-submit="onSearchSubmit"
|
||||
:on-input-search="onInputSearch"
|
||||
:on-toggle-create="onToggleCreate"
|
||||
/>
|
||||
<manage-layout :contact-id="contactId" />
|
||||
<div class="view-box columns bg-white">
|
||||
<settings-header
|
||||
button-route="new"
|
||||
:header-title="contact.name"
|
||||
show-back-button
|
||||
:back-button-label="$t('CONTACT_PROFILE.BACK_BUTTON')"
|
||||
:back-url="backUrl"
|
||||
:show-new-button="false"
|
||||
>
|
||||
<thumbnail
|
||||
v-if="contact.thumbnail"
|
||||
:src="contact.thumbnail"
|
||||
:username="contact.name"
|
||||
size="32px"
|
||||
class="margin-right-small"
|
||||
/>
|
||||
</settings-header>
|
||||
|
||||
<create-contact :show="showCreateModal" @cancel="onToggleCreate" />
|
||||
<div
|
||||
v-if="uiFlags.isFetchingItem"
|
||||
class="text-center p-normal fs-default h-full"
|
||||
>
|
||||
<spinner size="" />
|
||||
<span>{{ $t('CONTACT_PROFILE.LOADING') }}</span>
|
||||
</div>
|
||||
<div
|
||||
v-else-if="contact.id"
|
||||
class="overflow-hidden column contact--dashboard-content"
|
||||
>
|
||||
<div class="row h-full">
|
||||
<contact-info-panel :show-avatar="false" :contact="contact" />
|
||||
<div class="small-12 medium-9 h-full">
|
||||
<woot-tabs :index="selectedTabIndex" @change="onClickTabChange">
|
||||
<woot-tabs-item
|
||||
v-for="tab in tabs"
|
||||
:key="tab.key"
|
||||
:name="tab.name"
|
||||
:show-badge="false"
|
||||
/>
|
||||
</woot-tabs>
|
||||
<div class="tab-content overflow-auto">
|
||||
<contact-notes
|
||||
v-if="selectedTabIndex === 0"
|
||||
:contact-id="Number(contactId)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import ContactsHeader from '../components/Header';
|
||||
import ManageLayout from 'dashboard/modules/contact/components/ManageLayout';
|
||||
import CreateContact from 'dashboard/routes/dashboard/conversation/contact/CreateContact';
|
||||
import ContactInfoPanel from '../components/ContactInfoPanel.vue';
|
||||
import ContactNotes from 'dashboard/modules/notes/NotesOnContactPage';
|
||||
import SettingsHeader from '../../settings/SettingsHeader.vue';
|
||||
import Spinner from 'shared/components/Spinner';
|
||||
import Thumbnail from 'dashboard/components/widgets/Thumbnail';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ContactsHeader,
|
||||
CreateContact,
|
||||
ManageLayout,
|
||||
ContactInfoPanel,
|
||||
ContactNotes,
|
||||
SettingsHeader,
|
||||
Spinner,
|
||||
Thumbnail,
|
||||
},
|
||||
props: {
|
||||
contactId: {
|
||||
type: [String, Number],
|
||||
default: 0,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
searchQuery: '',
|
||||
showCreateModal: false,
|
||||
selectedTabIndex: 0,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
uiFlags: 'contacts/getUIFlags',
|
||||
}),
|
||||
tabs() {
|
||||
return [
|
||||
{
|
||||
key: 0,
|
||||
name: this.$t('NOTES.HEADER.TITLE'),
|
||||
},
|
||||
];
|
||||
},
|
||||
showEmptySearchResult() {
|
||||
const hasEmptyResults = !!this.searchQuery && this.records.length === 0;
|
||||
return hasEmptyResults;
|
||||
},
|
||||
contact() {
|
||||
return this.$store.getters['contacts/getContact'](this.contactId);
|
||||
},
|
||||
backUrl() {
|
||||
return `/app/accounts/${this.$route.params.accountId}/contacts`;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.fetchContactDetails();
|
||||
},
|
||||
mounted() {},
|
||||
methods: {
|
||||
onInputSearch(event) {
|
||||
const newQuery = event.target.value;
|
||||
const refetchAllContacts = !!this.searchQuery && newQuery === '';
|
||||
if (refetchAllContacts) {
|
||||
this.$store.dispatch('contacts/get', { page: 1 });
|
||||
}
|
||||
this.searchQuery = newQuery;
|
||||
onClickTabChange(index) {
|
||||
this.selectedTabIndex = index;
|
||||
},
|
||||
onSearchSubmit() {
|
||||
this.selectedContactId = '';
|
||||
if (this.searchQuery) {
|
||||
this.$store.dispatch('contacts/search', {
|
||||
search: this.searchQuery,
|
||||
page: 1,
|
||||
});
|
||||
}
|
||||
},
|
||||
onToggleCreate() {
|
||||
this.showCreateModal = !this.showCreateModal;
|
||||
fetchContactDetails() {
|
||||
const { contactId: id } = this;
|
||||
this.$store.dispatch('contacts/show', { id });
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.contact-manage-view {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
flex: 1 1 0;
|
||||
@import '~dashboard/assets/scss/mixins';
|
||||
|
||||
.left {
|
||||
border-right: 1px solid var(--color-border);
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.right {
|
||||
padding: var(--space-normal);
|
||||
}
|
||||
|
||||
.tab-content {
|
||||
background: var(--color-background-light);
|
||||
height: calc(100% - 40px);
|
||||
padding: var(--space-normal);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -21,7 +21,7 @@ export const routes = [
|
||||
},
|
||||
{
|
||||
path: frontendURL('accounts/:accountId/contacts/:contactId'),
|
||||
name: 'contacts_dashboard_manage',
|
||||
name: 'contact_profile_dashboard',
|
||||
roles: ['administrator', 'agent'],
|
||||
component: ContactManageView,
|
||||
props: route => {
|
||||
|
||||
@@ -222,9 +222,8 @@ export default {
|
||||
return this.additionalAttributes.initiated_at;
|
||||
},
|
||||
browserName() {
|
||||
return `${this.browser.browser_name || ''} ${
|
||||
this.browser.browser_version || ''
|
||||
}`;
|
||||
return `${this.browser.browser_name || ''} ${this.browser
|
||||
.browser_version || ''}`;
|
||||
},
|
||||
contactAdditionalAttributes() {
|
||||
return this.contact.additional_attributes || {};
|
||||
@@ -248,8 +247,10 @@ export default {
|
||||
return `${cityAndCountry} ${countryFlag}`;
|
||||
},
|
||||
platformName() {
|
||||
const { platform_name: platformName, platform_version: platformVersion } =
|
||||
this.browser;
|
||||
const {
|
||||
platform_name: platformName,
|
||||
platform_version: platformVersion,
|
||||
} = this.browser;
|
||||
return `${platformName || ''} ${platformVersion || ''}`;
|
||||
},
|
||||
channelType() {
|
||||
@@ -403,7 +404,7 @@ export default {
|
||||
::v-deep {
|
||||
.contact--profile {
|
||||
padding-bottom: var(--space-slab);
|
||||
border-bottom: 1px solid var(--color-border-light);
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
}
|
||||
.conversation--actions .multiselect-wrap--small {
|
||||
.multiselect {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
<div class="contact--profile">
|
||||
<div class="contact--info">
|
||||
<thumbnail
|
||||
v-if="showAvatar"
|
||||
:src="contact.thumbnail"
|
||||
size="56px"
|
||||
:username="contact.name"
|
||||
@@ -9,8 +10,16 @@
|
||||
/>
|
||||
|
||||
<div class="contact--details">
|
||||
<h3 class="sub-block-title contact--name">
|
||||
{{ contact.name }}
|
||||
<h3 v-if="showAvatar" class="sub-block-title contact--name">
|
||||
<a
|
||||
:href="contactProfileLink"
|
||||
class="fs-default"
|
||||
target="_blank"
|
||||
rel="noopener nofollow noreferrer"
|
||||
>
|
||||
{{ contact.name }}
|
||||
<i class="ion-android-open open-link--icon" />
|
||||
</a>
|
||||
</h3>
|
||||
<p v-if="additionalAttributes.description" class="contact--bio">
|
||||
{{ additionalAttributes.description }}
|
||||
@@ -25,7 +34,6 @@
|
||||
:title="$t('CONTACT_PANEL.EMAIL_ADDRESS')"
|
||||
show-copy
|
||||
/>
|
||||
|
||||
<contact-info-row
|
||||
:href="contact.phone_number ? `tel:${contact.phone_number}` : ''"
|
||||
:value="contact.phone_number"
|
||||
@@ -161,6 +169,10 @@ export default {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
showAvatar: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -172,6 +184,9 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({ uiFlags: 'contacts/getUIFlags' }),
|
||||
contactProfileLink() {
|
||||
return `/app/accounts/${this.$route.params.accountId}/contacts/${this.contact.id}`;
|
||||
},
|
||||
additionalAttributes() {
|
||||
return this.contact.additional_attributes || {};
|
||||
},
|
||||
@@ -266,6 +281,16 @@ export default {
|
||||
.contact--name {
|
||||
text-transform: capitalize;
|
||||
white-space: normal;
|
||||
|
||||
a {
|
||||
color: var(--color-body);
|
||||
}
|
||||
|
||||
.open-link--icon {
|
||||
color: var(--color-body);
|
||||
font-size: var(--font-size-small);
|
||||
margin-left: var(--space-smaller);
|
||||
}
|
||||
}
|
||||
|
||||
.contact--metadata {
|
||||
|
||||
@@ -2,8 +2,13 @@
|
||||
<div class="settings-header">
|
||||
<h1 class="page-title">
|
||||
<woot-sidemenu-icon></woot-sidemenu-icon>
|
||||
<back-button v-if="showBackButton" :back-url="backUrl"></back-button>
|
||||
<i :class="iconClass"></i>
|
||||
<back-button
|
||||
v-if="showBackButton"
|
||||
:button-label="backButtonLabel"
|
||||
:back-url="backUrl"
|
||||
/>
|
||||
<i v-if="icon" :class="iconClass"></i>
|
||||
<slot></slot>
|
||||
<span>{{ headerTitle }}</span>
|
||||
</h1>
|
||||
<router-link
|
||||
@@ -51,6 +56,10 @@ export default {
|
||||
type: [String, Object],
|
||||
default: '',
|
||||
},
|
||||
backButtonLabel: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
|
||||
Reference in New Issue
Block a user