Chore: Add an option to upload a business logo to inbox (#905)

Chore: Add an option to upload a business logo to inbox
This commit is contained in:
Pranav Raj S 2020-05-31 16:16:22 +05:30 committed by GitHub
parent 47ec7ad7c9
commit 884a1c5971
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 236 additions and 127 deletions

View file

@ -1,10 +1,11 @@
/* eslint no-plusplus: 0 */ /* eslint no-plusplus: 0 */
/* eslint-env browser */ /* eslint-env browser */
import AvatarUploader from './widgets/forms/AvatarUploader.vue';
import Bar from './widgets/chart/BarChart'; import Bar from './widgets/chart/BarChart';
import Code from './Code'; import Code from './Code';
import ColorPicker from './widgets/ColorPicker'; import ColorPicker from './widgets/ColorPicker';
import DeleteModal from './widgets/modal/DeleteModal.vue'; import DeleteModal from './widgets/modal/DeleteModal.vue';
import Input from './widgets/forms/Input.vue';
import LoadingState from './widgets/LoadingState'; import LoadingState from './widgets/LoadingState';
import Modal from './Modal'; import Modal from './Modal';
import ModalHeader from './ModalHeader'; import ModalHeader from './ModalHeader';
@ -14,12 +15,15 @@ import Spinner from 'shared/components/Spinner';
import SubmitButton from './buttons/FormSubmitButton'; import SubmitButton from './buttons/FormSubmitButton';
import Tabs from './ui/Tabs/Tabs'; import Tabs from './ui/Tabs/Tabs';
import TabsItem from './ui/Tabs/TabsItem'; import TabsItem from './ui/Tabs/TabsItem';
import Thumbnail from './widgets/Thumbnail.vue';
const WootUIKit = { const WootUIKit = {
AvatarUploader,
Bar, Bar,
Code, Code,
ColorPicker, ColorPicker,
DeleteModal, DeleteModal,
Input,
LoadingState, LoadingState,
Modal, Modal,
ModalHeader, ModalHeader,
@ -29,6 +33,7 @@ const WootUIKit = {
SubmitButton, SubmitButton,
Tabs, Tabs,
TabsItem, TabsItem,
Thumbnail,
install(Vue) { install(Vue) {
const keys = Object.keys(this); const keys = Object.keys(this);
keys.pop(); // remove 'install' from keys keys.pop(); // remove 'install' from keys

View file

@ -105,6 +105,15 @@ export default {
return `user-thumbnail ${classname}`; return `user-thumbnail ${classname}`;
}, },
}, },
watch: {
src: {
handler(value, oldValue) {
if (value !== oldValue && this.imgError) {
this.imgError = false;
}
},
},
},
methods: { methods: {
onImgError() { onImgError() {
this.imgError = true; this.imgError = true;

View file

@ -0,0 +1,39 @@
<template>
<label>
<span v-if="label">{{ label }}</span>
<woot-thumbnail v-if="src" size="80px" :src="src" />
<input
id="file"
ref="file"
type="file"
accept="image/*"
@change="handleImageUpload"
/>
<slot></slot>
</label>
</template>
<script>
export default {
props: {
label: {
type: String,
default: '',
},
src: {
type: String,
default: '',
},
},
methods: {
handleImageUpload(event) {
const [file] = event.target.files;
this.$emit('change', {
file,
url: URL.createObjectURL(file),
});
},
},
};
</script>

View file

@ -0,0 +1,44 @@
<template>
<label>
<span v-if="label">{{ label }}</span>
<input
:value="value"
:type="type"
:placeholder="placeholder"
@input="onChange"
/>
<p v-if="helpText" class="help-text"></p>
</label>
</template>
<script>
export default {
props: {
label: {
type: String,
default: '',
},
value: {
type: [String, Number],
default: '',
},
type: {
type: String,
default: 'text',
},
placeholder: {
type: String,
default: '',
},
helpText: {
type: String,
default: '',
},
},
methods: {
onChange(e) {
this.$emit('input', e.target.value);
},
},
};
</script>

View file

@ -44,6 +44,9 @@
"TITLE": "Website channel", "TITLE": "Website channel",
"DESC": "Create a channel for your website and start supporting your customers via our website widget.", "DESC": "Create a channel for your website and start supporting your customers via our website widget.",
"LOADING_MESSAGE": "Creating Website Support Channel", "LOADING_MESSAGE": "Creating Website Support Channel",
"CHANNEL_AVATAR": {
"LABEL": "Channel Avatar"
},
"CHANNEL_NAME": { "CHANNEL_NAME": {
"LABEL": "Website Name", "LABEL": "Website Name",
"PLACEHOLDER": "Enter your website name (eg: Acme Inc)" "PLACEHOLDER": "Enter your website name (eg: Acme Inc)"

View file

@ -10,95 +10,76 @@
:title="$t('INBOX_MGMT.SETTINGS_POPUP.INBOX_UPDATE_TITLE')" :title="$t('INBOX_MGMT.SETTINGS_POPUP.INBOX_UPDATE_TITLE')"
:sub-title="$t('INBOX_MGMT.SETTINGS_POPUP.INBOX_UPDATE_SUB_TEXT')" :sub-title="$t('INBOX_MGMT.SETTINGS_POPUP.INBOX_UPDATE_SUB_TEXT')"
> >
<div v-if="inbox.channel_type === 'Channel::WebWidget'"> <woot-avatar-uploader
<div class="medium-12 columns"> :label="$t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_AVATAR.LABEL')"
<label> :src="avatarUrl"
{{ $t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_NAME.LABEL') }} @change="handleImageUpload"
<input />
<woot-input
v-if="isAWidgetInbox"
v-model.trim="selectedInboxName" v-model.trim="selectedInboxName"
type="text" class="medium-12 columns"
:label="$t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_NAME.LABEL')"
:placeholder=" :placeholder="
$t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_NAME.PLACEHOLDER') $t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_NAME.PLACEHOLDER')
" "
/> />
</label> <woot-input
</div> v-if="isAWidgetInbox"
<div class="medium-12 columns">
<label>
{{ $t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_DOMAIN.LABEL') }}
<input
v-model.trim="channelWebsiteUrl" v-model.trim="channelWebsiteUrl"
type="text" class="medium-12 columns"
:label="$t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_DOMAIN.LABEL')"
:placeholder=" :placeholder="
$t( $t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_DOMAIN.PLACEHOLDER')
'INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_DOMAIN.PLACEHOLDER'
)
" "
/> />
</label> <woot-input
</div> v-if="isAWidgetInbox"
<div class="medium-12 columns">
<label>
{{
$t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_WELCOME_TITLE.LABEL')
}}
<input
v-model.trim="channelWelcomeTitle" v-model.trim="channelWelcomeTitle"
type="text" class="medium-12 columns"
:label="
$t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_WELCOME_TITLE.LABEL')
"
:placeholder=" :placeholder="
$t( $t(
'INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_WELCOME_TITLE.PLACEHOLDER' 'INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_WELCOME_TITLE.PLACEHOLDER'
) )
" "
/> />
</label> <woot-input
</div> v-if="isAWidgetInbox"
<div class="medium-12 columns">
<label>
{{
$t(
'INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_WELCOME_TAGLINE.LABEL'
)
}}
<input
v-model.trim="channelWelcomeTagline" v-model.trim="channelWelcomeTagline"
type="text" class="medium-12 columns"
:label="
$t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_WELCOME_TAGLINE.LABEL')
"
:placeholder=" :placeholder="
$t( $t(
'INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_WELCOME_TAGLINE.PLACEHOLDER' 'INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_WELCOME_TAGLINE.PLACEHOLDER'
) )
" "
/> />
</label>
</div> <woot-input
<div class="medium-12 columns"> v-if="isAWidgetInbox"
<label> v-model.trim="channelAgentAwayMessage"
{{ class="medium-12 columns"
:label="
$t( $t(
'INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_AGENT_AWAY_MESSAGE.LABEL' 'INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_AGENT_AWAY_MESSAGE.LABEL'
) )
}} "
<input
v-model.trim="channelAgentAwayMessage"
type="text"
:placeholder=" :placeholder="
$t( $t(
'INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_AGENT_AWAY_MESSAGE.PLACEHOLDER' 'INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_AGENT_AWAY_MESSAGE.PLACEHOLDER'
) )
" "
/> />
</label> <label v-if="isAWidgetInbox" class="medium-12 columns">
</div>
<div class="medium-12 columns">
<label>
{{ $t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.WIDGET_COLOR.LABEL') }} {{ $t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.WIDGET_COLOR.LABEL') }}
<woot-color-picker v-model="inbox.widget_color" /> <woot-color-picker v-model="inbox.widget_color" />
</label> </label>
</div> <label class="medium-12 columns">
<div class="medium-12 columns">
<label>
{{ $t('INBOX_MGMT.SETTINGS_POPUP.AUTO_ASSIGNMENT') }} {{ $t('INBOX_MGMT.SETTINGS_POPUP.AUTO_ASSIGNMENT') }}
<select v-model="autoAssignment"> <select v-model="autoAssignment">
<option value="true"> <option value="true">
@ -112,8 +93,6 @@
{{ $t('INBOX_MGMT.SETTINGS_POPUP.AUTO_ASSIGNMENT_SUB_TEXT') }} {{ $t('INBOX_MGMT.SETTINGS_POPUP.AUTO_ASSIGNMENT_SUB_TEXT') }}
</p> </p>
</label> </label>
</div>
</div>
<woot-submit-button <woot-submit-button
:button-text="$t('INBOX_MGMT.SETTINGS_POPUP.UPDATE')" :button-text="$t('INBOX_MGMT.SETTINGS_POPUP.UPDATE')"
:loading="uiFlags.isUpdatingInbox" :loading="uiFlags.isUpdatingInbox"
@ -201,15 +180,26 @@ export default {
mixins: [configMixin], mixins: [configMixin],
data() { data() {
return { return {
avatarFile: null,
avatarUrl: '',
selectedAgents: [], selectedAgents: [],
autoAssignment: false, autoAssignment: false,
isUpdating: false,
isAgentListUpdating: false, isAgentListUpdating: false,
selectedInboxName: '', selectedInboxName: '',
channelWebsiteUrl: '', channelWebsiteUrl: '',
channelWelcomeTitle: '', channelWelcomeTitle: '',
channelWelcomeTagline: '', channelWelcomeTagline: '',
channelAgentAwayMessage: '', channelAgentAwayMessage: '',
autoAssignmentOptions: [
{
value: true,
label: this.$t('INBOX_MGMT.EDIT.AUTO_ASSIGNMENT.ENABLED'),
},
{
value: false,
label: this.$t('INBOX_MGMT.EDIT.AUTO_ASSIGNMENT.DISABLED'),
},
],
}; };
}, },
computed: { computed: {
@ -223,6 +213,9 @@ export default {
inbox() { inbox() {
return this.$store.getters['inboxes/getInbox'](this.currentInboxId); return this.$store.getters['inboxes/getInbox'](this.currentInboxId);
}, },
isAWidgetInbox() {
return this.inbox.channel_type === 'Channel::WebWidget';
},
inboxName() { inboxName() {
if (this.inbox.channel_type === 'Channel::TwilioSms') { if (this.inbox.channel_type === 'Channel::TwilioSms') {
return `${this.inbox.name} (${this.inbox.phone_number})`; return `${this.inbox.name} (${this.inbox.phone_number})`;
@ -252,6 +245,7 @@ export default {
this.$store.dispatch('agents/get'); this.$store.dispatch('agents/get');
this.$store.dispatch('inboxes/get').then(() => { this.$store.dispatch('inboxes/get').then(() => {
this.fetchAttachedAgents(); this.fetchAttachedAgents();
this.avatarUrl = this.inbox.avatar_url;
this.selectedInboxName = this.inbox.name; this.selectedInboxName = this.inbox.name;
this.autoAssignment = this.inbox.enable_auto_assignment; this.autoAssignment = this.inbox.enable_auto_assignment;
this.channelWebsiteUrl = this.inbox.website_url; this.channelWebsiteUrl = this.inbox.website_url;
@ -296,7 +290,7 @@ export default {
}, },
async updateInbox() { async updateInbox() {
try { try {
await this.$store.dispatch('inboxes/updateInbox', { const payload = {
id: this.currentInboxId, id: this.currentInboxId,
name: this.selectedInboxName, name: this.selectedInboxName,
enable_auto_assignment: this.autoAssignment, enable_auto_assignment: this.autoAssignment,
@ -307,12 +301,21 @@ export default {
welcome_tagline: this.channelWelcomeTagline, welcome_tagline: this.channelWelcomeTagline,
agent_away_message: this.channelAgentAwayMessage, agent_away_message: this.channelAgentAwayMessage,
}, },
}); };
if (this.avatarFile) {
payload.avatar = this.avatarFile;
}
await this.$store.dispatch('inboxes/updateInbox', payload);
this.showAlert(this.$t('INBOX_MGMT.EDIT.API.SUCCESS_MESSAGE')); this.showAlert(this.$t('INBOX_MGMT.EDIT.API.SUCCESS_MESSAGE'));
} catch (error) { } catch (error) {
this.showAlert(this.$t('INBOX_MGMT.EDIT.API.SUCCESS_MESSAGE')); this.showAlert(this.$t('INBOX_MGMT.EDIT.API.SUCCESS_MESSAGE'));
} }
}, },
handleImageUpload({ file, url }) {
this.avatarFile = file;
this.avatarUrl = url;
console.log(this.avatarUrl);
},
}, },
validations: { validations: {
selectedAgents: { selectedAgents: {

View file

@ -141,7 +141,7 @@ export default {
channel: { channel: {
type: 'web_widget', type: 'web_widget',
website_url: this.channelWebsiteUrl, website_url: this.channelWebsiteUrl,
widget_color: this.channelWidgetColor.hex, widget_color: this.channelWidgetColor,
welcome_title: this.channelWelcomeTitle, welcome_title: this.channelWelcomeTitle,
welcome_tagline: this.channelWelcomeTagline, welcome_tagline: this.channelWelcomeTagline,
agent_away_message: this.channelAgentAwayMessage, agent_away_message: this.channelAgentAwayMessage,

View file

@ -9,17 +9,11 @@
<p>{{ $t('PROFILE_SETTINGS.FORM.PROFILE_SECTION.NOTE') }}</p> <p>{{ $t('PROFILE_SETTINGS.FORM.PROFILE_SECTION.NOTE') }}</p>
</div> </div>
<div class="columns small-9 medium-5"> <div class="columns small-9 medium-5">
<label> <woot-avatar-uploader
{{ $t('PROFILE_SETTINGS.FORM.PROFILE_IMAGE.LABEL') }} :label="$t('PROFILE_SETTINGS.FORM.PROFILE_IMAGE.LABEL')"
<thumbnail size="80px" :src="avatarUrl"></thumbnail> :src="avatarUrl"
<input
id="file"
ref="file"
type="file"
accept="image/*"
@change="handleImageUpload" @change="handleImageUpload"
/> />
</label>
<label :class="{ error: $v.name.$error }"> <label :class="{ error: $v.name.$error }">
{{ $t('PROFILE_SETTINGS.FORM.NAME.LABEL') }} {{ $t('PROFILE_SETTINGS.FORM.NAME.LABEL') }}
<input <input
@ -106,8 +100,6 @@
<script> <script>
/* global bus */ /* global bus */
import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue';
import { required, minLength, email } from 'vuelidate/lib/validators'; import { required, minLength, email } from 'vuelidate/lib/validators';
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import { clearCookiesOnLogout } from '../../../../store/utils/api'; import { clearCookiesOnLogout } from '../../../../store/utils/api';
@ -116,7 +108,6 @@ import NotificationSettings from './NotificationSettings';
export default { export default {
components: { components: {
NotificationSettings, NotificationSettings,
Thumbnail,
}, },
data() { data() {
return { return {
@ -202,10 +193,9 @@ export default {
this.isUpdating = false; this.isUpdating = false;
} }
}, },
handleImageUpload(event) { handleImageUpload({ file, url }) {
const [file] = event.target.files;
this.avatarFile = file; this.avatarFile = file;
this.avatarUrl = URL.createObjectURL(file); this.avatarUrl = url;
}, },
}, },
}; };

View file

@ -5,6 +5,18 @@ import WebChannel from '../../api/channel/webChannel';
import FBChannel from '../../api/channel/fbChannel'; import FBChannel from '../../api/channel/fbChannel';
import TwilioChannel from '../../api/channel/twilioChannel'; import TwilioChannel from '../../api/channel/twilioChannel';
const buildInboxData = inboxParams => {
const formData = new FormData();
const { channel = {}, ...inboxProperties } = inboxParams;
Object.keys(inboxProperties).forEach(key => {
formData.append(key, inboxProperties[key]);
});
Object.keys(channel).forEach(key => {
formData.append(`channel[${key}]`, channel[key]);
});
return formData;
};
export const state = { export const state = {
records: [], records: [],
uiFlags: { uiFlags: {
@ -46,7 +58,7 @@ export const actions = {
createWebsiteChannel: async ({ commit }, params) => { createWebsiteChannel: async ({ commit }, params) => {
try { try {
commit(types.default.SET_INBOXES_UI_FLAG, { isCreating: true }); commit(types.default.SET_INBOXES_UI_FLAG, { isCreating: true });
const response = await WebChannel.create(params); const response = await WebChannel.create(buildInboxData(params));
commit(types.default.ADD_INBOXES, response.data); commit(types.default.ADD_INBOXES, response.data);
commit(types.default.SET_INBOXES_UI_FLAG, { isCreating: false }); commit(types.default.SET_INBOXES_UI_FLAG, { isCreating: false });
return response.data; return response.data;
@ -84,7 +96,7 @@ export const actions = {
isUpdatingAutoAssignment: true, isUpdatingAutoAssignment: true,
}); });
try { try {
const response = await InboxesAPI.update(id, inboxParams); const response = await InboxesAPI.update(id, buildInboxData(inboxParams));
commit(types.default.EDIT_INBOXES, response.data); commit(types.default.EDIT_INBOXES, response.data);
commit(types.default.SET_INBOXES_UI_FLAG, { commit(types.default.SET_INBOXES_UI_FLAG, {
isUpdatingAutoAssignment: false, isUpdatingAutoAssignment: false,

View file

@ -58,6 +58,10 @@ export default {
.header-branding { .header-branding {
display: flex; display: flex;
align-items: center; align-items: center;
img {
border-radius: 50%;
}
} }
.title { .title {