feat: Update Inbox/Team creation UI (#12305)
This commit is contained in:
@@ -2,23 +2,23 @@ import { computed } from 'vue';
|
||||
|
||||
export function useChannelIcon(inbox) {
|
||||
const channelTypeIconMap = {
|
||||
'Channel::Api': 'i-ri-cloudy-fill',
|
||||
'Channel::Email': 'i-ri-mail-fill',
|
||||
'Channel::FacebookPage': 'i-ri-messenger-fill',
|
||||
'Channel::Line': 'i-ri-line-fill',
|
||||
'Channel::Sms': 'i-ri-chat-1-fill',
|
||||
'Channel::Telegram': 'i-ri-telegram-fill',
|
||||
'Channel::TwilioSms': 'i-ri-chat-1-fill',
|
||||
'Channel::Api': 'i-woot-api',
|
||||
'Channel::Email': 'i-woot-mail',
|
||||
'Channel::FacebookPage': 'i-woot-messenger',
|
||||
'Channel::Line': 'i-woot-line',
|
||||
'Channel::Sms': 'i-woot-sms',
|
||||
'Channel::Telegram': 'i-woot-telegram',
|
||||
'Channel::TwilioSms': 'i-woot-sms',
|
||||
'Channel::TwitterProfile': 'i-ri-twitter-x-fill',
|
||||
'Channel::WebWidget': 'i-ri-global-fill',
|
||||
'Channel::Whatsapp': 'i-ri-whatsapp-fill',
|
||||
'Channel::Instagram': 'i-ri-instagram-fill',
|
||||
'Channel::WebWidget': 'i-woot-website',
|
||||
'Channel::Whatsapp': 'i-woot-whatsapp',
|
||||
'Channel::Instagram': 'i-woot-instagram',
|
||||
'Channel::Voice': 'i-ri-phone-fill',
|
||||
};
|
||||
|
||||
const providerIconMap = {
|
||||
microsoft: 'i-ri-microsoft-fill',
|
||||
google: 'i-ri-google-fill',
|
||||
microsoft: 'i-woot-outlook',
|
||||
google: 'i-woot-gmail',
|
||||
};
|
||||
|
||||
const channelIcon = computed(() => {
|
||||
@@ -34,7 +34,7 @@ export function useChannelIcon(inbox) {
|
||||
|
||||
// Special case for Twilio whatsapp
|
||||
if (type === 'Channel::TwilioSms' && inboxDetails.medium === 'whatsapp') {
|
||||
icon = 'i-ri-whatsapp-fill';
|
||||
icon = 'i-woot-whatsapp';
|
||||
}
|
||||
|
||||
return icon ?? 'i-ri-global-fill';
|
||||
|
||||
@@ -4,19 +4,19 @@ describe('useChannelIcon', () => {
|
||||
it('returns correct icon for API channel', () => {
|
||||
const inbox = { channel_type: 'Channel::Api' };
|
||||
const { value: icon } = useChannelIcon(inbox);
|
||||
expect(icon).toBe('i-ri-cloudy-fill');
|
||||
expect(icon).toBe('i-woot-api');
|
||||
});
|
||||
|
||||
it('returns correct icon for Facebook channel', () => {
|
||||
const inbox = { channel_type: 'Channel::FacebookPage' };
|
||||
const { value: icon } = useChannelIcon(inbox);
|
||||
expect(icon).toBe('i-ri-messenger-fill');
|
||||
expect(icon).toBe('i-woot-messenger');
|
||||
});
|
||||
|
||||
it('returns correct icon for WhatsApp channel', () => {
|
||||
const inbox = { channel_type: 'Channel::Whatsapp' };
|
||||
const { value: icon } = useChannelIcon(inbox);
|
||||
expect(icon).toBe('i-ri-whatsapp-fill');
|
||||
expect(icon).toBe('i-woot-whatsapp');
|
||||
});
|
||||
|
||||
it('returns correct icon for Voice channel', () => {
|
||||
@@ -28,19 +28,19 @@ describe('useChannelIcon', () => {
|
||||
it('returns correct icon for Line channel', () => {
|
||||
const inbox = { channel_type: 'Channel::Line' };
|
||||
const { value: icon } = useChannelIcon(inbox);
|
||||
expect(icon).toBe('i-ri-line-fill');
|
||||
expect(icon).toBe('i-woot-line');
|
||||
});
|
||||
|
||||
it('returns correct icon for SMS channel', () => {
|
||||
const inbox = { channel_type: 'Channel::Sms' };
|
||||
const { value: icon } = useChannelIcon(inbox);
|
||||
expect(icon).toBe('i-ri-chat-1-fill');
|
||||
expect(icon).toBe('i-woot-sms');
|
||||
});
|
||||
|
||||
it('returns correct icon for Telegram channel', () => {
|
||||
const inbox = { channel_type: 'Channel::Telegram' };
|
||||
const { value: icon } = useChannelIcon(inbox);
|
||||
expect(icon).toBe('i-ri-telegram-fill');
|
||||
expect(icon).toBe('i-woot-telegram');
|
||||
});
|
||||
|
||||
it('returns correct icon for Twitter channel', () => {
|
||||
@@ -52,20 +52,20 @@ describe('useChannelIcon', () => {
|
||||
it('returns correct icon for WebWidget channel', () => {
|
||||
const inbox = { channel_type: 'Channel::WebWidget' };
|
||||
const { value: icon } = useChannelIcon(inbox);
|
||||
expect(icon).toBe('i-ri-global-fill');
|
||||
expect(icon).toBe('i-woot-website');
|
||||
});
|
||||
|
||||
it('returns correct icon for Instagram channel', () => {
|
||||
const inbox = { channel_type: 'Channel::Instagram' };
|
||||
const { value: icon } = useChannelIcon(inbox);
|
||||
expect(icon).toBe('i-ri-instagram-fill');
|
||||
expect(icon).toBe('i-woot-instagram');
|
||||
});
|
||||
|
||||
describe('TwilioSms channel', () => {
|
||||
it('returns chat icon for regular Twilio SMS channel', () => {
|
||||
const inbox = { channel_type: 'Channel::TwilioSms' };
|
||||
const { value: icon } = useChannelIcon(inbox);
|
||||
expect(icon).toBe('i-ri-chat-1-fill');
|
||||
expect(icon).toBe('i-woot-sms');
|
||||
});
|
||||
|
||||
it('returns WhatsApp icon for Twilio SMS with WhatsApp medium', () => {
|
||||
@@ -74,7 +74,7 @@ describe('useChannelIcon', () => {
|
||||
medium: 'whatsapp',
|
||||
};
|
||||
const { value: icon } = useChannelIcon(inbox);
|
||||
expect(icon).toBe('i-ri-whatsapp-fill');
|
||||
expect(icon).toBe('i-woot-whatsapp');
|
||||
});
|
||||
|
||||
it('returns chat icon for Twilio SMS with non-WhatsApp medium', () => {
|
||||
@@ -83,7 +83,7 @@ describe('useChannelIcon', () => {
|
||||
medium: 'sms',
|
||||
};
|
||||
const { value: icon } = useChannelIcon(inbox);
|
||||
expect(icon).toBe('i-ri-chat-1-fill');
|
||||
expect(icon).toBe('i-woot-sms');
|
||||
});
|
||||
|
||||
it('returns chat icon for Twilio SMS with undefined medium', () => {
|
||||
@@ -92,7 +92,7 @@ describe('useChannelIcon', () => {
|
||||
medium: undefined,
|
||||
};
|
||||
const { value: icon } = useChannelIcon(inbox);
|
||||
expect(icon).toBe('i-ri-chat-1-fill');
|
||||
expect(icon).toBe('i-woot-sms');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -100,7 +100,7 @@ describe('useChannelIcon', () => {
|
||||
it('returns mail icon for generic email channel', () => {
|
||||
const inbox = { channel_type: 'Channel::Email' };
|
||||
const { value: icon } = useChannelIcon(inbox);
|
||||
expect(icon).toBe('i-ri-mail-fill');
|
||||
expect(icon).toBe('i-woot-mail');
|
||||
});
|
||||
|
||||
it('returns Microsoft icon for Microsoft email provider', () => {
|
||||
@@ -109,7 +109,7 @@ describe('useChannelIcon', () => {
|
||||
provider: 'microsoft',
|
||||
};
|
||||
const { value: icon } = useChannelIcon(inbox);
|
||||
expect(icon).toBe('i-ri-microsoft-fill');
|
||||
expect(icon).toBe('i-woot-outlook');
|
||||
});
|
||||
|
||||
it('returns Google icon for Google email provider', () => {
|
||||
@@ -118,7 +118,7 @@ describe('useChannelIcon', () => {
|
||||
provider: 'google',
|
||||
};
|
||||
const { value: icon } = useChannelIcon(inbox);
|
||||
expect(icon).toBe('i-ri-google-fill');
|
||||
expect(icon).toBe('i-woot-gmail');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ const reauthorizationRequired = computed(() => {
|
||||
|
||||
<template>
|
||||
<span
|
||||
class="size-4 grid place-content-center rounded-full bg-n-alpha-2"
|
||||
class="size-5 grid place-content-center rounded-full bg-n-alpha-2"
|
||||
:class="{ 'bg-n-solid-blue': active }"
|
||||
>
|
||||
<ChannelIcon :inbox="inbox" class="size-3" />
|
||||
|
||||
@@ -1,50 +1,57 @@
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
src: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
isComingSoon: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
<script setup>
|
||||
import Icon from 'next/icon/Icon.vue';
|
||||
|
||||
defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
};
|
||||
description: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
icon: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
isComingSoon: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<button
|
||||
class="relative bg-n-background cursor-pointer flex flex-col justify-end transition-all duration-200 ease-in -m-px py-4 px-0 items-center border border-solid border-n-weak hover:border-n-brand hover:shadow-md hover:z-50 disabled:opacity-60"
|
||||
class="relative bg-n-solid-1 gap-6 cursor-pointer rounded-2xl flex flex-col justify-start transition-all duration-200 ease-in -m-px py-6 px-5 items-start border border-solid border-n-weak"
|
||||
:class="{
|
||||
'hover:enabled:border-n-blue-9 hover:enabled:shadow-md disabled:opacity-60 disabled:cursor-not-allowed':
|
||||
!isComingSoon,
|
||||
'cursor-not-allowed disabled:opacity-80': isComingSoon,
|
||||
}"
|
||||
>
|
||||
<img :src="src" :alt="title" draggable="false" class="w-1/2 my-4 mx-auto" />
|
||||
<h3 class="text-n-slate-12 text-base text-center capitalize">
|
||||
{{ title }}
|
||||
</h3>
|
||||
<div
|
||||
class="flex size-10 items-center justify-center rounded-full bg-n-alpha-2"
|
||||
>
|
||||
<Icon :icon="icon" class="text-n-slate-10 size-6" />
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col items-start gap-1.5">
|
||||
<h3 class="text-n-slate-12 text-sm text-start font-medium capitalize">
|
||||
{{ title }}
|
||||
</h3>
|
||||
<p class="text-n-slate-11 text-start text-sm">
|
||||
{{ description }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="isComingSoon"
|
||||
class="absolute inset-0 flex items-center justify-center backdrop-blur-[2px] rounded-md bg-gradient-to-br from-n-background/90 via-n-background/70 to-n-background/95"
|
||||
class="absolute inset-0 flex items-center justify-center backdrop-blur-[2px] rounded-2xl bg-gradient-to-br from-n-background/90 via-n-background/70 to-n-background/95 cursor-not-allowed"
|
||||
>
|
||||
<span class="text-n-slate-12 font-medium text-base">
|
||||
<span class="text-n-slate-12 font-medium text-sm">
|
||||
{{ $t('CHANNEL_SELECTOR.COMING_SOON') }} 🚀
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.inactive {
|
||||
img {
|
||||
filter: grayscale(100%);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
@apply border-n-strong shadow-none cursor-not-allowed;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,97 +1,75 @@
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
items: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
classObject() {
|
||||
return 'w-full';
|
||||
},
|
||||
activeIndex() {
|
||||
return this.items.findIndex(i => i.route === this.$route.name);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
isActive(item) {
|
||||
return this.items.indexOf(item) === this.activeIndex;
|
||||
},
|
||||
isOver(item) {
|
||||
return this.items.indexOf(item) < this.activeIndex;
|
||||
},
|
||||
<script setup>
|
||||
import { computed } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
const props = defineProps({
|
||||
items: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
});
|
||||
|
||||
const route = useRoute();
|
||||
|
||||
const activeIndex = computed(() => {
|
||||
return props.items.findIndex(i => i.route === route.name);
|
||||
});
|
||||
|
||||
const isActive = item => {
|
||||
return props.items.indexOf(item) === activeIndex.value;
|
||||
};
|
||||
|
||||
const isOver = item => {
|
||||
return props.items.indexOf(item) < activeIndex.value;
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<transition-group
|
||||
name="wizard-items"
|
||||
tag="div"
|
||||
class="wizard-box"
|
||||
:class="classObject"
|
||||
>
|
||||
<transition-group tag="div">
|
||||
<div
|
||||
v-for="item in items"
|
||||
v-for="(item, index) in items"
|
||||
:key="item.route"
|
||||
class="item"
|
||||
:class="{ active: isActive(item), over: isOver(item) }"
|
||||
class="cursor-pointer flex items-start gap-6 relative after:content-[''] after:absolute after:w-0.5 after:h-full after:top-5 ltr:after:left-4 rtl:after:right-4 before:content-[''] before:absolute before:w-0.5 before:h-4 before:top-0 before:left-4 rtl:before:right-4 last:after:hidden last:before:hidden"
|
||||
:class="
|
||||
isOver(item)
|
||||
? 'after:bg-n-blue-9 before:bg-n-blue-9'
|
||||
: 'after:bg-n-weak before:bg-n-weak'
|
||||
"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<h3
|
||||
class="text-n-slate-12 text-base font-medium pl-6 overflow-hidden whitespace-nowrap mt-0.5 text-ellipsis leading-tight"
|
||||
<div
|
||||
class="rounded-2xl flex-shrink-0 size-8 flex items-center justify-center left-2 outline outline-2 leading-4 z-10 top-5 bg-n-background"
|
||||
:class="
|
||||
isActive(item) || isOver(item) ? 'outline-n-blue-9' : 'outline-n-weak'
|
||||
"
|
||||
>
|
||||
<span
|
||||
class="text-xs font-bold"
|
||||
:class="
|
||||
isActive(item) || isOver(item)
|
||||
? 'text-n-blue-11'
|
||||
: 'text-n-slate-11'
|
||||
"
|
||||
>
|
||||
{{ item.title }}
|
||||
</h3>
|
||||
<span v-if="isOver(item)" class="mx-1 mt-0.5 text-n-teal-9">
|
||||
<fluent-icon icon="checkmark" />
|
||||
{{ index + 1 }}
|
||||
</span>
|
||||
</div>
|
||||
<span class="step">
|
||||
{{ items.indexOf(item) + 1 }}
|
||||
</span>
|
||||
<p class="pl-6 m-0 mt-1.5 text-sm text-n-slate-11">
|
||||
{{ item.body }}
|
||||
</p>
|
||||
<div class="flex flex-col items-start gap-1.5 pb-10 pt-1">
|
||||
<div class="flex items-center">
|
||||
<h3
|
||||
class="text-sm font-medium overflow-hidden whitespace-nowrap mt-0.5 text-ellipsis leading-tight"
|
||||
:class="
|
||||
isActive(item) || isOver(item)
|
||||
? 'text-n-blue-11'
|
||||
: 'text-n-slate-12'
|
||||
"
|
||||
>
|
||||
{{ item.title }}
|
||||
</h3>
|
||||
</div>
|
||||
<p class="m-0 mt-1.5 text-sm text-n-slate-11">
|
||||
{{ item.body }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</transition-group>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.wizard-box {
|
||||
.item {
|
||||
@apply cursor-pointer after:bg-n-slate-6 before:bg-n-slate-6 py-4 ltr:pr-4 rtl:pl-4 ltr:pl-6 rtl:pr-6 relative before:h-4 before:top-0 last:before:h-0 first:before:h-0 last:after:h-0 before:content-[''] before:absolute before:w-0.5 after:content-[''] after:h-full after:absolute after:top-5 after:w-0.5 rtl:after:left-6 rtl:before:left-6;
|
||||
|
||||
&.active {
|
||||
h3 {
|
||||
@apply text-n-blue-text dark:text-n-blue-text;
|
||||
}
|
||||
|
||||
.step {
|
||||
@apply bg-n-brand dark:bg-n-brand;
|
||||
}
|
||||
}
|
||||
|
||||
&.over {
|
||||
&::after {
|
||||
@apply bg-n-brand dark:bg-n-brand;
|
||||
}
|
||||
|
||||
.step {
|
||||
@apply bg-n-brand dark:bg-n-brand;
|
||||
}
|
||||
|
||||
& + .item {
|
||||
&::before {
|
||||
@apply bg-n-brand dark:bg-n-brand;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.step {
|
||||
@apply bg-n-slate-7 rounded-2xl font-medium w-4 left-4 leading-4 z-10 absolute text-center text-white dark:text-white text-xxs top-5;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,91 +1,87 @@
|
||||
<script>
|
||||
<script setup>
|
||||
import { computed } from 'vue';
|
||||
import ChannelSelector from '../ChannelSelector.vue';
|
||||
export default {
|
||||
components: { ChannelSelector },
|
||||
props: {
|
||||
channel: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
enabledFeatures: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
emits: ['channelItemClick'],
|
||||
computed: {
|
||||
hasFbConfigured() {
|
||||
return window.chatwootConfig?.fbAppId;
|
||||
},
|
||||
hasInstagramConfigured() {
|
||||
return window.chatwootConfig?.instagramAppId;
|
||||
},
|
||||
isActive() {
|
||||
const { key } = this.channel;
|
||||
if (Object.keys(this.enabledFeatures).length === 0) {
|
||||
return false;
|
||||
}
|
||||
if (key === 'website') {
|
||||
return this.enabledFeatures.channel_website;
|
||||
}
|
||||
if (key === 'facebook') {
|
||||
return this.enabledFeatures.channel_facebook && this.hasFbConfigured;
|
||||
}
|
||||
if (key === 'email') {
|
||||
return this.enabledFeatures.channel_email;
|
||||
}
|
||||
|
||||
if (key === 'instagram') {
|
||||
return (
|
||||
this.enabledFeatures.channel_instagram && this.hasInstagramConfigured
|
||||
);
|
||||
}
|
||||
|
||||
if (key === 'voice') {
|
||||
return this.enabledFeatures.channel_voice;
|
||||
}
|
||||
|
||||
return [
|
||||
'website',
|
||||
'twilio',
|
||||
'api',
|
||||
'whatsapp',
|
||||
'sms',
|
||||
'telegram',
|
||||
'line',
|
||||
'instagram',
|
||||
'voice',
|
||||
].includes(key);
|
||||
},
|
||||
isComingSoon() {
|
||||
const { key } = this.channel;
|
||||
// Show "Coming Soon" only if the channel is marked as coming soon
|
||||
// and the corresponding feature flag is not enabled yet.
|
||||
return ['voice'].includes(key) && !this.isActive;
|
||||
},
|
||||
const props = defineProps({
|
||||
channel: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
methods: {
|
||||
getChannelThumbnail() {
|
||||
if (this.channel.key === 'api' && this.channel.thumbnail) {
|
||||
return this.channel.thumbnail;
|
||||
}
|
||||
return `/assets/images/dashboard/channels/${this.channel.key}.png`;
|
||||
},
|
||||
onItemClick() {
|
||||
if (this.isActive) {
|
||||
this.$emit('channelItemClick', this.channel.key);
|
||||
}
|
||||
},
|
||||
enabledFeatures: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['channelItemClick']);
|
||||
|
||||
const hasFbConfigured = computed(() => {
|
||||
return window.chatwootConfig?.fbAppId;
|
||||
});
|
||||
|
||||
const hasInstagramConfigured = computed(() => {
|
||||
return window.chatwootConfig?.instagramAppId;
|
||||
});
|
||||
|
||||
const isActive = computed(() => {
|
||||
const { key } = props.channel;
|
||||
if (Object.keys(props.enabledFeatures).length === 0) {
|
||||
return false;
|
||||
}
|
||||
if (key === 'website') {
|
||||
return props.enabledFeatures.channel_website;
|
||||
}
|
||||
if (key === 'facebook') {
|
||||
return props.enabledFeatures.channel_facebook && hasFbConfigured.value;
|
||||
}
|
||||
if (key === 'email') {
|
||||
return props.enabledFeatures.channel_email;
|
||||
}
|
||||
|
||||
if (key === 'instagram') {
|
||||
return (
|
||||
props.enabledFeatures.channel_instagram && hasInstagramConfigured.value
|
||||
);
|
||||
}
|
||||
|
||||
if (key === 'voice') {
|
||||
return props.enabledFeatures.channel_voice;
|
||||
}
|
||||
|
||||
return [
|
||||
'website',
|
||||
'twilio',
|
||||
'api',
|
||||
'whatsapp',
|
||||
'sms',
|
||||
'telegram',
|
||||
'line',
|
||||
'instagram',
|
||||
'voice',
|
||||
].includes(key);
|
||||
});
|
||||
|
||||
const isComingSoon = computed(() => {
|
||||
const { key } = props.channel;
|
||||
// Show "Coming Soon" only if the channel is marked as coming soon
|
||||
// and the corresponding feature flag is not enabled yet.
|
||||
return ['voice'].includes(key) && !isActive.value;
|
||||
});
|
||||
|
||||
const onItemClick = () => {
|
||||
if (isActive.value) {
|
||||
emit('channelItemClick', props.channel.key);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ChannelSelector
|
||||
:class="{ inactive: !isActive }"
|
||||
:title="channel.name"
|
||||
:src="getChannelThumbnail()"
|
||||
:title="channel.title"
|
||||
:description="channel.description"
|
||||
:icon="channel.icon"
|
||||
:is-coming-soon="isComingSoon"
|
||||
:disabled="!isActive"
|
||||
@click="onItemClick"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -13,7 +13,7 @@ defineProps({
|
||||
<div class="flex items-center text-n-slate-11 text-xs min-w-0">
|
||||
<ChannelIcon
|
||||
:inbox="inbox"
|
||||
class="size-3 ltr:mr-0.5 rtl:ml-0.5 flex-shrink-0"
|
||||
class="size-3 ltr:mr-1 rtl:ml-1 flex-shrink-0"
|
||||
/>
|
||||
<span class="truncate">
|
||||
{{ inbox.name }}
|
||||
|
||||
@@ -250,7 +250,6 @@ const deleteConversation = () => {
|
||||
:src="currentContact.thumbnail"
|
||||
:size="32"
|
||||
:status="currentContact.availability_status"
|
||||
:inbox="inbox"
|
||||
:class="!showInboxName ? 'mt-4' : 'mt-8'"
|
||||
hide-offline-status
|
||||
rounded-full
|
||||
|
||||
@@ -424,7 +424,51 @@
|
||||
},
|
||||
"AUTH": {
|
||||
"TITLE": "Choose a channel",
|
||||
"DESC": "Chatwoot supports live-chat widgets, Facebook Messenger, WhatsApp, Emails, etc., as channels. If you want to build a custom channel, you can create it using the API channel. To get started, choose one of the channels below."
|
||||
"DESC": "Chatwoot supports live-chat widgets, Facebook Messenger, WhatsApp, Emails, etc., as channels. If you want to build a custom channel, you can create it using the API channel. To get started, choose one of the channels below.",
|
||||
"TITLE_NEXT": "Complete the setup",
|
||||
"TITLE_FINISH": "Voilà!",
|
||||
"CHANNEL": {
|
||||
"WEBSITE": {
|
||||
"TITLE": "Website",
|
||||
"DESCRIPTION": "Create a live-chat widget"
|
||||
},
|
||||
"FACEBOOK": {
|
||||
"TITLE": "Facebook",
|
||||
"DESCRIPTION": "Connect your Facebook page"
|
||||
},
|
||||
"WHATSAPP": {
|
||||
"TITLE": "WhatsApp",
|
||||
"DESCRIPTION": "Support your customers on WhatsApp"
|
||||
},
|
||||
"EMAIL": {
|
||||
"TITLE": "Email",
|
||||
"DESCRIPTION": "Connect with Gmail, Outlook, or other providers"
|
||||
},
|
||||
"SMS": {
|
||||
"TITLE": "SMS",
|
||||
"DESCRIPTION": "Integrate SMS channel with Twilio or bandwidth"
|
||||
},
|
||||
"API": {
|
||||
"TITLE": "API",
|
||||
"DESCRIPTION": "Make a custom channel using our API"
|
||||
},
|
||||
"TELEGRAM": {
|
||||
"TITLE": "Telegram",
|
||||
"DESCRIPTION": "Configure Telegram channel using Bot token"
|
||||
},
|
||||
"LINE": {
|
||||
"TITLE": "Line",
|
||||
"DESCRIPTION": "Integrate your Line channel"
|
||||
},
|
||||
"INSTAGRAM": {
|
||||
"TITLE": "Instagram",
|
||||
"DESCRIPTION": "Connect your instagram account"
|
||||
},
|
||||
"VOICE": {
|
||||
"TITLE": "Voice",
|
||||
"DESCRIPTION": "Integrate with Twilio Voice"
|
||||
}
|
||||
}
|
||||
},
|
||||
"AGENTS": {
|
||||
"TITLE": "Agents",
|
||||
@@ -871,9 +915,18 @@
|
||||
"SCRIPT_SETTINGS": "\n window.chatwootSettings = {options};"
|
||||
},
|
||||
"EMAIL_PROVIDERS": {
|
||||
"MICROSOFT": "Microsoft",
|
||||
"GOOGLE": "Google",
|
||||
"OTHER_PROVIDERS": "Other Providers"
|
||||
"MICROSOFT": {
|
||||
"TITLE": "Microsoft",
|
||||
"DESCRIPTION": "Connect with Microsoft"
|
||||
},
|
||||
"GOOGLE": {
|
||||
"TITLE": "Google",
|
||||
"DESCRIPTION": "Connect with Google"
|
||||
},
|
||||
"OTHER_PROVIDERS": {
|
||||
"TITLE": "Other Providers",
|
||||
"DESCRIPTION": "Connect with Other Providers"
|
||||
}
|
||||
},
|
||||
"CHANNELS": {
|
||||
"MESSENGER": "Messenger",
|
||||
|
||||
@@ -63,9 +63,7 @@ export default {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="border border-n-weak bg-n-solid-1 rounded-t-lg border-b-0 h-full w-full p-6 col-span-6 overflow-auto"
|
||||
>
|
||||
<div class="h-full w-full p-6 col-span-6">
|
||||
<form class="flex flex-wrap flex-col mx-0" @submit.prevent="addAgents()">
|
||||
<div class="w-full">
|
||||
<PageHeader
|
||||
|
||||
@@ -1,83 +1,108 @@
|
||||
<script>
|
||||
import ChannelItem from 'dashboard/components/widgets/ChannelItem.vue';
|
||||
import router from '../../../index';
|
||||
import PageHeader from '../SettingsSubPageHeader.vue';
|
||||
import { mapGetters } from 'vuex';
|
||||
import { useBranding } from 'shared/composables/useBranding';
|
||||
<script setup>
|
||||
import { ref, computed, onMounted } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useMapGetter } from 'dashboard/composables/store';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ChannelItem,
|
||||
PageHeader,
|
||||
},
|
||||
setup() {
|
||||
const { replaceInstallationName } = useBranding();
|
||||
return {
|
||||
replaceInstallationName,
|
||||
};
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
enabledFeatures: {},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
account() {
|
||||
return this.$store.getters['accounts/getAccount'](this.accountId);
|
||||
import { useAccount } from 'dashboard/composables/useAccount';
|
||||
|
||||
import ChannelItem from 'dashboard/components/widgets/ChannelItem.vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
const router = useRouter();
|
||||
const { accountId, currentAccount } = useAccount();
|
||||
|
||||
const globalConfig = useMapGetter('globalConfig/get');
|
||||
|
||||
const enabledFeatures = ref({});
|
||||
|
||||
const channelList = computed(() => {
|
||||
const { apiChannelName } = globalConfig.value;
|
||||
return [
|
||||
{
|
||||
key: 'website',
|
||||
title: t('INBOX_MGMT.ADD.AUTH.CHANNEL.WEBSITE.TITLE'),
|
||||
description: t('INBOX_MGMT.ADD.AUTH.CHANNEL.WEBSITE.DESCRIPTION'),
|
||||
icon: 'i-woot-website',
|
||||
},
|
||||
channelList() {
|
||||
const { apiChannelName, apiChannelThumbnail } = this.globalConfig;
|
||||
return [
|
||||
{ key: 'website', name: 'Website' },
|
||||
{ key: 'facebook', name: 'Messenger' },
|
||||
{ key: 'whatsapp', name: 'WhatsApp' },
|
||||
{ key: 'sms', name: 'SMS' },
|
||||
{ key: 'email', name: 'Email' },
|
||||
{
|
||||
key: 'api',
|
||||
name: apiChannelName || 'API',
|
||||
thumbnail: apiChannelThumbnail,
|
||||
},
|
||||
{ key: 'telegram', name: 'Telegram' },
|
||||
{ key: 'line', name: 'Line' },
|
||||
{ key: 'instagram', name: 'Instagram' },
|
||||
{ key: 'voice', name: 'Voice' },
|
||||
];
|
||||
{
|
||||
key: 'facebook',
|
||||
title: t('INBOX_MGMT.ADD.AUTH.CHANNEL.FACEBOOK.TITLE'),
|
||||
description: t('INBOX_MGMT.ADD.AUTH.CHANNEL.FACEBOOK.DESCRIPTION'),
|
||||
icon: 'i-woot-messenger',
|
||||
},
|
||||
...mapGetters({
|
||||
accountId: 'getCurrentAccountId',
|
||||
globalConfig: 'globalConfig/get',
|
||||
}),
|
||||
},
|
||||
mounted() {
|
||||
this.initializeEnabledFeatures();
|
||||
},
|
||||
methods: {
|
||||
async initializeEnabledFeatures() {
|
||||
this.enabledFeatures = this.account.features;
|
||||
{
|
||||
key: 'whatsapp',
|
||||
title: t('INBOX_MGMT.ADD.AUTH.CHANNEL.WHATSAPP.TITLE'),
|
||||
description: t('INBOX_MGMT.ADD.AUTH.CHANNEL.WHATSAPP.DESCRIPTION'),
|
||||
icon: 'i-woot-whatsapp',
|
||||
},
|
||||
initChannelAuth(channel) {
|
||||
const params = {
|
||||
sub_page: channel,
|
||||
accountId: this.accountId,
|
||||
};
|
||||
router.push({ name: 'settings_inboxes_page_channel', params });
|
||||
{
|
||||
key: 'sms',
|
||||
title: t('INBOX_MGMT.ADD.AUTH.CHANNEL.SMS.TITLE'),
|
||||
description: t('INBOX_MGMT.ADD.AUTH.CHANNEL.SMS.DESCRIPTION'),
|
||||
icon: 'i-woot-sms',
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'email',
|
||||
title: t('INBOX_MGMT.ADD.AUTH.CHANNEL.EMAIL.TITLE'),
|
||||
description: t('INBOX_MGMT.ADD.AUTH.CHANNEL.EMAIL.DESCRIPTION'),
|
||||
icon: 'i-woot-mail',
|
||||
},
|
||||
{
|
||||
key: 'api',
|
||||
title: apiChannelName || t('INBOX_MGMT.ADD.AUTH.CHANNEL.API.TITLE'),
|
||||
description: t('INBOX_MGMT.ADD.AUTH.CHANNEL.API.DESCRIPTION'),
|
||||
icon: 'i-woot-api',
|
||||
},
|
||||
{
|
||||
key: 'telegram',
|
||||
title: t('INBOX_MGMT.ADD.AUTH.CHANNEL.TELEGRAM.TITLE'),
|
||||
description: t('INBOX_MGMT.ADD.AUTH.CHANNEL.TELEGRAM.DESCRIPTION'),
|
||||
icon: 'i-woot-telegram',
|
||||
},
|
||||
{
|
||||
key: 'line',
|
||||
title: t('INBOX_MGMT.ADD.AUTH.CHANNEL.LINE.TITLE'),
|
||||
description: t('INBOX_MGMT.ADD.AUTH.CHANNEL.LINE.DESCRIPTION'),
|
||||
icon: 'i-woot-line',
|
||||
},
|
||||
{
|
||||
key: 'instagram',
|
||||
title: t('INBOX_MGMT.ADD.AUTH.CHANNEL.INSTAGRAM.TITLE'),
|
||||
description: t('INBOX_MGMT.ADD.AUTH.CHANNEL.INSTAGRAM.DESCRIPTION'),
|
||||
icon: 'i-woot-instagram',
|
||||
},
|
||||
{
|
||||
key: 'voice',
|
||||
title: t('INBOX_MGMT.ADD.AUTH.CHANNEL.VOICE.TITLE'),
|
||||
description: t('INBOX_MGMT.ADD.AUTH.CHANNEL.VOICE.DESCRIPTION'),
|
||||
icon: 'i-ri-phone-fill',
|
||||
},
|
||||
];
|
||||
});
|
||||
|
||||
const initializeEnabledFeatures = async () => {
|
||||
enabledFeatures.value = currentAccount.value.features;
|
||||
};
|
||||
|
||||
const initChannelAuth = channel => {
|
||||
const params = {
|
||||
sub_page: channel,
|
||||
accountId: accountId.value,
|
||||
};
|
||||
router.push({ name: 'settings_inboxes_page_channel', params });
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
initializeEnabledFeatures();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="w-full h-full col-span-6 p-6 overflow-auto border border-b-0 rounded-t-lg border-n-weak bg-n-solid-1"
|
||||
>
|
||||
<PageHeader
|
||||
class="max-w-4xl"
|
||||
:header-title="$t('INBOX_MGMT.ADD.AUTH.TITLE')"
|
||||
:header-content="replaceInstallationName($t('INBOX_MGMT.ADD.AUTH.DESC'))"
|
||||
/>
|
||||
<div class="w-full p-8 overflow-auto">
|
||||
<div
|
||||
class="grid max-w-3xl grid-cols-2 mx-0 mt-6 sm:grid-cols-3 lg:grid-cols-4"
|
||||
class="grid max-w-3xl grid-cols-1 xs:grid-cols-2 mx-0 gap-6 sm:grid-cols-3"
|
||||
>
|
||||
<ChannelItem
|
||||
v-for="channel in channelList"
|
||||
|
||||
@@ -168,9 +168,7 @@ onMounted(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="overflow-auto col-span-6 p-6 w-full h-full rounded-t-lg border border-b-0 border-n-weak bg-n-solid-1"
|
||||
>
|
||||
<div class="w-full h-full col-span-6 p-6 overflow-auto">
|
||||
<DuplicateInboxBanner
|
||||
v-if="hasDuplicateInstagramInbox"
|
||||
:content="$t('INBOX_MGMT.ADD.INSTAGRAM.NEW_INBOX_SUGGESTION')"
|
||||
|
||||
@@ -1,55 +1,106 @@
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
<script setup>
|
||||
import { computed } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useMapGetter } from 'dashboard/composables/store';
|
||||
import { useBranding } from 'shared/composables/useBranding';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const { replaceInstallationName } = useBranding();
|
||||
import PageHeader from '../SettingsSubPageHeader.vue';
|
||||
import Icon from 'next/icon/Icon.vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
const route = useRoute();
|
||||
const { replaceInstallationName } = useBranding();
|
||||
|
||||
const globalConfig = useMapGetter('globalConfig/get');
|
||||
|
||||
const ALL_CHANNEL_ICONS = [
|
||||
'i-woot-line',
|
||||
'i-woot-facebook',
|
||||
'i-woot-whatsapp',
|
||||
'i-woot-instagram',
|
||||
'i-woot-messenger',
|
||||
'i-woot-website',
|
||||
'i-woot-mail',
|
||||
'i-woot-sms',
|
||||
'i-woot-telegram',
|
||||
'i-woot-api',
|
||||
'i-woot-twilio',
|
||||
'i-woot-gmail',
|
||||
'i-woot-outlook',
|
||||
];
|
||||
|
||||
const createFlowSteps = computed(() => {
|
||||
const steps = ['CHANNEL', 'INBOX', 'AGENT', 'FINISH'];
|
||||
|
||||
const routes = {
|
||||
CHANNEL: 'settings_inbox_new',
|
||||
INBOX: 'settings_inboxes_page_channel',
|
||||
AGENT: 'settings_inboxes_add_agents',
|
||||
FINISH: 'settings_inbox_finish',
|
||||
};
|
||||
|
||||
return steps.map(step => {
|
||||
return {
|
||||
replaceInstallationName,
|
||||
title: t(`INBOX_MGMT.CREATE_FLOW.${step}.TITLE`),
|
||||
body: t(`INBOX_MGMT.CREATE_FLOW.${step}.BODY`),
|
||||
route: routes[step],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
globalConfig: 'globalConfig/get',
|
||||
}),
|
||||
createFlowSteps() {
|
||||
const steps = ['CHANNEL', 'INBOX', 'AGENT', 'FINISH'];
|
||||
});
|
||||
});
|
||||
|
||||
const routes = {
|
||||
CHANNEL: 'settings_inbox_new',
|
||||
INBOX: 'settings_inboxes_page_channel',
|
||||
AGENT: 'settings_inboxes_add_agents',
|
||||
FINISH: 'settings_inbox_finish',
|
||||
};
|
||||
const isFirstStep = computed(() => {
|
||||
return route.name === 'settings_inbox_new';
|
||||
});
|
||||
|
||||
return steps.map(step => {
|
||||
return {
|
||||
title: this.$t(`INBOX_MGMT.CREATE_FLOW.${step}.TITLE`),
|
||||
body: this.$t(`INBOX_MGMT.CREATE_FLOW.${step}.BODY`),
|
||||
route: routes[step],
|
||||
};
|
||||
});
|
||||
},
|
||||
items() {
|
||||
return this.createFlowSteps.map(item => ({
|
||||
...item,
|
||||
body: this.replaceInstallationName(item.body),
|
||||
}));
|
||||
},
|
||||
},
|
||||
};
|
||||
const isFinishStep = computed(() => {
|
||||
return route.name === 'settings_inbox_finish';
|
||||
});
|
||||
|
||||
const pageTitle = computed(() => {
|
||||
if (isFirstStep.value) {
|
||||
return t('INBOX_MGMT.ADD.AUTH.TITLE');
|
||||
}
|
||||
if (isFinishStep.value) {
|
||||
return t('INBOX_MGMT.ADD.AUTH.TITLE_FINISH');
|
||||
}
|
||||
return t('INBOX_MGMT.ADD.AUTH.TITLE_NEXT');
|
||||
});
|
||||
|
||||
const items = computed(() => {
|
||||
return createFlowSteps.value.map(item => ({
|
||||
...item,
|
||||
body: replaceInstallationName(item.body),
|
||||
}));
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="grid grid-cols-1 md:grid-cols-8 overflow-auto h-full">
|
||||
<woot-wizard
|
||||
class="hidden md:block col-span-2"
|
||||
:global-config="globalConfig"
|
||||
:items="items"
|
||||
/>
|
||||
<div class="col-span-6">
|
||||
<router-view />
|
||||
<div class="mx-2 flex flex-col gap-6 mb-8">
|
||||
<PageHeader class="block lg:hidden !mb-0" :header-title="pageTitle" />
|
||||
<div class="hidden lg:grid grid-cols-1 lg:grid-cols-8 items-center gap-2">
|
||||
<div class="col-span-2 w-full" />
|
||||
<div class="flex items-center gap-2 col-span-6 ltr:ml-8 rtl:mr-8">
|
||||
<div
|
||||
v-for="icon in ALL_CHANNEL_ICONS"
|
||||
:key="icon"
|
||||
class="size-8 bg-n-alpha-2 flex items-center flex-shrink-0 justify-center rounded-full"
|
||||
>
|
||||
<Icon :icon="icon" class="size-4 text-n-slate-10" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="grid grid-cols-1 lg:grid-cols-8 lg:divide-x lg:divide-n-weak rounded-xl border border-n-weak min-h-[52rem]"
|
||||
>
|
||||
<woot-wizard
|
||||
class="hidden lg:block col-span-2 h-fit py-8 px-6"
|
||||
:global-config="globalConfig"
|
||||
:items="items"
|
||||
/>
|
||||
<div class="col-span-6 overflow-hidden">
|
||||
<router-view />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -116,7 +116,7 @@ const openDelete = inbox => {
|
||||
v-else
|
||||
class="size-12 flex justify-center items-center bg-n-alpha-3 rounded-full p-2 ring ring-n-solid-1 border border-n-strong shadow-sm"
|
||||
>
|
||||
<ChannelIcon class="size-5" :inbox="inbox" />
|
||||
<ChannelIcon class="size-5 text-n-slate-10" :inbox="inbox" />
|
||||
</div>
|
||||
<div>
|
||||
<span class="block font-medium capitalize">
|
||||
|
||||
@@ -65,9 +65,7 @@ export default {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="border border-n-weak bg-n-solid-1 rounded-t-lg border-b-0 h-full w-full p-6 col-span-6 overflow-auto"
|
||||
>
|
||||
<div class="h-full w-full p-6 col-span-6">
|
||||
<PageHeader
|
||||
:header-title="$t('INBOX_MGMT.ADD.API_CHANNEL.TITLE')"
|
||||
:header-content="$t('INBOX_MGMT.ADD.API_CHANNEL.DESC')"
|
||||
|
||||
@@ -20,22 +20,25 @@ const isAChatwootInstance = getters['globalConfig/isAChatwootInstance'];
|
||||
const emailProviderList = computed(() => {
|
||||
return [
|
||||
{
|
||||
title: t('INBOX_MGMT.EMAIL_PROVIDERS.MICROSOFT'),
|
||||
title: t('INBOX_MGMT.EMAIL_PROVIDERS.MICROSOFT.TITLE'),
|
||||
description: t('INBOX_MGMT.EMAIL_PROVIDERS.MICROSOFT.DESCRIPTION'),
|
||||
isEnabled: !!globalConfig.value.azureAppId,
|
||||
key: 'microsoft',
|
||||
src: '/assets/images/dashboard/channels/microsoft.png',
|
||||
icon: 'i-woot-outlook',
|
||||
},
|
||||
{
|
||||
title: t('INBOX_MGMT.EMAIL_PROVIDERS.GOOGLE'),
|
||||
title: t('INBOX_MGMT.EMAIL_PROVIDERS.GOOGLE.TITLE'),
|
||||
description: t('INBOX_MGMT.EMAIL_PROVIDERS.GOOGLE.DESCRIPTION'),
|
||||
isEnabled: !!window.chatwootConfig.googleOAuthClientId,
|
||||
key: 'google',
|
||||
src: '/assets/images/dashboard/channels/google.png',
|
||||
icon: 'i-woot-gmail',
|
||||
},
|
||||
{
|
||||
title: t('INBOX_MGMT.EMAIL_PROVIDERS.OTHER_PROVIDERS'),
|
||||
title: t('INBOX_MGMT.EMAIL_PROVIDERS.OTHER_PROVIDERS.TITLE'),
|
||||
description: t('INBOX_MGMT.EMAIL_PROVIDERS.OTHER_PROVIDERS.DESCRIPTION'),
|
||||
isEnabled: true,
|
||||
key: 'other_provider',
|
||||
src: '/assets/images/dashboard/channels/email.png',
|
||||
icon: 'i-woot-mail',
|
||||
},
|
||||
].filter(providerConfig => {
|
||||
if (isAChatwootInstance.value) {
|
||||
@@ -53,22 +56,20 @@ function onClick(emailProvider) {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
v-if="!provider"
|
||||
class="border border-n-weak bg-n-solid-1 rounded-t-lg border-b-0 h-full w-full p-6 col-span-6 overflow-auto"
|
||||
>
|
||||
<div v-if="!provider" class="h-full w-full p-6 col-span-6">
|
||||
<PageHeader
|
||||
class="max-w-4xl"
|
||||
:header-title="$t('INBOX_MGMT.ADD.EMAIL_PROVIDER.TITLE')"
|
||||
:header-content="$t('INBOX_MGMT.ADD.EMAIL_PROVIDER.DESCRIPTION')"
|
||||
/>
|
||||
<div class="grid max-w-3xl grid-cols-4 mx-0 mt-6">
|
||||
<div class="grid max-w-3xl grid-cols-4 gap-6 mx-0 mt-6">
|
||||
<ChannelSelector
|
||||
v-for="emailProvider in emailProviderList"
|
||||
:key="emailProvider.key"
|
||||
:class="{ inactive: !emailProvider.isEnabled }"
|
||||
:title="emailProvider.title"
|
||||
:src="emailProvider.src"
|
||||
:description="emailProvider.description"
|
||||
:icon="emailProvider.icon"
|
||||
:disabled="!emailProvider.isEnabled"
|
||||
@click="() => onClick(emailProvider)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -206,16 +206,14 @@ export default {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="w-full h-full col-span-6 p-6 overflow-auto border border-b-0 rounded-t-lg border-n-weak bg-n-solid-1"
|
||||
>
|
||||
<div class="w-full h-full col-span-6 p-6 overflow-auto">
|
||||
<div
|
||||
v-if="!hasLoginStarted"
|
||||
class="flex flex-col items-center justify-center h-full text-center"
|
||||
>
|
||||
<a href="#" @click="startLogin()">
|
||||
<img
|
||||
class="w-auto h-10"
|
||||
class="w-auto h-10 rounded-md"
|
||||
src="~dashboard/assets/images/channels/facebook_login.png"
|
||||
alt="Facebook-logo"
|
||||
/>
|
||||
|
||||
@@ -71,9 +71,7 @@ export default {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="border border-n-weak bg-n-solid-1 rounded-t-lg border-b-0 h-full w-full p-6 col-span-6 overflow-auto"
|
||||
>
|
||||
<div class="h-full w-full p-6 col-span-6">
|
||||
<PageHeader
|
||||
:header-title="$t('INBOX_MGMT.ADD.LINE_CHANNEL.TITLE')"
|
||||
:header-content="$t('INBOX_MGMT.ADD.LINE_CHANNEL.DESC')"
|
||||
|
||||
@@ -18,9 +18,7 @@ export default {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="border border-n-weak bg-n-solid-1 rounded-t-lg border-b-0 h-full w-full p-6 col-span-6 overflow-auto"
|
||||
>
|
||||
<div class="h-full w-full p-6 col-span-6">
|
||||
<PageHeader
|
||||
:header-title="$t('INBOX_MGMT.ADD.SMS.TITLE')"
|
||||
:header-content="$t('INBOX_MGMT.ADD.SMS.DESC')"
|
||||
|
||||
@@ -65,9 +65,7 @@ export default {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="border border-n-weak bg-n-solid-1 rounded-t-lg border-b-0 h-full w-full p-6 col-span-6 overflow-auto"
|
||||
>
|
||||
<div class="h-full w-full p-6 col-span-6">
|
||||
<PageHeader
|
||||
:header-title="$t('INBOX_MGMT.ADD.TELEGRAM_CHANNEL.TITLE')"
|
||||
:header-content="$t('INBOX_MGMT.ADD.TELEGRAM_CHANNEL.DESC')"
|
||||
|
||||
@@ -30,9 +30,7 @@ export default {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="border border-n-weak bg-n-solid-1 rounded-t-lg border-b-0 h-full w-full p-6 col-span-6 overflow-auto"
|
||||
>
|
||||
<div class="h-full w-full p-6 col-span-6">
|
||||
<div class="login-init h-full text-center">
|
||||
<form @submit.prevent="requestAuthorization">
|
||||
<NextButton
|
||||
|
||||
@@ -93,9 +93,7 @@ async function createChannel() {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="overflow-auto col-span-6 p-6 w-full h-full rounded-t-lg border border-b-0 border-n-weak bg-n-solid-1"
|
||||
>
|
||||
<div class="overflow-auto col-span-6 p-6 w-full h-full">
|
||||
<PageHeader
|
||||
:header-title="t('INBOX_MGMT.ADD.VOICE.TITLE')"
|
||||
:header-content="t('INBOX_MGMT.ADD.VOICE.DESC')"
|
||||
|
||||
@@ -78,9 +78,7 @@ export default {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="border border-n-weak bg-n-solid-1 rounded-t-lg border-b-0 h-full w-full p-6 col-span-6 overflow-auto"
|
||||
>
|
||||
<div class="h-full w-full p-6 col-span-6">
|
||||
<PageHeader
|
||||
:header-title="$t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.TITLE')"
|
||||
:header-content="$t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.DESC')"
|
||||
|
||||
@@ -7,6 +7,7 @@ import Twilio from './Twilio.vue';
|
||||
import ThreeSixtyDialogWhatsapp from './360DialogWhatsapp.vue';
|
||||
import CloudWhatsapp from './CloudWhatsapp.vue';
|
||||
import WhatsappEmbeddedSignup from './WhatsappEmbeddedSignup.vue';
|
||||
import ChannelSelector from 'dashboard/components/ChannelSelector.vue';
|
||||
import { FEATURE_FLAGS } from 'dashboard/featureFlags';
|
||||
|
||||
const route = useRoute();
|
||||
@@ -45,16 +46,16 @@ const showConfiguration = computed(() => Boolean(selectedProvider.value));
|
||||
|
||||
const availableProviders = computed(() => [
|
||||
{
|
||||
value: PROVIDER_TYPES.WHATSAPP,
|
||||
label: t('INBOX_MGMT.ADD.WHATSAPP.PROVIDERS.WHATSAPP_CLOUD'),
|
||||
key: PROVIDER_TYPES.WHATSAPP,
|
||||
title: t('INBOX_MGMT.ADD.WHATSAPP.PROVIDERS.WHATSAPP_CLOUD'),
|
||||
description: t('INBOX_MGMT.ADD.WHATSAPP.PROVIDERS.WHATSAPP_CLOUD_DESC'),
|
||||
icon: '/assets/images/dashboard/channels/whatsapp.png',
|
||||
icon: 'i-woot-whatsapp',
|
||||
},
|
||||
{
|
||||
value: PROVIDER_TYPES.TWILIO,
|
||||
label: t('INBOX_MGMT.ADD.WHATSAPP.PROVIDERS.TWILIO'),
|
||||
key: PROVIDER_TYPES.TWILIO,
|
||||
title: t('INBOX_MGMT.ADD.WHATSAPP.PROVIDERS.TWILIO'),
|
||||
description: t('INBOX_MGMT.ADD.WHATSAPP.PROVIDERS.TWILIO_DESC'),
|
||||
icon: '/assets/images/dashboard/channels/twilio.png',
|
||||
icon: 'i-woot-twilio',
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -92,9 +93,7 @@ const shouldShowCloudWhatsapp = provider => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="overflow-auto col-span-6 p-6 w-full h-full rounded-t-lg border border-b-0 border-n-weak bg-n-solid-1"
|
||||
>
|
||||
<div class="overflow-auto col-span-6 p-6 w-full h-full">
|
||||
<div v-if="showProviderSelection">
|
||||
<div class="mb-10 text-left">
|
||||
<h1 class="mb-2 text-lg font-medium text-slate-12">
|
||||
@@ -106,51 +105,30 @@ const shouldShowCloudWhatsapp = provider => {
|
||||
</div>
|
||||
|
||||
<div class="flex gap-6 justify-start">
|
||||
<div
|
||||
<ChannelSelector
|
||||
v-for="provider in availableProviders"
|
||||
:key="provider.value"
|
||||
class="gap-6 px-5 py-6 w-96 rounded-2xl border transition-all duration-200 cursor-pointer border-n-weak hover:bg-n-slate-3"
|
||||
@click="selectProvider(provider.value)"
|
||||
>
|
||||
<div class="flex justify-start mb-5">
|
||||
<div
|
||||
class="flex justify-center items-center rounded-full size-10 bg-n-alpha-2"
|
||||
>
|
||||
<img
|
||||
:src="provider.icon"
|
||||
:alt="provider.label"
|
||||
class="object-contain size-[26px]"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-start">
|
||||
<h3 class="mb-1.5 text-sm font-medium text-slate-12">
|
||||
{{ provider.label }}
|
||||
</h3>
|
||||
<p class="text-sm text-slate-11">
|
||||
{{ provider.description }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
:key="provider.key"
|
||||
:title="provider.title"
|
||||
:description="provider.description"
|
||||
:icon="provider.icon"
|
||||
@click="selectProvider(provider.key)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else-if="showConfiguration">
|
||||
<div class="px-6 py-5 rounded-2xl border bg-n-solid-2 border-n-weak">
|
||||
<WhatsappEmbeddedSignup
|
||||
v-if="shouldShowEmbeddedSignup(selectedProvider)"
|
||||
/>
|
||||
<CloudWhatsapp v-else-if="shouldShowCloudWhatsapp(selectedProvider)" />
|
||||
<Twilio
|
||||
v-else-if="selectedProvider === PROVIDER_TYPES.TWILIO"
|
||||
type="whatsapp"
|
||||
/>
|
||||
<ThreeSixtyDialogWhatsapp
|
||||
v-else-if="selectedProvider === PROVIDER_TYPES.THREE_SIXTY_DIALOG"
|
||||
/>
|
||||
<CloudWhatsapp v-else />
|
||||
</div>
|
||||
<WhatsappEmbeddedSignup
|
||||
v-if="shouldShowEmbeddedSignup(selectedProvider)"
|
||||
/>
|
||||
<CloudWhatsapp v-else-if="shouldShowCloudWhatsapp(selectedProvider)" />
|
||||
<Twilio
|
||||
v-else-if="selectedProvider === PROVIDER_TYPES.TWILIO"
|
||||
type="whatsapp"
|
||||
/>
|
||||
<ThreeSixtyDialogWhatsapp
|
||||
v-else-if="selectedProvider === PROVIDER_TYPES.THREE_SIXTY_DIALOG"
|
||||
/>
|
||||
<CloudWhatsapp v-else />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -70,9 +70,7 @@ export default {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="border border-n-weak bg-n-solid-1 rounded-t-lg border-b-0 h-full w-full p-6 col-span-6 overflow-auto"
|
||||
>
|
||||
<div class="h-full w-full p-6 col-span-6">
|
||||
<PageHeader
|
||||
:header-title="$t('INBOX_MGMT.ADD.EMAIL_CHANNEL.TITLE')"
|
||||
:header-content="$t('INBOX_MGMT.ADD.EMAIL_CHANNEL.DESC')"
|
||||
|
||||
@@ -60,9 +60,7 @@ async function requestAuthorization() {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="border border-n-weak bg-n-solid-1 rounded-t-lg border-b-0 h-full w-full p-6 col-span-6 overflow-auto"
|
||||
>
|
||||
<div class="h-full w-full p-6 col-span-6">
|
||||
<SettingsSubPageHeader
|
||||
:header-title="title"
|
||||
:header-content="description"
|
||||
|
||||
@@ -88,9 +88,7 @@ export default {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="border border-n-weak bg-n-solid-1 rounded-t-lg border-b-0 h-full w-full p-6 col-span-6 overflow-auto"
|
||||
>
|
||||
<div class="h-full w-full p-6 col-span-6">
|
||||
<form
|
||||
class="flex flex-wrap mx-0 overflow-x-auto"
|
||||
@submit.prevent="addAgents"
|
||||
|
||||
@@ -37,9 +37,7 @@ export default {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="border border-n-weak bg-n-solid-1 rounded-t-lg border-b-0 h-full w-full p-6 col-span-6 overflow-auto"
|
||||
>
|
||||
<div class="h-full w-full p-6 col-span-6">
|
||||
<PageHeader
|
||||
:header-title="$t('TEAMS_SETTINGS.CREATE_FLOW.CREATE.TITLE')"
|
||||
:header-content="$t('TEAMS_SETTINGS.CREATE_FLOW.CREATE.DESC')"
|
||||
|
||||
@@ -23,8 +23,15 @@ export default {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="grid grid-cols-1 md:grid-cols-8 overflow-auto h-full px-5 flex-1">
|
||||
<woot-wizard class="hidden md:block col-span-2" :items="items" />
|
||||
<router-view />
|
||||
<div class="mx-2 flex flex-col gap-6 mb-8">
|
||||
<div
|
||||
class="grid grid-cols-1 lg:grid-cols-8 lg:divide-x lg:divide-n-weak rounded-xl border border-n-weak min-h-[43rem]"
|
||||
>
|
||||
<woot-wizard
|
||||
class="hidden lg:block col-span-2 h-fit py-8 px-6"
|
||||
:items="items"
|
||||
/>
|
||||
<router-view />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -103,9 +103,7 @@ export default {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="border border-n-weak bg-n-solid-1 rounded-t-lg border-b-0 h-full w-full p-6 col-span-6 overflow-auto"
|
||||
>
|
||||
<div class="h-full w-full p-8 col-span-6">
|
||||
<form
|
||||
class="flex flex-wrap mx-0 overflow-x-auto"
|
||||
@submit.prevent="addAgents"
|
||||
|
||||
@@ -57,9 +57,7 @@ export default {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="border border-n-weak bg-n-solid-1 rounded-t-lg border-b-0 h-full w-full p-6 col-span-6 overflow-auto"
|
||||
>
|
||||
<div class="h-full w-full p-8 col-span-6">
|
||||
<PageHeader
|
||||
:header-title="$t('TEAMS_SETTINGS.EDIT_FLOW.CREATE.TITLE')"
|
||||
:header-content="$t('TEAMS_SETTINGS.EDIT_FLOW.CREATE.DESC')"
|
||||
|
||||
@@ -27,8 +27,15 @@ export default {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="grid grid-cols-1 md:grid-cols-8 overflow-auto h-full px-5 flex-1">
|
||||
<woot-wizard class="hidden md:block col-span-2" :items="items" />
|
||||
<router-view />
|
||||
<div class="mx-2 flex flex-col gap-6 mb-8">
|
||||
<div
|
||||
class="grid grid-cols-1 lg:grid-cols-8 lg:divide-x lg:divide-n-weak rounded-xl border border-n-weak min-h-[43rem]"
|
||||
>
|
||||
<woot-wizard
|
||||
class="hidden lg:block col-span-2 h-fit py-8 px-6"
|
||||
:items="items"
|
||||
/>
|
||||
<router-view />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -11,9 +11,7 @@ export default {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="border border-n-weak bg-n-solid-1 rounded-t-lg border-b-0 h-full w-full p-6 col-span-6 overflow-auto"
|
||||
>
|
||||
<div class="h-full w-full p-6 col-span-6">
|
||||
<EmptyState
|
||||
:title="$t('TEAMS_SETTINGS.FINISH.TITLE')"
|
||||
:message="$t('TEAMS_SETTINGS.FINISH.MESSAGE')"
|
||||
|
||||
Reference in New Issue
Block a user