chore: Improve location display in sidebar (#1509)
- Log IP Address on widget load - Save country code to contact
This commit is contained in:
@@ -35,7 +35,6 @@ class Api::V1::Accounts::ContactsController < Api::V1::Accounts::BaseController
|
|||||||
def create
|
def create
|
||||||
ActiveRecord::Base.transaction do
|
ActiveRecord::Base.transaction do
|
||||||
@contact = Current.account.contacts.new(contact_params)
|
@contact = Current.account.contacts.new(contact_params)
|
||||||
set_ip
|
|
||||||
@contact.save!
|
@contact.save!
|
||||||
@contact_inbox = build_contact_inbox
|
@contact_inbox = build_contact_inbox
|
||||||
end
|
end
|
||||||
@@ -43,7 +42,6 @@ class Api::V1::Accounts::ContactsController < Api::V1::Accounts::BaseController
|
|||||||
|
|
||||||
def update
|
def update
|
||||||
@contact.assign_attributes(contact_update_params)
|
@contact.assign_attributes(contact_update_params)
|
||||||
set_ip
|
|
||||||
@contact.save!
|
@contact.save!
|
||||||
rescue ActiveRecord::RecordInvalid => e
|
rescue ActiveRecord::RecordInvalid => e
|
||||||
render json: {
|
render json: {
|
||||||
@@ -99,11 +97,4 @@ class Api::V1::Accounts::ContactsController < Api::V1::Accounts::BaseController
|
|||||||
def fetch_contact
|
def fetch_contact
|
||||||
@contact = Current.account.contacts.includes(contact_inboxes: [:inbox]).find(params[:id])
|
@contact = Current.account.contacts.includes(contact_inboxes: [:inbox]).find(params[:id])
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_ip
|
|
||||||
return if @contact.account.feature_enabled?('ip_lookup')
|
|
||||||
|
|
||||||
@contact[:additional_attributes][:created_at_ip] ||= request.remote_ip
|
|
||||||
@contact[:additional_attributes][:updated_at_ip] = request.remote_ip
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -41,13 +41,21 @@ class WidgetsController < ActionController::Base
|
|||||||
def build_contact
|
def build_contact
|
||||||
return if @contact.present?
|
return if @contact.present?
|
||||||
|
|
||||||
contact_inbox = @web_widget.create_contact_inbox
|
contact_inbox = @web_widget.create_contact_inbox(additional_attributes)
|
||||||
@contact = contact_inbox.contact
|
@contact = contact_inbox.contact
|
||||||
|
|
||||||
payload = { source_id: contact_inbox.source_id, inbox_id: @web_widget.inbox.id }
|
payload = { source_id: contact_inbox.source_id, inbox_id: @web_widget.inbox.id }
|
||||||
@token = ::Widget::TokenService.new(payload: payload).generate_token
|
@token = ::Widget::TokenService.new(payload: payload).generate_token
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def additional_attributes
|
||||||
|
if @web_widget.inbox.account.feature_enabled?('ip_lookup')
|
||||||
|
{ created_at_ip: request.remote_ip }
|
||||||
|
else
|
||||||
|
{}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def permitted_params
|
def permitted_params
|
||||||
params.permit(:website_token, :cw_conversation)
|
params.permit(:website_token, :cw_conversation)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -5,6 +5,12 @@
|
|||||||
</span>
|
</span>
|
||||||
<contact-info :contact="contact" :channel-type="channelType" />
|
<contact-info :contact="contact" :channel-type="channelType" />
|
||||||
<div v-if="browser.browser_name" class="conversation--details">
|
<div v-if="browser.browser_name" class="conversation--details">
|
||||||
|
<contact-details-item
|
||||||
|
v-if="location"
|
||||||
|
:title="$t('EDIT_CONTACT.FORM.LOCATION.LABEL')"
|
||||||
|
:value="location"
|
||||||
|
icon="ion-map"
|
||||||
|
/>
|
||||||
<contact-details-item
|
<contact-details-item
|
||||||
v-if="browser.browser_name"
|
v-if="browser.browser_name"
|
||||||
:title="$t('CONTACT_PANEL.BROWSER')"
|
:title="$t('CONTACT_PANEL.BROWSER')"
|
||||||
@@ -51,6 +57,7 @@ import ContactDetailsItem from './ContactDetailsItem.vue';
|
|||||||
import ContactInfo from './contact/ContactInfo';
|
import ContactInfo from './contact/ContactInfo';
|
||||||
import ConversationLabels from './labels/LabelBox.vue';
|
import ConversationLabels from './labels/LabelBox.vue';
|
||||||
import ContactCustomAttributes from './ContactCustomAttributes';
|
import ContactCustomAttributes from './ContactCustomAttributes';
|
||||||
|
import flag from 'country-code-emoji';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
@@ -99,6 +106,22 @@ export default {
|
|||||||
return `${this.browser.browser_name || ''} ${this.browser
|
return `${this.browser.browser_name || ''} ${this.browser
|
||||||
.browser_version || ''}`;
|
.browser_version || ''}`;
|
||||||
},
|
},
|
||||||
|
location() {
|
||||||
|
const {
|
||||||
|
additional_attributes: {
|
||||||
|
country = '',
|
||||||
|
city = '',
|
||||||
|
country_code: countryCode,
|
||||||
|
},
|
||||||
|
} = this.contact;
|
||||||
|
const cityAndCountry = [city, country].filter(item => !!item).join(', ');
|
||||||
|
|
||||||
|
if (!cityAndCountry) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
const countryFlag = countryCode ? flag(countryCode) : '🌎';
|
||||||
|
return `${countryFlag} ${cityAndCountry}`;
|
||||||
|
},
|
||||||
platformName() {
|
platformName() {
|
||||||
const {
|
const {
|
||||||
platform_name: platformName,
|
platform_name: platformName,
|
||||||
|
|||||||
@@ -13,8 +13,8 @@
|
|||||||
<div class="contact--name">
|
<div class="contact--name">
|
||||||
{{ contact.name }}
|
{{ contact.name }}
|
||||||
</div>
|
</div>
|
||||||
<div v-if="additionalAttibutes.description" class="contact--bio">
|
<div v-if="additionalAttributes.description" class="contact--bio">
|
||||||
{{ additionalAttibutes.description }}
|
{{ additionalAttributes.description }}
|
||||||
</div>
|
</div>
|
||||||
<social-icons :social-profiles="socialProfiles" />
|
<social-icons :social-profiles="socialProfiles" />
|
||||||
<div class="contact--metadata">
|
<div class="contact--metadata">
|
||||||
@@ -33,12 +33,13 @@
|
|||||||
:title="$t('CONTACT_PANEL.PHONE_NUMBER')"
|
:title="$t('CONTACT_PANEL.PHONE_NUMBER')"
|
||||||
/>
|
/>
|
||||||
<contact-info-row
|
<contact-info-row
|
||||||
:value="additionalAttibutes.location"
|
v-if="additionalAttributes.location"
|
||||||
|
:value="additionalAttributes.location"
|
||||||
icon="ion-map"
|
icon="ion-map"
|
||||||
:title="$t('CONTACT_PANEL.LOCATION')"
|
:title="$t('CONTACT_PANEL.LOCATION')"
|
||||||
/>
|
/>
|
||||||
<contact-info-row
|
<contact-info-row
|
||||||
:value="additionalAttibutes.company_name"
|
:value="additionalAttributes.company_name"
|
||||||
icon="ion-briefcase"
|
icon="ion-briefcase"
|
||||||
:title="$t('CONTACT_PANEL.COMPANY')"
|
:title="$t('CONTACT_PANEL.COMPANY')"
|
||||||
/>
|
/>
|
||||||
@@ -89,14 +90,14 @@ export default {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
additionalAttibutes() {
|
additionalAttributes() {
|
||||||
return this.contact.additional_attributes || {};
|
return this.contact.additional_attributes || {};
|
||||||
},
|
},
|
||||||
socialProfiles() {
|
socialProfiles() {
|
||||||
const {
|
const {
|
||||||
social_profiles: socialProfiles,
|
social_profiles: socialProfiles,
|
||||||
screen_name: twitterScreenName,
|
screen_name: twitterScreenName,
|
||||||
} = this.additionalAttibutes;
|
} = this.additionalAttributes;
|
||||||
|
|
||||||
return { twitter: twitterScreenName, ...(socialProfiles || {}) };
|
return { twitter: twitterScreenName, ...(socialProfiles || {}) };
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -49,13 +49,6 @@
|
|||||||
:label="$t('EDIT_CONTACT.FORM.PHONE_NUMBER.LABEL')"
|
:label="$t('EDIT_CONTACT.FORM.PHONE_NUMBER.LABEL')"
|
||||||
:placeholder="$t('EDIT_CONTACT.FORM.PHONE_NUMBER.PLACEHOLDER')"
|
:placeholder="$t('EDIT_CONTACT.FORM.PHONE_NUMBER.PLACEHOLDER')"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<woot-input
|
|
||||||
v-model.trim="location"
|
|
||||||
class="medium-6 columns"
|
|
||||||
:label="$t('EDIT_CONTACT.FORM.LOCATION.LABEL')"
|
|
||||||
:placeholder="$t('EDIT_CONTACT.FORM.LOCATION.PLACEHOLDER')"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<woot-input
|
<woot-input
|
||||||
v-model.trim="companyName"
|
v-model.trim="companyName"
|
||||||
@@ -121,7 +114,6 @@ export default {
|
|||||||
companyName: '',
|
companyName: '',
|
||||||
description: '',
|
description: '',
|
||||||
email: '',
|
email: '',
|
||||||
location: '',
|
|
||||||
name: '',
|
name: '',
|
||||||
phoneNumber: '',
|
phoneNumber: '',
|
||||||
socialProfileUserNames: {
|
socialProfileUserNames: {
|
||||||
@@ -144,7 +136,6 @@ export default {
|
|||||||
email: {},
|
email: {},
|
||||||
companyName: {},
|
companyName: {},
|
||||||
phoneNumber: {},
|
phoneNumber: {},
|
||||||
location: {},
|
|
||||||
bio: {},
|
bio: {},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -171,7 +162,6 @@ export default {
|
|||||||
this.name = name || '';
|
this.name = name || '';
|
||||||
this.email = email || '';
|
this.email = email || '';
|
||||||
this.phoneNumber = phoneNumber || '';
|
this.phoneNumber = phoneNumber || '';
|
||||||
this.location = additionalAttributes.location || '';
|
|
||||||
this.companyName = additionalAttributes.company_name || '';
|
this.companyName = additionalAttributes.company_name || '';
|
||||||
this.description = additionalAttributes.description || '';
|
this.description = additionalAttributes.description || '';
|
||||||
const {
|
const {
|
||||||
@@ -193,7 +183,6 @@ export default {
|
|||||||
additional_attributes: {
|
additional_attributes: {
|
||||||
...this.contact.additional_attributes,
|
...this.contact.additional_attributes,
|
||||||
description: this.description,
|
description: this.description,
|
||||||
location: this.location,
|
|
||||||
company_name: this.companyName,
|
company_name: this.companyName,
|
||||||
social_profiles: this.socialProfileUserNames,
|
social_profiles: this.socialProfileUserNames,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -24,8 +24,12 @@ class ContactIpLookupJob < ApplicationJob
|
|||||||
ip = get_contact_ip(contact)
|
ip = get_contact_ip(contact)
|
||||||
return if ip.blank?
|
return if ip.blank?
|
||||||
|
|
||||||
contact.additional_attributes['city'] = Geocoder.search(ip).first.city
|
geocoder_result = Geocoder.search(ip).first
|
||||||
contact.additional_attributes['country'] = Geocoder.search(ip).first.country
|
return unless geocoder_result
|
||||||
|
|
||||||
|
contact.additional_attributes['city'] = geocoder_result.city
|
||||||
|
contact.additional_attributes['country'] = geocoder_result.country
|
||||||
|
contact.additional_attributes['country_code'] = geocoder_result.country_code
|
||||||
contact.save!
|
contact.save!
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -62,9 +62,12 @@ class Channel::WebWidget < ApplicationRecord
|
|||||||
"
|
"
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_contact_inbox
|
def create_contact_inbox(additional_attributes = {})
|
||||||
ActiveRecord::Base.transaction do
|
ActiveRecord::Base.transaction do
|
||||||
contact = inbox.account.contacts.create!(name: ::Haikunator.haikunate(1000))
|
contact = inbox.account.contacts.create!(
|
||||||
|
name: ::Haikunator.haikunate(1000),
|
||||||
|
additional_attributes: additional_attributes
|
||||||
|
)
|
||||||
contact_inbox = ::ContactInbox.create!(
|
contact_inbox = ::ContactInbox.create!(
|
||||||
contact_id: contact.id,
|
contact_id: contact.id,
|
||||||
inbox_id: inbox.id,
|
inbox_id: inbox.id,
|
||||||
|
|||||||
@@ -38,9 +38,8 @@ class Contact < ApplicationRecord
|
|||||||
has_many :messages, as: :sender, dependent: :destroy
|
has_many :messages, as: :sender, dependent: :destroy
|
||||||
|
|
||||||
before_validation :prepare_email_attribute
|
before_validation :prepare_email_attribute
|
||||||
after_create_commit :dispatch_create_event
|
after_create_commit :dispatch_create_event, :ip_lookup
|
||||||
after_update_commit :dispatch_update_event
|
after_update_commit :dispatch_update_event
|
||||||
after_commit :ip_lookup
|
|
||||||
|
|
||||||
def get_source_id(inbox_id)
|
def get_source_id(inbox_id)
|
||||||
contact_inboxes.find_by!(inbox_id: inbox_id).source_id
|
contact_inboxes.find_by!(inbox_id: inbox_id).source_id
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
"chart.js": "~2.5.0",
|
"chart.js": "~2.5.0",
|
||||||
"copy-text-to-clipboard": "^2.1.1",
|
"copy-text-to-clipboard": "^2.1.1",
|
||||||
"core-js": "3",
|
"core-js": "3",
|
||||||
|
"country-code-emoji": "^1.0.0",
|
||||||
"date-fns": "^2.16.1",
|
"date-fns": "^2.16.1",
|
||||||
"dotenv": "^8.0.0",
|
"dotenv": "^8.0.0",
|
||||||
"foundation-sites": "~6.5.3",
|
"foundation-sites": "~6.5.3",
|
||||||
|
|||||||
@@ -3213,6 +3213,11 @@ cosmiconfig@^6.0.0:
|
|||||||
path-type "^4.0.0"
|
path-type "^4.0.0"
|
||||||
yaml "^1.7.2"
|
yaml "^1.7.2"
|
||||||
|
|
||||||
|
country-code-emoji@^1.0.0:
|
||||||
|
version "1.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/country-code-emoji/-/country-code-emoji-1.0.0.tgz#7c77791839c9e9921beec08ef080caa7cfb8b40c"
|
||||||
|
integrity sha512-fBM5A49oZkOxOVb0bx7q7Hanlfh8e3z/r6/ZnFhbL57JXGIgWPC2HYrjXEyiGML7OFftDV/WfAlJdDkoAbj1Rg==
|
||||||
|
|
||||||
create-ecdh@^4.0.0:
|
create-ecdh@^4.0.0:
|
||||||
version "4.0.3"
|
version "4.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff"
|
resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff"
|
||||||
|
|||||||
Reference in New Issue
Block a user