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:
parent
47ec7ad7c9
commit
884a1c5971
10 changed files with 236 additions and 127 deletions
|
@ -1,10 +1,11 @@
|
|||
/* eslint no-plusplus: 0 */
|
||||
/* eslint-env browser */
|
||||
|
||||
import AvatarUploader from './widgets/forms/AvatarUploader.vue';
|
||||
import Bar from './widgets/chart/BarChart';
|
||||
import Code from './Code';
|
||||
import ColorPicker from './widgets/ColorPicker';
|
||||
import DeleteModal from './widgets/modal/DeleteModal.vue';
|
||||
import Input from './widgets/forms/Input.vue';
|
||||
import LoadingState from './widgets/LoadingState';
|
||||
import Modal from './Modal';
|
||||
import ModalHeader from './ModalHeader';
|
||||
|
@ -14,12 +15,15 @@ import Spinner from 'shared/components/Spinner';
|
|||
import SubmitButton from './buttons/FormSubmitButton';
|
||||
import Tabs from './ui/Tabs/Tabs';
|
||||
import TabsItem from './ui/Tabs/TabsItem';
|
||||
import Thumbnail from './widgets/Thumbnail.vue';
|
||||
|
||||
const WootUIKit = {
|
||||
AvatarUploader,
|
||||
Bar,
|
||||
Code,
|
||||
ColorPicker,
|
||||
DeleteModal,
|
||||
Input,
|
||||
LoadingState,
|
||||
Modal,
|
||||
ModalHeader,
|
||||
|
@ -29,6 +33,7 @@ const WootUIKit = {
|
|||
SubmitButton,
|
||||
Tabs,
|
||||
TabsItem,
|
||||
Thumbnail,
|
||||
install(Vue) {
|
||||
const keys = Object.keys(this);
|
||||
keys.pop(); // remove 'install' from keys
|
||||
|
|
|
@ -105,6 +105,15 @@ export default {
|
|||
return `user-thumbnail ${classname}`;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
src: {
|
||||
handler(value, oldValue) {
|
||||
if (value !== oldValue && this.imgError) {
|
||||
this.imgError = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onImgError() {
|
||||
this.imgError = true;
|
||||
|
|
|
@ -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>
|
44
app/javascript/dashboard/components/widgets/forms/Input.vue
Normal file
44
app/javascript/dashboard/components/widgets/forms/Input.vue
Normal 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>
|
|
@ -44,6 +44,9 @@
|
|||
"TITLE": "Website channel",
|
||||
"DESC": "Create a channel for your website and start supporting your customers via our website widget.",
|
||||
"LOADING_MESSAGE": "Creating Website Support Channel",
|
||||
"CHANNEL_AVATAR": {
|
||||
"LABEL": "Channel Avatar"
|
||||
},
|
||||
"CHANNEL_NAME": {
|
||||
"LABEL": "Website Name",
|
||||
"PLACEHOLDER": "Enter your website name (eg: Acme Inc)"
|
||||
|
|
|
@ -10,110 +10,89 @@
|
|||
:title="$t('INBOX_MGMT.SETTINGS_POPUP.INBOX_UPDATE_TITLE')"
|
||||
:sub-title="$t('INBOX_MGMT.SETTINGS_POPUP.INBOX_UPDATE_SUB_TEXT')"
|
||||
>
|
||||
<div v-if="inbox.channel_type === 'Channel::WebWidget'">
|
||||
<div class="medium-12 columns">
|
||||
<label>
|
||||
{{ $t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_NAME.LABEL') }}
|
||||
<input
|
||||
v-model.trim="selectedInboxName"
|
||||
type="text"
|
||||
:placeholder="
|
||||
$t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_NAME.PLACEHOLDER')
|
||||
"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<div class="medium-12 columns">
|
||||
<label>
|
||||
{{ $t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_DOMAIN.LABEL') }}
|
||||
<input
|
||||
v-model.trim="channelWebsiteUrl"
|
||||
type="text"
|
||||
:placeholder="
|
||||
$t(
|
||||
'INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_DOMAIN.PLACEHOLDER'
|
||||
)
|
||||
"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<div class="medium-12 columns">
|
||||
<label>
|
||||
{{
|
||||
$t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_WELCOME_TITLE.LABEL')
|
||||
}}
|
||||
<input
|
||||
v-model.trim="channelWelcomeTitle"
|
||||
type="text"
|
||||
:placeholder="
|
||||
$t(
|
||||
'INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_WELCOME_TITLE.PLACEHOLDER'
|
||||
)
|
||||
"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<div class="medium-12 columns">
|
||||
<label>
|
||||
{{
|
||||
$t(
|
||||
'INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_WELCOME_TAGLINE.LABEL'
|
||||
)
|
||||
}}
|
||||
<input
|
||||
v-model.trim="channelWelcomeTagline"
|
||||
type="text"
|
||||
:placeholder="
|
||||
$t(
|
||||
'INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_WELCOME_TAGLINE.PLACEHOLDER'
|
||||
)
|
||||
"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<div class="medium-12 columns">
|
||||
<label>
|
||||
{{
|
||||
$t(
|
||||
'INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_AGENT_AWAY_MESSAGE.LABEL'
|
||||
)
|
||||
}}
|
||||
<input
|
||||
v-model.trim="channelAgentAwayMessage"
|
||||
type="text"
|
||||
:placeholder="
|
||||
$t(
|
||||
'INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_AGENT_AWAY_MESSAGE.PLACEHOLDER'
|
||||
)
|
||||
"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<woot-avatar-uploader
|
||||
:label="$t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_AVATAR.LABEL')"
|
||||
:src="avatarUrl"
|
||||
@change="handleImageUpload"
|
||||
/>
|
||||
<woot-input
|
||||
v-if="isAWidgetInbox"
|
||||
v-model.trim="selectedInboxName"
|
||||
class="medium-12 columns"
|
||||
:label="$t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_NAME.LABEL')"
|
||||
:placeholder="
|
||||
$t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_NAME.PLACEHOLDER')
|
||||
"
|
||||
/>
|
||||
<woot-input
|
||||
v-if="isAWidgetInbox"
|
||||
v-model.trim="channelWebsiteUrl"
|
||||
class="medium-12 columns"
|
||||
:label="$t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_DOMAIN.LABEL')"
|
||||
:placeholder="
|
||||
$t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_DOMAIN.PLACEHOLDER')
|
||||
"
|
||||
/>
|
||||
<woot-input
|
||||
v-if="isAWidgetInbox"
|
||||
v-model.trim="channelWelcomeTitle"
|
||||
class="medium-12 columns"
|
||||
:label="
|
||||
$t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_WELCOME_TITLE.LABEL')
|
||||
"
|
||||
:placeholder="
|
||||
$t(
|
||||
'INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_WELCOME_TITLE.PLACEHOLDER'
|
||||
)
|
||||
"
|
||||
/>
|
||||
<woot-input
|
||||
v-if="isAWidgetInbox"
|
||||
v-model.trim="channelWelcomeTagline"
|
||||
class="medium-12 columns"
|
||||
:label="
|
||||
$t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_WELCOME_TAGLINE.LABEL')
|
||||
"
|
||||
:placeholder="
|
||||
$t(
|
||||
'INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_WELCOME_TAGLINE.PLACEHOLDER'
|
||||
)
|
||||
"
|
||||
/>
|
||||
|
||||
<div class="medium-12 columns">
|
||||
<label>
|
||||
{{ $t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.WIDGET_COLOR.LABEL') }}
|
||||
<woot-color-picker v-model="inbox.widget_color" />
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="medium-12 columns">
|
||||
<label>
|
||||
{{ $t('INBOX_MGMT.SETTINGS_POPUP.AUTO_ASSIGNMENT') }}
|
||||
<select v-model="autoAssignment">
|
||||
<option value="true">
|
||||
{{ $t('INBOX_MGMT.EDIT.AUTO_ASSIGNMENT.ENABLED') }}
|
||||
</option>
|
||||
<option value="false">
|
||||
{{ $t('INBOX_MGMT.EDIT.AUTO_ASSIGNMENT.DISABLED') }}
|
||||
</option>
|
||||
</select>
|
||||
<p class="help-text">
|
||||
{{ $t('INBOX_MGMT.SETTINGS_POPUP.AUTO_ASSIGNMENT_SUB_TEXT') }}
|
||||
</p>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<woot-input
|
||||
v-if="isAWidgetInbox"
|
||||
v-model.trim="channelAgentAwayMessage"
|
||||
class="medium-12 columns"
|
||||
:label="
|
||||
$t(
|
||||
'INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_AGENT_AWAY_MESSAGE.LABEL'
|
||||
)
|
||||
"
|
||||
:placeholder="
|
||||
$t(
|
||||
'INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_AGENT_AWAY_MESSAGE.PLACEHOLDER'
|
||||
)
|
||||
"
|
||||
/>
|
||||
<label v-if="isAWidgetInbox" class="medium-12 columns">
|
||||
{{ $t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.WIDGET_COLOR.LABEL') }}
|
||||
<woot-color-picker v-model="inbox.widget_color" />
|
||||
</label>
|
||||
<label class="medium-12 columns">
|
||||
{{ $t('INBOX_MGMT.SETTINGS_POPUP.AUTO_ASSIGNMENT') }}
|
||||
<select v-model="autoAssignment">
|
||||
<option value="true">
|
||||
{{ $t('INBOX_MGMT.EDIT.AUTO_ASSIGNMENT.ENABLED') }}
|
||||
</option>
|
||||
<option value="false">
|
||||
{{ $t('INBOX_MGMT.EDIT.AUTO_ASSIGNMENT.DISABLED') }}
|
||||
</option>
|
||||
</select>
|
||||
<p class="help-text">
|
||||
{{ $t('INBOX_MGMT.SETTINGS_POPUP.AUTO_ASSIGNMENT_SUB_TEXT') }}
|
||||
</p>
|
||||
</label>
|
||||
<woot-submit-button
|
||||
:button-text="$t('INBOX_MGMT.SETTINGS_POPUP.UPDATE')"
|
||||
:loading="uiFlags.isUpdatingInbox"
|
||||
|
@ -201,15 +180,26 @@ export default {
|
|||
mixins: [configMixin],
|
||||
data() {
|
||||
return {
|
||||
avatarFile: null,
|
||||
avatarUrl: '',
|
||||
selectedAgents: [],
|
||||
autoAssignment: false,
|
||||
isUpdating: false,
|
||||
isAgentListUpdating: false,
|
||||
selectedInboxName: '',
|
||||
channelWebsiteUrl: '',
|
||||
channelWelcomeTitle: '',
|
||||
channelWelcomeTagline: '',
|
||||
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: {
|
||||
|
@ -223,6 +213,9 @@ export default {
|
|||
inbox() {
|
||||
return this.$store.getters['inboxes/getInbox'](this.currentInboxId);
|
||||
},
|
||||
isAWidgetInbox() {
|
||||
return this.inbox.channel_type === 'Channel::WebWidget';
|
||||
},
|
||||
inboxName() {
|
||||
if (this.inbox.channel_type === 'Channel::TwilioSms') {
|
||||
return `${this.inbox.name} (${this.inbox.phone_number})`;
|
||||
|
@ -252,6 +245,7 @@ export default {
|
|||
this.$store.dispatch('agents/get');
|
||||
this.$store.dispatch('inboxes/get').then(() => {
|
||||
this.fetchAttachedAgents();
|
||||
this.avatarUrl = this.inbox.avatar_url;
|
||||
this.selectedInboxName = this.inbox.name;
|
||||
this.autoAssignment = this.inbox.enable_auto_assignment;
|
||||
this.channelWebsiteUrl = this.inbox.website_url;
|
||||
|
@ -296,7 +290,7 @@ export default {
|
|||
},
|
||||
async updateInbox() {
|
||||
try {
|
||||
await this.$store.dispatch('inboxes/updateInbox', {
|
||||
const payload = {
|
||||
id: this.currentInboxId,
|
||||
name: this.selectedInboxName,
|
||||
enable_auto_assignment: this.autoAssignment,
|
||||
|
@ -307,12 +301,21 @@ export default {
|
|||
welcome_tagline: this.channelWelcomeTagline,
|
||||
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'));
|
||||
} catch (error) {
|
||||
this.showAlert(this.$t('INBOX_MGMT.EDIT.API.SUCCESS_MESSAGE'));
|
||||
}
|
||||
},
|
||||
handleImageUpload({ file, url }) {
|
||||
this.avatarFile = file;
|
||||
this.avatarUrl = url;
|
||||
console.log(this.avatarUrl);
|
||||
},
|
||||
},
|
||||
validations: {
|
||||
selectedAgents: {
|
||||
|
|
|
@ -141,7 +141,7 @@ export default {
|
|||
channel: {
|
||||
type: 'web_widget',
|
||||
website_url: this.channelWebsiteUrl,
|
||||
widget_color: this.channelWidgetColor.hex,
|
||||
widget_color: this.channelWidgetColor,
|
||||
welcome_title: this.channelWelcomeTitle,
|
||||
welcome_tagline: this.channelWelcomeTagline,
|
||||
agent_away_message: this.channelAgentAwayMessage,
|
||||
|
|
|
@ -9,17 +9,11 @@
|
|||
<p>{{ $t('PROFILE_SETTINGS.FORM.PROFILE_SECTION.NOTE') }}</p>
|
||||
</div>
|
||||
<div class="columns small-9 medium-5">
|
||||
<label>
|
||||
{{ $t('PROFILE_SETTINGS.FORM.PROFILE_IMAGE.LABEL') }}
|
||||
<thumbnail size="80px" :src="avatarUrl"></thumbnail>
|
||||
<input
|
||||
id="file"
|
||||
ref="file"
|
||||
type="file"
|
||||
accept="image/*"
|
||||
@change="handleImageUpload"
|
||||
/>
|
||||
</label>
|
||||
<woot-avatar-uploader
|
||||
:label="$t('PROFILE_SETTINGS.FORM.PROFILE_IMAGE.LABEL')"
|
||||
:src="avatarUrl"
|
||||
@change="handleImageUpload"
|
||||
/>
|
||||
<label :class="{ error: $v.name.$error }">
|
||||
{{ $t('PROFILE_SETTINGS.FORM.NAME.LABEL') }}
|
||||
<input
|
||||
|
@ -106,8 +100,6 @@
|
|||
|
||||
<script>
|
||||
/* global bus */
|
||||
|
||||
import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue';
|
||||
import { required, minLength, email } from 'vuelidate/lib/validators';
|
||||
import { mapGetters } from 'vuex';
|
||||
import { clearCookiesOnLogout } from '../../../../store/utils/api';
|
||||
|
@ -116,7 +108,6 @@ import NotificationSettings from './NotificationSettings';
|
|||
export default {
|
||||
components: {
|
||||
NotificationSettings,
|
||||
Thumbnail,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
@ -202,10 +193,9 @@ export default {
|
|||
this.isUpdating = false;
|
||||
}
|
||||
},
|
||||
handleImageUpload(event) {
|
||||
const [file] = event.target.files;
|
||||
handleImageUpload({ file, url }) {
|
||||
this.avatarFile = file;
|
||||
this.avatarUrl = URL.createObjectURL(file);
|
||||
this.avatarUrl = url;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -5,6 +5,18 @@ import WebChannel from '../../api/channel/webChannel';
|
|||
import FBChannel from '../../api/channel/fbChannel';
|
||||
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 = {
|
||||
records: [],
|
||||
uiFlags: {
|
||||
|
@ -46,7 +58,7 @@ export const actions = {
|
|||
createWebsiteChannel: async ({ commit }, params) => {
|
||||
try {
|
||||
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.SET_INBOXES_UI_FLAG, { isCreating: false });
|
||||
return response.data;
|
||||
|
@ -84,7 +96,7 @@ export const actions = {
|
|||
isUpdatingAutoAssignment: true,
|
||||
});
|
||||
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.SET_INBOXES_UI_FLAG, {
|
||||
isUpdatingAutoAssignment: false,
|
||||
|
|
|
@ -58,6 +58,10 @@ export default {
|
|||
.header-branding {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
img {
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
|
|
Loading…
Reference in a new issue