Merge branch 'develop' into report-rewrite
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div
|
||||
class="w-[25%] bg-white dark:bg-slate-900 contact--panel"
|
||||
:class="{ 'border-left': showAvatar }"
|
||||
class="w-1/4 bg-white dark:bg-slate-900 border-slate-50 dark:border-slate-800/50 h-full text-sm overflow-y-auto relative"
|
||||
:class="showAvatar ? 'border-l border-solid ' : 'border-r border-solid'"
|
||||
>
|
||||
<contact-info
|
||||
:show-close-button="showCloseButton"
|
||||
@@ -151,9 +151,6 @@ export default {
|
||||
@apply pb-3 mb-4;
|
||||
}
|
||||
}
|
||||
.contact--panel {
|
||||
@apply border-r border-slate-50 dark:border-slate-800/50 h-full text-sm overflow-y-auto relative;
|
||||
}
|
||||
|
||||
.list-group {
|
||||
.list-group-item {
|
||||
|
||||
+1
-1
@@ -243,7 +243,7 @@ export default {
|
||||
attr.attribute_display_type === 'checkbox'
|
||||
);
|
||||
});
|
||||
if (isCustomAttributeCheckbox) {
|
||||
if (isCustomAttributeCheckbox || type === 'blocked') {
|
||||
return [
|
||||
{
|
||||
id: true,
|
||||
|
||||
@@ -135,7 +135,7 @@ export default {
|
||||
status={row.availability_status}
|
||||
/>
|
||||
<div class="user-block">
|
||||
<h6 class="sub-block-title overflow-hidden whitespace-nowrap text-ellipsis">
|
||||
<h6 class="text-base overflow-hidden whitespace-nowrap text-ellipsis">
|
||||
<router-link
|
||||
to={`/app/accounts/${this.$route.params.accountId}/contacts/${row.id}`}
|
||||
class="user-name"
|
||||
|
||||
@@ -113,6 +113,13 @@
|
||||
</woot-button>
|
||||
</div>
|
||||
</div>
|
||||
<woot-confirm-modal
|
||||
ref="confirmExportContactsDialog"
|
||||
:title="$t('EXPORT_CONTACTS.CONFIRM.TITLE')"
|
||||
:description="$t('EXPORT_CONTACTS.CONFIRM.MESSAGE')"
|
||||
:confirm-label="$t('EXPORT_CONTACTS.CONFIRM.YES')"
|
||||
:cancel-label="$t('EXPORT_CONTACTS.CONFIRM.NO')"
|
||||
/>
|
||||
</header>
|
||||
</template>
|
||||
|
||||
@@ -175,8 +182,13 @@ export default {
|
||||
toggleImport() {
|
||||
this.$emit('on-toggle-import');
|
||||
},
|
||||
submitExport() {
|
||||
this.$emit('on-export-submit');
|
||||
async submitExport() {
|
||||
const ok =
|
||||
await this.$refs.confirmExportContactsDialog.showConfirmation();
|
||||
|
||||
if (ok) {
|
||||
this.$emit('on-export-submit');
|
||||
}
|
||||
},
|
||||
submitSearch() {
|
||||
this.$emit('on-search-submit');
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="wrap">
|
||||
<div class="header">
|
||||
<h5 class="block-title text-black-900 dark:text-slate-200">
|
||||
<h5 class="text-lg text-black-900 dark:text-slate-200">
|
||||
{{ $t('EVENTS.HEADER.TITLE') }}
|
||||
</h5>
|
||||
</div>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<div class="card-wrap">
|
||||
<div class="header">
|
||||
<div class="text-wrap">
|
||||
<h6 class="text-block-title">
|
||||
<h6 class="text-sm">
|
||||
{{ eventType }}
|
||||
</h6>
|
||||
<span class="event-path">on {{ eventPath }}</span>
|
||||
|
||||
@@ -76,6 +76,14 @@ const filterTypes = [
|
||||
filterOperators: OPERATOR_TYPES_5,
|
||||
attributeModel: 'standard',
|
||||
},
|
||||
{
|
||||
attributeKey: 'blocked',
|
||||
attributeI18nKey: 'BLOCKED',
|
||||
inputType: 'search_select',
|
||||
dataType: 'text',
|
||||
filterOperators: OPERATOR_TYPES_1,
|
||||
attributeModel: 'standard',
|
||||
},
|
||||
];
|
||||
|
||||
export const filterAttributeGroups = [
|
||||
@@ -115,6 +123,10 @@ export const filterAttributeGroups = [
|
||||
key: 'last_activity_at',
|
||||
i18nKey: 'LAST_ACTIVITY',
|
||||
},
|
||||
{
|
||||
key: 'blocked',
|
||||
i18nKey: 'BLOCKED',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
:show-avatar="false"
|
||||
:contact="contact"
|
||||
/>
|
||||
<div class="w-[75%] h-full">
|
||||
<div class="w-3/4 h-full">
|
||||
<woot-tabs :index="selectedTabIndex" @change="onClickTabChange">
|
||||
<woot-tabs-item
|
||||
v-for="tab in tabs"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<spinner v-if="watchersUiFlas.isFetching" size="tiny" />
|
||||
{{ totalWatchersText }}
|
||||
</p>
|
||||
<p v-else class="text-muted m-0 text-sm">
|
||||
<p v-else class="text-slate-400 dark:text-slate-700 m-0 text-sm">
|
||||
{{ $t('CONVERSATION_PARTICIPANTS.NO_PARTICIPANTS_TEXT') }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -3,14 +3,13 @@
|
||||
<span class="overflow-hidden whitespace-nowrap text-ellipsis">{{
|
||||
macro.name
|
||||
}}</span>
|
||||
<div class="macros-actions">
|
||||
<div class="macros-actions flex items-center gap-1">
|
||||
<woot-button
|
||||
v-tooltip.left-start="$t('MACROS.EXECUTE.PREVIEW')"
|
||||
size="tiny"
|
||||
variant="smooth"
|
||||
color-scheme="secondary"
|
||||
icon="info"
|
||||
class="margin-right-smaller"
|
||||
@click="toggleMacroPreview(macro)"
|
||||
/>
|
||||
<woot-button
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<form
|
||||
class="contact--form w-full pt-6 px-8 pb-8"
|
||||
class="w-full px-8 pt-6 pb-8 contact--form"
|
||||
@submit.prevent="handleSubmit"
|
||||
>
|
||||
<div>
|
||||
@@ -76,7 +76,7 @@
|
||||
</label>
|
||||
<div
|
||||
v-if="isPhoneNumberNotValid || !phoneNumber"
|
||||
class="callout small warning text-sm dark:bg-yellow-200/20 dark:text-yellow-400"
|
||||
class="relative mx-0 mt-0 mb-2.5 p-2 rounded-md text-sm border border-solid border-yellow-500 text-yellow-700 dark:border-yellow-700 bg-yellow-200/60 dark:bg-yellow-200/20 dark:text-yellow-400"
|
||||
>
|
||||
{{ $t('CONTACT_FORM.FORM.PHONE_NUMBER.HELP') }}
|
||||
</div>
|
||||
@@ -121,17 +121,20 @@
|
||||
<div
|
||||
v-for="socialProfile in socialProfileKeys"
|
||||
:key="socialProfile.key"
|
||||
class="input-group"
|
||||
class="flex items-stretch w-full mb-4"
|
||||
>
|
||||
<span class="input-group-label">{{ socialProfile.prefixURL }}</span>
|
||||
<span
|
||||
class="flex items-center h-10 px-2 text-sm border-solid bg-slate-50 border-y ltr:border-l rtl:border-r ltr:rounded-l-md rtl:rounded-r-md dark:bg-slate-700 text-slate-800 dark:text-slate-100 border-slate-200 dark:border-slate-600"
|
||||
>{{ socialProfile.prefixURL }}</span
|
||||
>
|
||||
<input
|
||||
v-model="socialProfileUserNames[socialProfile.key]"
|
||||
class="input-group-field"
|
||||
class="input-group-field ltr:rounded-l-none rtl:rounded-r-none !mb-0"
|
||||
type="text"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-row justify-end gap-2 py-2 px-0 w-full">
|
||||
<div class="flex flex-row justify-end w-full gap-2 px-0 py-2">
|
||||
<div class="w-full">
|
||||
<woot-submit-button
|
||||
:loading="inProgress"
|
||||
@@ -416,10 +419,6 @@ export default {
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.input-group-label {
|
||||
@apply text-sm bg-slate-50 dark:bg-slate-700 text-slate-800 dark:text-slate-100 border-slate-200 dark:border-slate-600;
|
||||
}
|
||||
|
||||
::v-deep {
|
||||
.multiselect .multiselect__tags .multiselect__single {
|
||||
@apply pl-0;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="relative items-center p-4 bg-white dark:bg-slate-900">
|
||||
<div class="text-left rtl:text-right">
|
||||
<div class="relative items-center p-4 bg-white dark:bg-slate-900 w-full">
|
||||
<div class="text-left rtl:text-right flex flex-col gap-2 w-full">
|
||||
<div class="flex justify-between flex-row">
|
||||
<thumbnail
|
||||
v-if="showAvatar"
|
||||
@@ -17,10 +17,10 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="mt-2 w-full">
|
||||
<div v-if="showAvatar" class="flex items-start mb-2 gap-1.5">
|
||||
<div class="flex flex-col items-start gap-1.5 min-w-0 w-full">
|
||||
<div v-if="showAvatar" class="flex items-start gap-2 min-w-0 w-full">
|
||||
<h3
|
||||
class="text-base text-slate-800 dark:text-slate-100 capitalize whitespace-normal my-0"
|
||||
class="flex-shrink min-w-0 text-base text-slate-800 dark:text-slate-100 capitalize my-0 max-w-full break-words"
|
||||
>
|
||||
{{ contact.name }}
|
||||
</h3>
|
||||
@@ -38,7 +38,7 @@
|
||||
/>
|
||||
<a
|
||||
:href="contactProfileLink"
|
||||
class="fs-default"
|
||||
class="text-base"
|
||||
target="_blank"
|
||||
rel="noopener nofollow noreferrer"
|
||||
>
|
||||
@@ -52,10 +52,10 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p v-if="additionalAttributes.description" class="break-words">
|
||||
<p v-if="additionalAttributes.description" class="break-words mb-0.5">
|
||||
{{ additionalAttributes.description }}
|
||||
</p>
|
||||
<div class="mb-3">
|
||||
<div class="flex flex-col gap-2 items-start w-full">
|
||||
<contact-info-row
|
||||
:href="contact.email ? `mailto:${contact.email}` : ''"
|
||||
:value="contact.email"
|
||||
@@ -95,7 +95,7 @@
|
||||
<social-icons :social-profiles="socialProfiles" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center w-full mt-2 gap-2">
|
||||
<div class="flex items-center w-full mt-0.5 gap-2">
|
||||
<woot-button
|
||||
v-tooltip="$t('CONTACT_PANEL.NEW_MESSAGE')"
|
||||
title="$t('CONTACT_PANEL.NEW_MESSAGE')"
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
<template>
|
||||
<div class="-ml-1">
|
||||
<div class="ltr:-ml-1 rtl:-mr-1 h-5 w-full">
|
||||
<a
|
||||
v-if="href"
|
||||
:href="href"
|
||||
class="flex items-center mb-2 text-slate-800 dark:text-slate-100 hover:underline"
|
||||
class="flex items-center gap-2 text-slate-800 dark:text-slate-100 hover:underline"
|
||||
>
|
||||
<emoji-or-icon
|
||||
:icon="icon"
|
||||
:emoji="emoji"
|
||||
icon-size="14"
|
||||
class="mr-2 ml-1 rtl:mr-1 rtl:ml-2"
|
||||
class="ltr:ml-1 rtl:mr-1 flex-shrink-0"
|
||||
/>
|
||||
<span
|
||||
v-if="value"
|
||||
@@ -29,20 +29,20 @@
|
||||
size="tiny"
|
||||
color-scheme="secondary"
|
||||
icon="clipboard"
|
||||
class-names="copy-button"
|
||||
class-names="p-0"
|
||||
@click="onCopy"
|
||||
/>
|
||||
</a>
|
||||
|
||||
<div
|
||||
v-else
|
||||
class="flex items-center mb-2 text-slate-800 dark:text-slate-100"
|
||||
class="flex items-center gap-2 text-slate-800 dark:text-slate-100"
|
||||
>
|
||||
<emoji-or-icon
|
||||
:icon="icon"
|
||||
:emoji="emoji"
|
||||
icon-size="14"
|
||||
class="mr-2 ml-1 rtl:mr-1 rtl:ml-2"
|
||||
class="ltr:ml-1 rtl:mr-1 flex-shrink-0"
|
||||
/>
|
||||
<span
|
||||
v-if="value"
|
||||
@@ -97,8 +97,3 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.copy-button {
|
||||
@apply ml-1 rtl:ml-0 rtl:mr-1;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
<template>
|
||||
<form class="conversation--form w-full" @submit.prevent="onFormSubmit">
|
||||
<div v-if="showNoInboxAlert" class="callout warning">
|
||||
<p>
|
||||
<div
|
||||
v-if="showNoInboxAlert"
|
||||
class="relative mx-0 mt-0 mb-2.5 p-2 rounded-none text-sm border border-solid border-yellow-500 dark:border-yellow-700 bg-yellow-200/60 dark:bg-yellow-200/20 text-slate-700 dark:text-yellow-400"
|
||||
>
|
||||
<p class="mb-0">
|
||||
{{ $t('NEW_CONVERSATION.NO_INBOX') }}
|
||||
</p>
|
||||
</div>
|
||||
@@ -226,7 +229,7 @@
|
||||
class="flex top-0 bottom-0 z-30 gap-2 right-0 left-0 items-center justify-center flex-col absolute w-full h-full bg-white/80 dark:bg-slate-700/80"
|
||||
>
|
||||
<fluent-icon icon="cloud-backup" size="40" />
|
||||
<h4 class="page-sub-title text-slate-600 dark:text-slate-200">
|
||||
<h4 class="text-2xl break-words text-slate-600 dark:text-slate-200">
|
||||
{{ $t('CONVERSATION.REPLYBOX.DRAG_DROP') }}
|
||||
</h4>
|
||||
</div>
|
||||
|
||||
@@ -1,28 +1,9 @@
|
||||
/* eslint arrow-body-style: 0 */
|
||||
import { frontendURL } from '../../../helper/URLHelper';
|
||||
const ConversationView = () => import('./ConversationView');
|
||||
const InboxView = () => import('../inbox/InboxView.vue');
|
||||
|
||||
export default {
|
||||
routes: [
|
||||
{
|
||||
path: frontendURL('accounts/:accountId/inbox-view'),
|
||||
name: 'inbox_view',
|
||||
roles: ['administrator', 'agent'],
|
||||
component: InboxView,
|
||||
props: () => {
|
||||
return { inboxId: 0 };
|
||||
},
|
||||
},
|
||||
{
|
||||
path: frontendURL('accounts/:accountId/inbox-view/:conversation_id'),
|
||||
name: 'inbox_view_conversation',
|
||||
roles: ['administrator', 'agent'],
|
||||
component: InboxView,
|
||||
props: route => {
|
||||
return { inboxId: 0, conversationId: route.params.conversation_id };
|
||||
},
|
||||
},
|
||||
{
|
||||
path: frontendURL('accounts/:accountId/dashboard'),
|
||||
name: 'home',
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
:show-close="true"
|
||||
:color="label.color"
|
||||
variant="smooth"
|
||||
class="max-w-[calc(100%-0.5rem)]"
|
||||
@click="removeLabelFromConversation"
|
||||
/>
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import conversation from './conversation/conversation.routes';
|
||||
import { routes as searchRoutes } from '../../modules/search/search.routes';
|
||||
import { routes as contactRoutes } from './contacts/routes';
|
||||
import { routes as notificationRoutes } from './notifications/routes';
|
||||
import { routes as inboxRoutes } from './inbox/routes';
|
||||
import { frontendURL } from '../../helper/URLHelper';
|
||||
import helpcenterRoutes from './helpcenter/helpcenter.routes';
|
||||
|
||||
@@ -16,6 +17,7 @@ export default {
|
||||
path: frontendURL('accounts/:account_id'),
|
||||
component: AppContainer,
|
||||
children: [
|
||||
...inboxRoutes,
|
||||
...conversation.routes,
|
||||
...settings.routes,
|
||||
...contactRoutes,
|
||||
|
||||
@@ -81,11 +81,11 @@ export default {
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.edit-article--container {
|
||||
@apply my-8 mx-auto py-0 px-6 max-w-[56rem] w-full;
|
||||
@apply my-8 mx-auto py-0 max-w-[56rem] w-full;
|
||||
}
|
||||
|
||||
.article-heading {
|
||||
@apply text-[2.5rem] font-semibold w-full text-slate-900 dark:text-slate-75 p-4 hover:bg-slate-25 dark:hover:bg-slate-800 hover:rounded-md resize-none min-h-[4rem] max-h-[40rem] h-auto mb-2 border-0 border-solid border-transparent dark:border-transparent;
|
||||
@apply text-[2.5rem] font-semibold leading-normal w-full text-slate-900 dark:text-slate-75 p-4 hover:bg-slate-25 dark:hover:bg-slate-800 hover:rounded-md resize-none min-h-[4rem] max-h-[40rem] h-auto mb-2 border-0 border-solid border-transparent dark:border-transparent;
|
||||
}
|
||||
|
||||
.article-content {
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
<template>
|
||||
<div class="article-container--row">
|
||||
<span class="article-column article-title">
|
||||
<emoji-or-icon class="icon-grab" icon="grab-handle" />
|
||||
<div class="article-block">
|
||||
<div
|
||||
class="text-slate-700 dark:text-slate-100 last:border-b-0 bg-white dark:bg-slate-900 my-0 -mx-4 grid grid-cols-1 lg:grid-cols-12 gap-4 border-b border-slate-50 dark:border-slate-800 px-6 py-3"
|
||||
>
|
||||
<span class="items-start flex gap-2 col-span-6 text-left">
|
||||
<fluent-icon
|
||||
v-if="showDragIcon"
|
||||
size="20"
|
||||
class="block cursor-move flex-shrink-0 h-4 mt-1 w-4 text-slate-200 dark:text-slate-700 hover:text-slate-400 hover:dark:text-slate-200"
|
||||
icon="grab-handle"
|
||||
/>
|
||||
<div class="flex flex-col truncate">
|
||||
<router-link :to="articleUrl(id)">
|
||||
<h6
|
||||
:title="title"
|
||||
class="text-base ltr:text-left rtl:text-right text-slate-800 dark:text-slate-100 mb-0 leading-6 h-6 hover:underline overflow-hidden whitespace-nowrap text-ellipsis"
|
||||
class="text-base ltr:text-left rtl:text-right text-slate-800 dark:text-slate-100 mb-0.5 leading-6 font-medium hover:underline overflow-hidden whitespace-nowrap text-ellipsis"
|
||||
>
|
||||
{{ title }}
|
||||
</h6>
|
||||
@@ -16,14 +23,14 @@
|
||||
v-if="author"
|
||||
:src="author.thumbnail"
|
||||
:username="author.name"
|
||||
size="16px"
|
||||
size="14px"
|
||||
/>
|
||||
<div
|
||||
v-else
|
||||
v-tooltip.right="
|
||||
$t('HELP_CENTER.TABLE.COLUMNS.AUTHOR_NOT_AVAILABLE')
|
||||
"
|
||||
class="flex items-center justify-center rounded w-4 h-4 bg-woot-100 dark:bg-woot-700"
|
||||
class="flex items-center justify-center rounded w-3.5 h-3.5 bg-woot-100 dark:bg-woot-700"
|
||||
>
|
||||
<fluent-icon
|
||||
icon="person"
|
||||
@@ -32,61 +39,64 @@
|
||||
class="text-woot-300 dark:text-woot-300"
|
||||
/>
|
||||
</div>
|
||||
<span class="font-normal text-slate-500 dark:text-slate-200 text-sm">
|
||||
<span class="font-normal text-slate-700 dark:text-slate-200 text-sm">
|
||||
{{ articleAuthorName }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
<span class="article-column article-category">
|
||||
<span class="flex items-center col-span-2">
|
||||
<router-link
|
||||
class="fs-small button clear link secondary"
|
||||
class="text-sm hover:underline p-0.5 truncate hover:bg-slate-25 hover:rounded-md"
|
||||
:to="getCategoryRoute(category.slug)"
|
||||
>
|
||||
<span
|
||||
:title="category.name"
|
||||
class="category-link-content overflow-hidden whitespace-nowrap text-ellipsis"
|
||||
>
|
||||
<span :title="category.name">
|
||||
{{ category.name }}
|
||||
</span>
|
||||
</router-link>
|
||||
</span>
|
||||
<span class="article-column article-read-count">
|
||||
<span class="fs-small" :title="formattedViewCount">
|
||||
{{ readableViewCount }}
|
||||
<span
|
||||
class="flex items-center text-xs lg:text-sm"
|
||||
:title="formattedViewCount"
|
||||
>
|
||||
{{ readableViewCount }}
|
||||
<span class="lg:hidden ml-1">
|
||||
{{ ` ${$t('HELP_CENTER.TABLE.HEADERS.READ_COUNT')}` }}
|
||||
</span>
|
||||
</span>
|
||||
<span class="article-column article-status">
|
||||
<div>
|
||||
<woot-label
|
||||
:title="status"
|
||||
size="small"
|
||||
variant="smooth"
|
||||
:color-scheme="labelColor"
|
||||
/>
|
||||
</div>
|
||||
<span class="flex items-center capitalize">
|
||||
<woot-label
|
||||
class="!mb-0"
|
||||
:title="status"
|
||||
size="small"
|
||||
variant="smooth"
|
||||
:color-scheme="labelColor"
|
||||
/>
|
||||
</span>
|
||||
<span class="article-column article-last-edited">
|
||||
<span class="fs-small">
|
||||
{{ lastUpdatedAt }}
|
||||
</span>
|
||||
<span
|
||||
class="flex items-center justify-end col-span-2 first-letter:uppercase text-slate-700 dark:text-slate-100 text-xs"
|
||||
>
|
||||
{{ lastUpdatedAt }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import timeMixin from 'dashboard/mixins/time';
|
||||
import portalMixin from '../mixins/portalMixin';
|
||||
import { frontendURL } from 'dashboard/helper/URLHelper';
|
||||
import EmojiOrIcon from '../../../../../shared/components/EmojiOrIcon.vue';
|
||||
import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
EmojiOrIcon,
|
||||
Thumbnail,
|
||||
},
|
||||
mixins: [timeMixin, portalMixin],
|
||||
props: {
|
||||
showDragIcon: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
id: {
|
||||
type: Number,
|
||||
required: true,
|
||||
@@ -156,65 +166,3 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.article-container--row {
|
||||
@apply bg-white dark:bg-slate-900 my-0 -mx-4 py-0 px-4 grid grid-cols-8 gap-4 border-b border-slate-50 dark:border-slate-800;
|
||||
|
||||
@media (max-width: 1024px) {
|
||||
@apply grid-cols-7;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
@apply grid-cols-6;
|
||||
}
|
||||
|
||||
&.draggable {
|
||||
span.article-column.article-title {
|
||||
@apply -ml-2;
|
||||
|
||||
.icon-grab {
|
||||
@apply block cursor-move h-4 mt-1 w-4 text-slate-100 dark:text-slate-700;
|
||||
|
||||
&:hover {
|
||||
@apply text-slate-300 dark:text-slate-200;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
span.article-column {
|
||||
@apply text-slate-700 dark:text-slate-100 text-sm font-semibold py-2 px-0 text-left capitalize last:text-right;
|
||||
|
||||
&.article-title {
|
||||
@apply items-start flex gap-2 col-span-4 text-left;
|
||||
|
||||
.icon-grab {
|
||||
@apply hidden;
|
||||
}
|
||||
}
|
||||
|
||||
// for screen sizes smaller than 1024px
|
||||
@media (max-width: 63.9375em) {
|
||||
&.article-read-count {
|
||||
@apply hidden;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 47.9375em) {
|
||||
&.article-read-count,
|
||||
&.article-last-edited {
|
||||
@apply hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.article-block {
|
||||
@apply min-w-0;
|
||||
}
|
||||
}
|
||||
|
||||
span {
|
||||
@apply font-normal text-slate-700 dark:text-slate-100 text-sm pl-0;
|
||||
}
|
||||
</style>
|
||||
|
||||
+2
-2
@@ -4,14 +4,14 @@
|
||||
@click="handlePreview"
|
||||
>
|
||||
<h4
|
||||
class="text-block-title text-left mb-0 text-slate-900 dark:text-slate-25 px-1 -mx-1 rounded-sm width-auto hover:underline group-hover:underline"
|
||||
class="text-sm ltr:text-left rtl:text-right w-full mb-0 text-slate-900 dark:text-slate-25 -mx-1 rounded-sm hover:underline group-hover:underline"
|
||||
>
|
||||
{{ title }}
|
||||
</h4>
|
||||
|
||||
<div class="flex content-between items-center gap-0.5 w-full">
|
||||
<p
|
||||
class="text-sm text-left text-slate-600 dark:text-slate-300 mb-0 w-full"
|
||||
class="text-sm ltr:text-left rtl:text-right text-slate-600 dark:text-slate-300 mb-0 w-full"
|
||||
>
|
||||
{{ locale }}
|
||||
{{ ` / ` }}
|
||||
|
||||
+7
-5
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="flex flex-col py-1">
|
||||
<div class="flex-container align-middle align-justify py-2">
|
||||
<h3 class="sub-block-title text-slate-900 dark:text-slate-25">
|
||||
<div class="flex items-center justify-between py-2 mb-1">
|
||||
<h3 class="text-base text-slate-900 dark:text-slate-25">
|
||||
{{ title }}
|
||||
</h3>
|
||||
<woot-button
|
||||
@@ -14,14 +14,16 @@
|
||||
</div>
|
||||
|
||||
<div class="relative">
|
||||
<div class="absolute left-0 w-8 h-8 flex justify-center items-center">
|
||||
<fluent-icon icon="search" class="" size="16" />
|
||||
<div
|
||||
class="absolute ltr:left-0 rtl:right-0 w-8 top-0.5 h-8 flex justify-center items-center"
|
||||
>
|
||||
<fluent-icon icon="search" class="" size="18" />
|
||||
</div>
|
||||
<input
|
||||
ref="searchInput"
|
||||
type="text"
|
||||
:placeholder="$t('HELP_CENTER.ARTICLE_SEARCH.PLACEHOLDER')"
|
||||
class="block w-full pl-8 h-8 text-sm dark:bg-slate-700 bg-slate-25 rounded-md leading-8 py-1 text-slate-700 shadow-sm ring-2 ring-transparent ring-slate-300 border border-solid border-slate-300 placeholder:text-slate-400 focus:border-woot-600 focus:ring-woot-200 mb-0 focus:bg-slate-25 dark:focus:bg-slate-700 dark:focus:ring-woot-700"
|
||||
class="block w-full !h-9 ltr:!pl-8 rtl:!pr-8 dark:!bg-slate-700 !bg-slate-25 text-sm rounded-md leading-8 text-slate-700 shadow-sm ring-2 ring-transparent ring-slate-300 border border-solid border-slate-300 placeholder:text-slate-400 focus:border-woot-600 focus:ring-woot-200 !mb-0 focus:bg-slate-25 dark:focus:bg-slate-700 dark:focus:ring-woot-700"
|
||||
:value="searchQuery"
|
||||
@focus="onFocus"
|
||||
@blur="onBlur"
|
||||
|
||||
@@ -1,38 +1,38 @@
|
||||
<template>
|
||||
<div class="w-full">
|
||||
<div class="flex-1">
|
||||
<div
|
||||
class="my-0 py-0 px-4 grid grid-cols-6 z-10 md:grid-cols-7 lg:grid-cols-8 gap-4 border-b border-slate-100 dark:border-slate-700 sticky top-16 bg-white dark:bg-slate-900"
|
||||
class="hidden lg:grid py-0 px-6 h-12 content-center grid-cols-12 z-10 gap-4 border-b border-slate-50 dark:border-slate-700 sticky top-16 bg-white dark:bg-slate-900"
|
||||
:class="{ draggable: onCategoryPage }"
|
||||
>
|
||||
<div
|
||||
class="font-semibold capitalize text-sm py-2 px-0 text-slate-700 dark:text-slate-100 ltr:text-left rtl:text-right col-span-4"
|
||||
class="font-semibold capitalize text-sm py-2 px-0 text-slate-700 dark:text-slate-100 text-left rtl:text-right col-span-6"
|
||||
>
|
||||
{{ $t('HELP_CENTER.TABLE.HEADERS.TITLE') }}
|
||||
</div>
|
||||
<div
|
||||
class="font-semibold capitalize text-sm py-2 px-0 text-slate-700 dark:text-slate-100 text-left"
|
||||
class="font-semibold capitalize text-sm py-2 px-0 text-slate-700 dark:text-slate-100 text-left rtl:text-right col-span-2"
|
||||
>
|
||||
{{ $t('HELP_CENTER.TABLE.HEADERS.CATEGORY') }}
|
||||
</div>
|
||||
<div
|
||||
class="font-semibold capitalize text-sm py-2 px-0 text-slate-700 dark:text-slate-100 text-left hidden lg:block"
|
||||
class="font-semibold capitalize text-sm py-2 px-0 text-slate-700 dark:text-slate-100 text-left rtl:text-right hidden lg:block"
|
||||
>
|
||||
{{ $t('HELP_CENTER.TABLE.HEADERS.READ_COUNT') }}
|
||||
</div>
|
||||
<div
|
||||
class="font-semibold capitalize text-sm py-2 px-0 text-slate-700 dark:text-slate-100 text-left"
|
||||
class="font-semibold capitalize text-sm py-2 px-0 text-slate-700 dark:text-slate-100 text-left rtl:text-right"
|
||||
>
|
||||
{{ $t('HELP_CENTER.TABLE.HEADERS.STATUS') }}
|
||||
</div>
|
||||
<div
|
||||
class="font-semibold capitalize text-sm py-2 px-0 text-slate-700 dark:text-slate-100 text-right hidden md:block"
|
||||
class="font-semibold capitalize text-sm py-2 px-0 text-slate-700 dark:text-slate-100 text-right rtl:text-left hidden md:block col-span-2"
|
||||
>
|
||||
{{ $t('HELP_CENTER.TABLE.HEADERS.LAST_EDITED') }}
|
||||
</div>
|
||||
</div>
|
||||
<draggable
|
||||
tag="div"
|
||||
class="border-t-0 px-4"
|
||||
class="border-t-0 px-4 pb-4"
|
||||
:disabled="!dragEnabled"
|
||||
:list="localArticles"
|
||||
ghost-class="article-ghost-class"
|
||||
@@ -46,6 +46,7 @@
|
||||
:class="{ draggable: onCategoryPage }"
|
||||
:title="article.title"
|
||||
:author="article.author"
|
||||
:show-drag-icon="dragEnabled"
|
||||
:category="article.category"
|
||||
:views="article.views"
|
||||
:status="article.status"
|
||||
@@ -58,7 +59,7 @@
|
||||
:current-page="currentPage"
|
||||
:total-count="totalCount"
|
||||
:page-size="pageSize"
|
||||
class="dark:bg-slate-900 sticky bottom-0 border-t-0 px-4"
|
||||
class="dark:bg-slate-900 sticky bottom-0"
|
||||
@page-change="onPageChange"
|
||||
/>
|
||||
</div>
|
||||
@@ -78,7 +79,7 @@ export default {
|
||||
props: {
|
||||
articles: {
|
||||
type: Array,
|
||||
default: () => {},
|
||||
default: () => [],
|
||||
},
|
||||
totalCount: {
|
||||
type: Number,
|
||||
@@ -95,7 +96,7 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
localArticles: [],
|
||||
localArticles: this.articles || [],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -155,6 +156,10 @@ export default {
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
/*
|
||||
The .article-ghost-class class is maintained as the vueDraggable doesn't allow multiple classes
|
||||
to be passed in the ghost-class prop.
|
||||
*/
|
||||
.article-ghost-class {
|
||||
@apply opacity-50 bg-slate-50 dark:bg-slate-800;
|
||||
}
|
||||
|
||||
+4
-3
@@ -1,14 +1,14 @@
|
||||
<template>
|
||||
<div
|
||||
class="flex px-4 items-center justify-between w-full h-16 pt-2 sticky top-0 z-50 bg-white dark:bg-slate-900"
|
||||
class="flex p-6 items-center justify-between w-full h-16 sticky top-0 z-50 bg-white dark:bg-slate-900"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<woot-sidemenu-icon />
|
||||
<div class="flex items-center my-0 mx-2">
|
||||
<h3 class="text-2xl text-slate-800 dark:text-slate-100 mb-0">
|
||||
<h3 class="text-xl text-slate-800 dark:text-slate-100 font-medium mb-0">
|
||||
{{ headerTitle }}
|
||||
</h3>
|
||||
<span class="text-sm text-slate-600 dark:text-slate-300 my-0 mx-2">{{
|
||||
<span class="text-sm text-slate-600 dark:text-slate-300 mx-2 mt-0.5">{{
|
||||
`(${count})`
|
||||
}}</span>
|
||||
</div>
|
||||
@@ -232,6 +232,7 @@ export default {
|
||||
.dropdown-pane--open {
|
||||
@apply absolute top-10 right-0 z-50 min-w-[8rem];
|
||||
}
|
||||
|
||||
.dropdown-arrow {
|
||||
@apply ml-1 rtl:ml-0 rtl:mr-1;
|
||||
}
|
||||
|
||||
+4
-1
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="flex items-center justify-between w-full h-16 pt-2">
|
||||
<div class="flex items-center justify-between w-full h-16">
|
||||
<div class="flex items-center">
|
||||
<woot-button
|
||||
icon="chevron-left"
|
||||
@@ -240,12 +240,15 @@ export default {
|
||||
@apply absolute right-0;
|
||||
}
|
||||
}
|
||||
|
||||
.draft-status {
|
||||
animation: fadeIn 1s;
|
||||
|
||||
@keyframes fadeIn {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
+1
-1
@@ -85,7 +85,7 @@
|
||||
size="tiny"
|
||||
variant="smooth"
|
||||
icon="delete"
|
||||
color-scheme="secondary"
|
||||
color-scheme="alert"
|
||||
:disabled="locale.code === selectedLocaleCode"
|
||||
@click="deleteLocale(locale.code)"
|
||||
/>
|
||||
|
||||
+5
-7
@@ -1,7 +1,9 @@
|
||||
<template>
|
||||
<div class="wizard-body w-[75%] flex-shrink-0 flex-grow-0 max-w-[75%]">
|
||||
<div
|
||||
class="pt-3 bg-white dark:bg-slate-900 h-full border border-solid border-transparent px-6 pb-6 dark:border-transparent w-full max-w-full md:w-3/4 md:max-w-[75%] flex-shrink-0 flex-grow-0"
|
||||
>
|
||||
<div class="w-full">
|
||||
<h3 class="block-title text-black-900 dark:text-slate-200">
|
||||
<h3 class="text-lg text-black-900 dark:text-slate-200">
|
||||
{{
|
||||
$t(
|
||||
'HELP_CENTER.PORTAL.ADD.CREATE_FLOW_PAGE.BASIC_SETTINGS_PAGE.TITLE'
|
||||
@@ -75,7 +77,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-end">
|
||||
<div class="flex justify-end">
|
||||
<woot-button
|
||||
:is-loading="isSubmitting"
|
||||
:is-disabled="$v.$invalid"
|
||||
@@ -243,10 +245,6 @@ export default {
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.wizard-body {
|
||||
@apply pt-3 border border-solid border-transparent dark:border-transparent;
|
||||
}
|
||||
|
||||
::v-deep {
|
||||
input {
|
||||
@apply mb-1;
|
||||
|
||||
+5
-7
@@ -1,7 +1,9 @@
|
||||
<template>
|
||||
<div class="wizard-body w-[75%] flex-shrink-0 flex-grow-0 max-w-[75%] h-auto">
|
||||
<div
|
||||
class="pt-3 bg-white dark:bg-slate-900 h-full border border-solid border-transparent px-6 pb-6 dark:border-transparent w-full max-w-full md:w-3/4 md:max-w-[75%] flex-shrink-0 flex-grow-0"
|
||||
>
|
||||
<div class="w-full">
|
||||
<h3 class="block-title text-black-900 dark:text-slate-200">
|
||||
<h3 class="text-lg text-black-900 dark:text-slate-200">
|
||||
{{
|
||||
$t('HELP_CENTER.PORTAL.ADD.CREATE_FLOW_PAGE.CUSTOMIZATION_PAGE.TITLE')
|
||||
}}
|
||||
@@ -57,7 +59,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-end">
|
||||
<div class="flex justify-end">
|
||||
<woot-button
|
||||
:is-loading="isSubmitting"
|
||||
:is-disabled="$v.$invalid"
|
||||
@@ -150,10 +152,6 @@ export default {
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.wizard-body {
|
||||
@apply pt-3 border border-solid border-transparent dark:border-transparent;
|
||||
}
|
||||
|
||||
::v-deep {
|
||||
input {
|
||||
@apply mb-1;
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
</span>
|
||||
<span
|
||||
v-if="isLocaleDefault(locale.code)"
|
||||
class="fs-small text-slate-300 dark:text-slate-200"
|
||||
class="text-sm text-slate-300 dark:text-slate-200"
|
||||
>
|
||||
{{ `(${$t('HELP_CENTER.PORTAL.DEFAULT')})` }}
|
||||
</span>
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
<template>
|
||||
<div
|
||||
class="h-full overflow-auto w-60 flex flex-col bg-white dark:bg-slate-900 border-r dark:border-slate-700 rtl:border-r-0 rtl:border-l border-slate-50 text-sm px-2 pb-8"
|
||||
class="h-full overflow-auto w-60 flex flex-col bg-white dark:bg-slate-900 border-r dark:border-slate-700 rtl:border-r-0 rtl:border-l border-slate-50 text-sm"
|
||||
>
|
||||
<sidebar-header
|
||||
:thumbnail-src="thumbnailSrc"
|
||||
:header-title="headerTitle"
|
||||
:sub-title="subTitle"
|
||||
:portal-link="portalLink"
|
||||
class="px-4"
|
||||
@open-popover="openPortalPopover"
|
||||
/>
|
||||
<transition-group
|
||||
name="menu-list"
|
||||
tag="ul"
|
||||
class="pt-2 list-none ml-0 mb-0"
|
||||
class="py-2 px-4 list-none ml-0 mb-0"
|
||||
>
|
||||
<secondary-nav-item
|
||||
v-for="menuItem in accessibleMenuItems"
|
||||
@@ -75,9 +76,6 @@ export default {
|
||||
default: () => [],
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {};
|
||||
},
|
||||
computed: {
|
||||
hasCategory() {
|
||||
return (
|
||||
|
||||
+10
-18
@@ -1,10 +1,12 @@
|
||||
<template>
|
||||
<transition name="popover-animation">
|
||||
<div class="article-settings--container">
|
||||
<div
|
||||
class="min-w-[15rem] max-w-[22.5rem] p-6 overflow-y-auto border-l rtl:border-r rtl:border-l-0 border-solid border-slate-50 dark:border-slate-700"
|
||||
>
|
||||
<h3 class="text-base text-slate-800 dark:text-slate-100">
|
||||
{{ $t('HELP_CENTER.ARTICLE_SETTINGS.TITLE') }}
|
||||
</h3>
|
||||
<div class="form-wrap">
|
||||
<div class="mt-4 mb-6">
|
||||
<label>
|
||||
{{ $t('HELP_CENTER.ARTICLE_SETTINGS.FORM.CATEGORY.LABEL') }}
|
||||
<multiselect-dropdown
|
||||
@@ -64,6 +66,7 @@
|
||||
{{ $t('HELP_CENTER.ARTICLE_SETTINGS.FORM.META_DESCRIPTION.LABEL') }}
|
||||
<textarea
|
||||
v-model="metaDescription"
|
||||
class="text-sm"
|
||||
rows="3"
|
||||
type="text"
|
||||
:placeholder="
|
||||
@@ -95,7 +98,7 @@
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<div class="action-buttons">
|
||||
<div class="flex flex-col">
|
||||
<woot-button
|
||||
icon="archive"
|
||||
size="small"
|
||||
@@ -241,35 +244,24 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.article-settings--container {
|
||||
@apply flex-[0.3] min-w-[15rem] max-w-[22.5rem] py-2 pl-4 rtl:pl-0 rtl:pr-4 ml-4 rtl:ml-0 rtl:mr-4 overflow-y-auto border-l rtl:border-r rtl:border-l-0 border-solid border-slate-50 dark:border-slate-700;
|
||||
|
||||
.form-wrap {
|
||||
@apply mt-4 mb-6;
|
||||
|
||||
textarea {
|
||||
@apply text-sm;
|
||||
}
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
@apply flex flex-col;
|
||||
}
|
||||
}
|
||||
::v-deep {
|
||||
.multiselect {
|
||||
@apply mb-0;
|
||||
}
|
||||
|
||||
.multiselect__content-wrapper {
|
||||
@apply hidden;
|
||||
}
|
||||
|
||||
.multiselect--active .multiselect__tags {
|
||||
padding-right: var(--space-small) !important;
|
||||
@apply rounded-md;
|
||||
}
|
||||
|
||||
.multiselect__placeholder {
|
||||
@apply text-slate-300 dark:text-slate-200 pt-2 mb-0;
|
||||
}
|
||||
|
||||
.multiselect__select {
|
||||
@apply hidden;
|
||||
}
|
||||
|
||||
+43
-16
@@ -5,31 +5,58 @@
|
||||
Loading...
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import uiSettingsMixin from 'dashboard/mixins/uiSettings';
|
||||
import { mapGetters } from 'vuex';
|
||||
|
||||
export default {
|
||||
mixins: [uiSettingsMixin],
|
||||
computed: {
|
||||
...mapGetters({ portals: 'portals/allPortals' }),
|
||||
},
|
||||
mounted() {
|
||||
const {
|
||||
last_active_portal_slug: lastActivePortalSlug,
|
||||
last_active_locale_code: lastActiveLocaleCode,
|
||||
} = this.uiSettings || {};
|
||||
this.performRouting();
|
||||
},
|
||||
methods: {
|
||||
isPortalPresent(portalSlug) {
|
||||
return !!this.portals.find(portal => portal.slug === portalSlug);
|
||||
},
|
||||
async performRouting() {
|
||||
await this.$store.dispatch('portals/index');
|
||||
this.$nextTick(() => this.routeToLastActivePortal());
|
||||
},
|
||||
routeToView(name, params) {
|
||||
this.$router.replace({ name, params, replace: true });
|
||||
},
|
||||
async routeToLastActivePortal() {
|
||||
// TODO: This method should be written as a navigation guard rather than
|
||||
// a method in the component.
|
||||
const {
|
||||
last_active_portal_slug: lastActivePortalSlug,
|
||||
last_active_locale_code: lastActiveLocaleCode,
|
||||
} = this.uiSettings || {};
|
||||
|
||||
if (lastActivePortalSlug)
|
||||
this.$router.replace({
|
||||
name: 'list_all_locale_articles',
|
||||
params: {
|
||||
if (this.isPortalPresent(lastActivePortalSlug)) {
|
||||
// Check if the last active portal from the user preferences is available in the current
|
||||
// list of portals. If it is, navigate there. The last active portal is saved in the user's
|
||||
// UI settings, regardless of the account. Consequently, it's possible that the saved portal
|
||||
// slug is not available in the current account.
|
||||
this.routeToView('list_all_locale_articles', {
|
||||
portalSlug: lastActivePortalSlug,
|
||||
locale: lastActiveLocaleCode,
|
||||
},
|
||||
replace: true,
|
||||
});
|
||||
else
|
||||
this.$router.replace({
|
||||
name: 'list_all_portals',
|
||||
replace: true,
|
||||
});
|
||||
});
|
||||
} else if (this.portals.length > 0) {
|
||||
// If the last active portal is available, check for the exisiting list of portals and
|
||||
// navigate to the first available portal.
|
||||
const { slug: portalSlug, meta: { default_locale: locale } = {} } =
|
||||
this.portals[0];
|
||||
this.routeToView('list_all_locale_articles', { portalSlug, locale });
|
||||
} else {
|
||||
// If no portals are available, navigate to the portal list page to prompt creation.
|
||||
this.$router.replace({ name: 'list_all_portals', replace: true });
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
+10
-26
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<div class="article-container">
|
||||
<div class="article-container flex w-full overflow-auto">
|
||||
<div
|
||||
class="edit-article--container"
|
||||
:class="{ 'is-sidebar-open': showArticleSettings }"
|
||||
class="flex-1 flex-shrink-0 overflow-auto px-6"
|
||||
:class="{ 'flex-grow-1 flex-shrink-0': showArticleSettings }"
|
||||
>
|
||||
<edit-article-header
|
||||
:back-button-label="$t('HELP_CENTER.HEADER.TITLES.ALL_ARTICLES')"
|
||||
@@ -15,7 +15,7 @@
|
||||
@show="showArticleInPortal"
|
||||
@update-meta="updateMeta"
|
||||
/>
|
||||
<div v-if="isFetching" class="text-center p-normal fs-default h-full">
|
||||
<div v-if="isFetching" class="text-center p-4 text-base h-full">
|
||||
<spinner size="" />
|
||||
<span>{{ $t('HELP_CENTER.EDIT_ARTICLE.LOADING') }}</span>
|
||||
</div>
|
||||
@@ -45,6 +45,7 @@
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import EditArticleHeader from '../../components/Header/EditArticleHeader.vue';
|
||||
@@ -107,7 +108,11 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
onClickGoBack() {
|
||||
this.$router.push({ name: 'list_all_locale_articles' });
|
||||
if (window.history.length > 2) {
|
||||
this.$router.go(-1);
|
||||
} else {
|
||||
this.$router.push({ name: 'list_all_locale_articles' });
|
||||
}
|
||||
},
|
||||
fetchArticleDetails() {
|
||||
this.$store.dispatch('articles/show', {
|
||||
@@ -210,24 +215,3 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.article-container {
|
||||
display: flex;
|
||||
padding: 0 var(--space-normal);
|
||||
width: 100%;
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
|
||||
.edit-article--container {
|
||||
flex: 1;
|
||||
flex-shrink: 0;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.is-sidebar-open {
|
||||
flex-grow: 1;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
+16
-15
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div
|
||||
class="py-0 px-0 w-full max-w-full overflow-auto bg-white dark:bg-slate-900"
|
||||
class="py-0 px-0 w-full max-w-full overflow-auto bg-white dark:bg-slate-900 flex flex-col"
|
||||
>
|
||||
<article-header
|
||||
:header-title="headerTitle"
|
||||
@@ -8,31 +8,35 @@
|
||||
:selected-locale="activeLocaleName"
|
||||
:all-locales="allowedLocales"
|
||||
selected-value="Published"
|
||||
class="border-b border-slate-50 dark:border-slate-700"
|
||||
@new-article-page="newArticlePage"
|
||||
@change-locale="onChangeLocale"
|
||||
/>
|
||||
<article-table
|
||||
:articles="articles"
|
||||
:current-page="Number(meta.currentPage)"
|
||||
:total-count="Number(meta.count)"
|
||||
@page-change="onPageChange"
|
||||
@reorder="onReorder"
|
||||
/>
|
||||
<div
|
||||
v-if="shouldShowLoader"
|
||||
v-if="isFetching"
|
||||
class="items-center flex text-base justify-center py-6 px-4 text-slate-600 dark:text-slate-200"
|
||||
>
|
||||
<spinner />
|
||||
<span class="text-slate-600 dark:text-slate-200">{{
|
||||
$t('HELP_CENTER.TABLE.LOADING_MESSAGE')
|
||||
}}</span>
|
||||
<span class="text-slate-600 dark:text-slate-200">
|
||||
{{ $t('HELP_CENTER.TABLE.LOADING_MESSAGE') }}
|
||||
</span>
|
||||
</div>
|
||||
<empty-state
|
||||
v-else-if="shouldShowEmptyState"
|
||||
:title="$t('HELP_CENTER.TABLE.NO_ARTICLES')"
|
||||
/>
|
||||
<div v-else class="flex flex-1">
|
||||
<article-table
|
||||
:articles="articles"
|
||||
:current-page="Number(meta.currentPage)"
|
||||
:total-count="Number(meta.count)"
|
||||
@page-change="onPageChange"
|
||||
@reorder="onReorder"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import allLocales from 'shared/constants/locales.js';
|
||||
@@ -72,9 +76,6 @@ export default {
|
||||
shouldShowEmptyState() {
|
||||
return !this.isFetching && !this.articles.length;
|
||||
},
|
||||
shouldShowLoader() {
|
||||
return this.isFetching && !this.articles.length;
|
||||
},
|
||||
selectedPortalSlug() {
|
||||
return this.$route.params.portalSlug;
|
||||
},
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<div class="article-container">
|
||||
<div class="flex flex-1 overflow-auto">
|
||||
<div
|
||||
class="new-article--container"
|
||||
:class="{ 'is-sidebar-open': showArticleSettings }"
|
||||
class="flex-1 overflow-y-auto flex-shrink-0 px-6"
|
||||
:class="{ 'flex-grow-1': showArticleSettings }"
|
||||
>
|
||||
<edit-article-header
|
||||
:back-button-label="$t('HELP_CENTER.HEADER.TITLES.ALL_ARTICLES')"
|
||||
@@ -22,6 +22,7 @@
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import EditArticleHeader from 'dashboard/routes/dashboard/helpcenter/components/Header/EditArticleHeader.vue';
|
||||
@@ -116,22 +117,3 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.article-container {
|
||||
display: flex;
|
||||
padding: 0 var(--space-normal);
|
||||
width: 100%;
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
}
|
||||
.new-article--container {
|
||||
flex: 1;
|
||||
flex-shrink: 0;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.is-sidebar-open {
|
||||
flex: 0.7;
|
||||
flex-grow: 1;
|
||||
}
|
||||
</style>
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
<div class="flex items-center relative">
|
||||
<woot-button
|
||||
variant="hollow"
|
||||
class="absolute [&>span]:flex [&>span]:items-center [&>span]:justify-center z-10 top-[25px] h-[2.45rem] w-[2.45rem] !text-slate-400 dark:!text-slate-600 dark:!bg-slate-900 !p-0"
|
||||
class="absolute [&>span]:flex [&>span]:items-center [&>span]:justify-center z-10 top-[28px] h-[2.5rem] w-[2.45rem] !text-slate-400 dark:!text-slate-600 dark:!bg-slate-900 !p-0"
|
||||
color-scheme="secondary"
|
||||
@click="toggleEmojiPicker"
|
||||
>
|
||||
|
||||
+3
-1
@@ -3,7 +3,9 @@
|
||||
<div class="flex justify-between items-center mt-0 mb-2 mx-0 h-12">
|
||||
<div class="flex items-center">
|
||||
<woot-sidemenu-icon />
|
||||
<h1 class="my-0 mx-2 text-2xl text-slate-800 dark:text-slate-100">
|
||||
<h1
|
||||
class="my-0 mx-2 text-2xl text-slate-800 dark:text-slate-100 font-medium"
|
||||
>
|
||||
{{ $t('HELP_CENTER.PORTAL.HEADER') }}
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
class="flex flex-row overflow-auto py-4 pl-4 rtl:pl-0 rtl:pr-4 h-full bg-slate-50 dark:bg-slate-800"
|
||||
>
|
||||
<woot-wizard
|
||||
class="hide-for-small-only w-[25%]"
|
||||
class="hidden md:block w-1/4"
|
||||
:global-config="globalConfig"
|
||||
:items="items"
|
||||
/>
|
||||
|
||||
+4
-7
@@ -1,5 +1,7 @@
|
||||
<template>
|
||||
<div class="wizard-body w-[75%] flex-shrink-0 flex-grow-0 max-w-[75%] h-auto">
|
||||
<div
|
||||
class="pt-3 bg-white dark:bg-slate-900 h-full border border-solid border-transparent px-6 pb-6 dark:border-transparent w-full max-w-full md:w-3/4 md:max-w-[75%] flex-shrink-0 flex-grow-0"
|
||||
>
|
||||
<empty-state
|
||||
:title="$t('HELP_CENTER.PORTAL.ADD.CREATE_FLOW_PAGE.FINISH_PAGE.TITLE')"
|
||||
:message="
|
||||
@@ -8,7 +10,7 @@
|
||||
>
|
||||
<div class="w-full text-center">
|
||||
<router-link
|
||||
class="button success nice"
|
||||
class="button success nice rounded"
|
||||
:to="{
|
||||
name: 'list_all_portals',
|
||||
}"
|
||||
@@ -35,8 +37,3 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.wizard-body {
|
||||
@apply pb-3;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
<template>
|
||||
<div
|
||||
class="text-center bg-slate-25 dark:bg-slate-800 justify-center w-full h-full hidden md:flex items-center"
|
||||
>
|
||||
<span v-if="uiFlags.isFetching" class="spinner my-4" />
|
||||
<div v-else class="flex flex-col items-center gap-2">
|
||||
<fluent-icon
|
||||
icon="mail-inbox"
|
||||
size="40"
|
||||
class="text-slate-600 dark:text-slate-400"
|
||||
/>
|
||||
<span class="text-slate-500 text-sm font-medium dark:text-slate-300">
|
||||
{{ emptyMessage }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
export default {
|
||||
props: {
|
||||
emptyStateMessage: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
uiFlags: 'notifications/getUIFlags',
|
||||
}),
|
||||
emptyMessage() {
|
||||
if (this.emptyStateMessage) {
|
||||
return this.emptyStateMessage;
|
||||
}
|
||||
return this.$t('INBOX.LIST.NOTE');
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -1,43 +1,47 @@
|
||||
<template>
|
||||
<div
|
||||
class="flex flex-col h-full w-full ltr:border-r border-slate-50 dark:border-slate-800/50"
|
||||
:class="isOnExpandedLayout ? '' : 'min-w-[360px] max-w-[360px]'"
|
||||
>
|
||||
<inbox-list-header @filter="onFilterChange" />
|
||||
<section class="flex w-full h-full bg-white dark:bg-slate-900">
|
||||
<div
|
||||
ref="notificationList"
|
||||
class="flex flex-col w-full h-[calc(100%-56px)] overflow-x-hidden overflow-y-auto"
|
||||
class="flex flex-col h-full w-full md:min-w-[360px] md:max-w-[360px] ltr:border-r border-slate-50 dark:border-slate-800/50"
|
||||
:class="!currentNotificationId ? 'flex' : 'hidden md:flex'"
|
||||
>
|
||||
<inbox-card
|
||||
v-for="notificationItem in notifications"
|
||||
:key="notificationItem.id"
|
||||
:notification-item="notificationItem"
|
||||
@mark-notification-as-read="markNotificationAsRead"
|
||||
@mark-notification-as-unread="markNotificationAsUnRead"
|
||||
@delete-notification="deleteNotification"
|
||||
<inbox-list-header
|
||||
:is-context-menu-open="isInboxContextMenuOpen"
|
||||
@filter="onFilterChange"
|
||||
@redirect="redirectToInbox"
|
||||
/>
|
||||
<div v-if="uiFlags.isFetching" class="text-center">
|
||||
<span class="spinner mt-4 mb-4" />
|
||||
<div
|
||||
ref="notificationList"
|
||||
class="flex flex-col w-full h-[calc(100%-56px)] overflow-x-hidden overflow-y-auto"
|
||||
>
|
||||
<inbox-card
|
||||
v-for="notificationItem in notifications"
|
||||
:key="notificationItem.id"
|
||||
:active="currentNotificationId === notificationItem.id"
|
||||
:notification-item="notificationItem"
|
||||
@mark-notification-as-read="markNotificationAsRead"
|
||||
@mark-notification-as-unread="markNotificationAsUnRead"
|
||||
@delete-notification="deleteNotification"
|
||||
@context-menu-open="isInboxContextMenuOpen = true"
|
||||
@context-menu-close="isInboxContextMenuOpen = false"
|
||||
/>
|
||||
<div v-if="uiFlags.isFetching" class="text-center">
|
||||
<span class="spinner mt-4 mb-4" />
|
||||
</div>
|
||||
<p
|
||||
v-if="showEmptyState"
|
||||
class="text-center text-slate-400 text-sm dark:text-slate-400 p-4 font-medium"
|
||||
>
|
||||
{{ $t('INBOX.LIST.NO_NOTIFICATIONS') }}
|
||||
</p>
|
||||
<intersection-observer
|
||||
v-if="!showEndOfList && !uiFlags.isFetching"
|
||||
:options="infiniteLoaderOptions"
|
||||
@observed="loadMoreNotifications"
|
||||
/>
|
||||
</div>
|
||||
<p
|
||||
v-if="showEmptyState"
|
||||
class="text-center text-slate-400 text-sm dark:text-slate-400 p-4 font-medium"
|
||||
>
|
||||
{{ $t('INBOX.LIST.NO_NOTIFICATIONS') }}
|
||||
</p>
|
||||
<p
|
||||
v-if="showEndOfListMessage"
|
||||
class="text-center text-slate-400 dark:text-slate-400 p-4"
|
||||
>
|
||||
{{ $t('INBOX.LIST.EOF') }}
|
||||
</p>
|
||||
<intersection-observer
|
||||
v-if="!showEndOfList && !uiFlags.isFetching"
|
||||
:options="infiniteLoaderOptions"
|
||||
@observed="loadMoreNotifications"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<router-view />
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@@ -49,6 +53,7 @@ import { INBOX_EVENTS } from 'dashboard/helper/AnalyticsHelper/events';
|
||||
import IntersectionObserver from 'dashboard/components/IntersectionObserver.vue';
|
||||
import alertMixin from 'shared/mixins/alertMixin';
|
||||
import uiSettingsMixin from 'dashboard/mixins/uiSettings';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
InboxCard,
|
||||
@@ -56,16 +61,6 @@ export default {
|
||||
IntersectionObserver,
|
||||
},
|
||||
mixins: [alertMixin, uiSettingsMixin],
|
||||
props: {
|
||||
conversationId: {
|
||||
type: [String, Number],
|
||||
default: 0,
|
||||
},
|
||||
isOnExpandedLayout: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
infiniteLoaderOptions: {
|
||||
@@ -76,6 +71,8 @@ export default {
|
||||
status: '',
|
||||
type: '',
|
||||
sortOrder: wootConstants.INBOX_SORT_BY.NEWEST,
|
||||
isInboxContextMenuOpen: false,
|
||||
notificationIdToSnooze: null,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -85,6 +82,9 @@ export default {
|
||||
uiFlags: 'notifications/getUIFlags',
|
||||
notification: 'notifications/getFilteredNotifications',
|
||||
}),
|
||||
currentNotificationId() {
|
||||
return Number(this.$route.params.notification_id);
|
||||
},
|
||||
inboxFilters() {
|
||||
return {
|
||||
page: this.page,
|
||||
@@ -102,9 +102,6 @@ export default {
|
||||
showEmptyState() {
|
||||
return !this.uiFlags.isFetching && !this.notifications.length;
|
||||
},
|
||||
showEndOfListMessage() {
|
||||
return this.showEndOfList && this.notifications.length;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.setSavedFilter();
|
||||
@@ -115,13 +112,11 @@ export default {
|
||||
this.page = 1;
|
||||
this.$store.dispatch('notifications/clear');
|
||||
const filter = this.inboxFilters;
|
||||
|
||||
this.$store.dispatch('notifications/index', filter);
|
||||
},
|
||||
redirectToInbox() {
|
||||
if (!this.conversationId) return;
|
||||
if (this.$route.name === 'inbox_view') return;
|
||||
this.$router.push({ name: 'inbox_view' });
|
||||
this.$router.replace({ name: 'inbox_view' });
|
||||
},
|
||||
loadMoreNotifications() {
|
||||
if (this.uiFlags.isAllNotificationsLoaded) return;
|
||||
@@ -177,13 +172,14 @@ export default {
|
||||
});
|
||||
},
|
||||
onFilterChange(option) {
|
||||
if (option.type === wootConstants.INBOX_FILTER_TYPE.STATUS) {
|
||||
const { STATUS, TYPE, SORT_ORDER } = wootConstants.INBOX_FILTER_TYPE;
|
||||
if (option.type === STATUS) {
|
||||
this.status = option.selected ? option.key : '';
|
||||
}
|
||||
if (option.type === wootConstants.INBOX_FILTER_TYPE.TYPE) {
|
||||
if (option.type === TYPE) {
|
||||
this.type = option.selected ? option.key : '';
|
||||
}
|
||||
if (option.type === wootConstants.INBOX_FILTER_TYPE.SORT_ORDER) {
|
||||
if (option.type === SORT_ORDER) {
|
||||
this.sortOrder = option.key;
|
||||
}
|
||||
this.fetchNotifications();
|
||||
|
||||
@@ -1,127 +1,102 @@
|
||||
<template>
|
||||
<section class="flex w-full h-full bg-white dark:bg-slate-900">
|
||||
<inbox-list
|
||||
v-show="showConversationList"
|
||||
:conversation-id="conversationId"
|
||||
:is-on-expanded-layout="isOnExpandedLayout"
|
||||
/>
|
||||
<div
|
||||
v-if="showInboxMessageView"
|
||||
class="flex flex-col h-full"
|
||||
:class="isOnExpandedLayout ? 'w-full' : 'w-[calc(100%-360px)]'"
|
||||
>
|
||||
<div class="h-full w-full md:w-[calc(100%-360px)]">
|
||||
<div v-if="showEmptyState" class="flex w-full h-full">
|
||||
<inbox-empty-state
|
||||
:empty-state-message="$t('INBOX.LIST.NO_MESSAGES_AVAILABLE')"
|
||||
/>
|
||||
</div>
|
||||
<div v-else class="flex flex-col h-full w-full">
|
||||
<inbox-item-header
|
||||
:total-length="totalNotifications"
|
||||
class="flex-1"
|
||||
:total-length="totalNotificationCount"
|
||||
:current-index="activeNotificationIndex"
|
||||
:active-notification="activeNotification"
|
||||
@next="onClickNext"
|
||||
@prev="onClickPrev"
|
||||
/>
|
||||
<div
|
||||
v-if="isConversationLoading"
|
||||
class="flex items-center h-[calc(100%-56px)] justify-center bg-slate-25 dark:bg-slate-800"
|
||||
>
|
||||
<span class="spinner my-4" />
|
||||
</div>
|
||||
<conversation-box
|
||||
v-else
|
||||
class="h-[calc(100%-56px)]"
|
||||
is-inbox-view
|
||||
:inbox-id="inboxId"
|
||||
:is-contact-panel-open="isContactPanelOpen"
|
||||
:is-on-expanded-layout="isOnExpandedLayout"
|
||||
:is-on-expanded-layout="false"
|
||||
@contact-panel-toggle="onToggleContactPanel"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-if="!showInboxMessageView && !isOnExpandedLayout"
|
||||
class="text-center bg-slate-25 dark:bg-slate-800 justify-center w-full h-full flex items-center"
|
||||
>
|
||||
<span v-if="uiFlags.isFetching" class="spinner mt-4 mb-4" />
|
||||
<div v-else class="flex flex-col items-center gap-2">
|
||||
<fluent-icon
|
||||
icon="mail-inbox"
|
||||
size="40"
|
||||
class="text-slate-600 dark:text-slate-400"
|
||||
/>
|
||||
<span class="text-slate-500 text-sm font-medium dark:text-slate-300">
|
||||
{{ $t('INBOX.LIST.NOTE') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import InboxList from './InboxList.vue';
|
||||
import InboxItemHeader from './components/InboxItemHeader.vue';
|
||||
import ConversationBox from 'dashboard/components/widgets/conversation/ConversationBox.vue';
|
||||
import InboxEmptyState from './InboxEmptyState.vue';
|
||||
import uiSettingsMixin from 'dashboard/mixins/uiSettings';
|
||||
import wootConstants from 'dashboard/constants/globals';
|
||||
import { FEATURE_FLAGS } from 'dashboard/featureFlags';
|
||||
import { BUS_EVENTS } from 'shared/constants/busEvents';
|
||||
import { INBOX_EVENTS } from 'dashboard/helper/AnalyticsHelper/events';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
InboxList,
|
||||
InboxItemHeader,
|
||||
InboxEmptyState,
|
||||
ConversationBox,
|
||||
},
|
||||
mixins: [uiSettingsMixin],
|
||||
props: {
|
||||
inboxId: {
|
||||
type: [String, Number],
|
||||
default: 0,
|
||||
},
|
||||
conversationId: {
|
||||
type: [String, Number],
|
||||
default: 0,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isConversationLoading: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
currentAccountId: 'getCurrentAccountId',
|
||||
notifications: 'notifications/getNotifications',
|
||||
notification: 'notifications/getFilteredNotifications',
|
||||
currentChat: 'getSelectedChat',
|
||||
allConversation: 'getAllConversations',
|
||||
activeNotificationById: 'notifications/getNotificationById',
|
||||
conversationById: 'getConversationById',
|
||||
uiFlags: 'notifications/getUIFlags',
|
||||
meta: 'notifications/getMeta',
|
||||
}),
|
||||
notifications() {
|
||||
return this.notification({
|
||||
sortOrder: this.activeSortOrder,
|
||||
});
|
||||
},
|
||||
inboxId() {
|
||||
return Number(this.$route.params.inboxId);
|
||||
},
|
||||
notificationId() {
|
||||
return Number(this.$route.params.notification_id);
|
||||
},
|
||||
activeNotification() {
|
||||
return this.notifications.find(
|
||||
n => n.primary_actor.id === Number(this.conversationId)
|
||||
);
|
||||
return this.activeNotificationById(this.notificationId);
|
||||
},
|
||||
isInboxViewEnabled() {
|
||||
return this.$store.getters['accounts/isFeatureEnabledGlobally'](
|
||||
this.currentAccountId,
|
||||
FEATURE_FLAGS.INBOX_VIEW
|
||||
);
|
||||
conversationId() {
|
||||
return this.activeNotification?.primary_actor?.id;
|
||||
},
|
||||
showConversationList() {
|
||||
return this.isOnExpandedLayout ? !this.conversationId : true;
|
||||
totalNotificationCount() {
|
||||
return this.meta.count;
|
||||
},
|
||||
isFetchingInitialData() {
|
||||
return this.uiFlags.isFetching && !this.notifications.length;
|
||||
},
|
||||
showInboxMessageView() {
|
||||
showEmptyState() {
|
||||
return (
|
||||
Boolean(this.conversationId) &&
|
||||
Boolean(this.currentChat.id) &&
|
||||
!this.isFetchingInitialData
|
||||
!this.conversationId ||
|
||||
(!this.notifications?.length && this.uiFlags.isFetching)
|
||||
);
|
||||
},
|
||||
totalNotifications() {
|
||||
return this.notifications?.length ?? 0;
|
||||
},
|
||||
activeNotificationIndex() {
|
||||
const conversationId = Number(this.conversationId);
|
||||
const notificationIndex = this.notifications.findIndex(
|
||||
n => n.primary_actor.id === conversationId
|
||||
);
|
||||
return notificationIndex >= 0 ? notificationIndex + 1 : 0;
|
||||
return this.notifications?.findIndex(n => n.id === this.notificationId);
|
||||
},
|
||||
isOnExpandedLayout() {
|
||||
const {
|
||||
LAYOUT_TYPES: { CONDENSED },
|
||||
} = wootConstants;
|
||||
const { conversation_display_type: conversationDisplayType = CONDENSED } =
|
||||
this.uiSettings;
|
||||
return conversationDisplayType !== CONDENSED;
|
||||
activeSortOrder() {
|
||||
const { inbox_filter_by: filterBy = {} } = this.uiSettings;
|
||||
const { sort_by: sortBy } = filterBy;
|
||||
return sortBy || 'desc';
|
||||
},
|
||||
isContactPanelOpen() {
|
||||
if (this.currentChat.id) {
|
||||
@@ -135,29 +110,29 @@ export default {
|
||||
watch: {
|
||||
conversationId: {
|
||||
immediate: true,
|
||||
handler() {
|
||||
this.fetchConversationById();
|
||||
handler(newVal, oldVal) {
|
||||
if (newVal !== oldVal) {
|
||||
this.fetchConversationById();
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
// Open inbox view if inbox view feature is enabled, else redirect to dashboard
|
||||
// TODO: Remove this code once inbox view feature is enabled for all accounts
|
||||
if (!this.isInboxViewEnabled) {
|
||||
this.$router.push({
|
||||
name: 'home',
|
||||
});
|
||||
}
|
||||
this.$store.dispatch('agents/get');
|
||||
},
|
||||
methods: {
|
||||
async fetchConversationById() {
|
||||
if (!this.conversationId) return;
|
||||
const chat = this.findConversation();
|
||||
if (!chat) {
|
||||
await this.$store.dispatch('getConversation', this.conversationId);
|
||||
if (!this.notificationId || !this.conversationId) return;
|
||||
this.$store.dispatch('clearSelectedState');
|
||||
const existingChat = this.findConversation();
|
||||
if (existingChat) {
|
||||
this.setActiveChat(existingChat);
|
||||
return;
|
||||
}
|
||||
this.isConversationLoading = true;
|
||||
await this.$store.dispatch('getConversation', this.conversationId);
|
||||
this.setActiveChat();
|
||||
this.isConversationLoading = false;
|
||||
},
|
||||
setActiveChat() {
|
||||
const selectedConversation = this.findConversation();
|
||||
@@ -169,37 +144,47 @@ export default {
|
||||
});
|
||||
},
|
||||
findConversation() {
|
||||
const conversationId = Number(this.conversationId);
|
||||
return this.allConversation.find(c => c.id === conversationId);
|
||||
return this.conversationById(this.conversationId);
|
||||
},
|
||||
navigateToConversation(activeIndex, direction) {
|
||||
const indexOffset = direction === 'next' ? 0 : -2;
|
||||
const targetNotification = this.notifications[activeIndex + indexOffset];
|
||||
if (targetNotification) {
|
||||
const {
|
||||
id,
|
||||
primary_actor_id: primaryActorId,
|
||||
primary_actor_type: primaryActorType,
|
||||
primary_actor: { id: conversationId, meta: { unreadCount } = {} },
|
||||
notification_type: notificationType,
|
||||
} = targetNotification;
|
||||
|
||||
this.$track(INBOX_EVENTS.OPEN_CONVERSATION_VIA_INBOX, {
|
||||
notificationType,
|
||||
});
|
||||
|
||||
this.$store.dispatch('notifications/read', {
|
||||
id,
|
||||
primaryActorId,
|
||||
primaryActorType,
|
||||
unreadCount,
|
||||
});
|
||||
|
||||
this.$router.push({
|
||||
name: 'inbox_view_conversation',
|
||||
params: { conversation_id: conversationId },
|
||||
});
|
||||
let updatedIndex;
|
||||
if (direction === 'prev' && activeIndex) {
|
||||
updatedIndex = activeIndex - 1;
|
||||
} else if (
|
||||
direction === 'next' &&
|
||||
activeIndex < this.totalNotificationCount
|
||||
) {
|
||||
updatedIndex = activeIndex + 1;
|
||||
}
|
||||
const targetNotification = this.notifications[updatedIndex];
|
||||
if (targetNotification) {
|
||||
this.openNotification(targetNotification);
|
||||
}
|
||||
},
|
||||
openNotification(notification) {
|
||||
const {
|
||||
id,
|
||||
primary_actor_id: primaryActorId,
|
||||
primary_actor_type: primaryActorType,
|
||||
primary_actor: { meta: { unreadCount } = {} },
|
||||
notification_type: notificationType,
|
||||
} = notification;
|
||||
|
||||
this.$track(INBOX_EVENTS.OPEN_CONVERSATION_VIA_INBOX, {
|
||||
notificationType,
|
||||
});
|
||||
|
||||
this.$store.dispatch('notifications/read', {
|
||||
id,
|
||||
primaryActorId,
|
||||
primaryActorType,
|
||||
unreadCount,
|
||||
});
|
||||
|
||||
this.$router.push({
|
||||
name: 'inbox_view_conversation',
|
||||
params: { notification_id: id },
|
||||
});
|
||||
},
|
||||
onClickNext() {
|
||||
this.navigateToConversation(this.activeNotificationIndex, 'next');
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
role="button"
|
||||
class="flex flex-col ltr:pl-5 rtl:pl-3 rtl:pr-5 ltr:pr-3 gap-2.5 py-3 w-full border-b border-slate-50 dark:border-slate-800/50 hover:bg-slate-25 dark:hover:bg-slate-800 cursor-pointer"
|
||||
:class="
|
||||
isInboxCardActive
|
||||
active
|
||||
? 'bg-slate-25 dark:bg-slate-800 click-animation'
|
||||
: 'bg-white dark:bg-slate-900'
|
||||
"
|
||||
@@ -23,26 +23,21 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row justify-between items-center w-full">
|
||||
<div class="flex gap-1.5 items-center max-w-[calc(100%-70px)]">
|
||||
<Thumbnail
|
||||
v-if="assigneeMeta"
|
||||
:src="assigneeMeta.thumbnail"
|
||||
:username="assigneeMeta.name"
|
||||
size="16px"
|
||||
class="relative bottom-0.5"
|
||||
/>
|
||||
<div class="flex min-w-0">
|
||||
<span
|
||||
class="text-slate-800 dark:text-slate-50 text-sm overflow-hidden text-ellipsis whitespace-nowrap"
|
||||
:class="isUnread ? 'font-medium' : 'font-normal'"
|
||||
>
|
||||
{{ pushTitle }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-row justify-between items-center w-full gap-2">
|
||||
<Thumbnail
|
||||
v-if="assigneeMeta"
|
||||
:src="assigneeMeta.thumbnail"
|
||||
:username="assigneeMeta.name"
|
||||
size="16px"
|
||||
/>
|
||||
<span
|
||||
class="font-medium max-w-[60px] text-slate-600 dark:text-slate-300 text-xs whitespace-nowrap"
|
||||
class="flex-1 text-slate-800 dark:text-slate-50 text-sm overflow-hidden text-ellipsis whitespace-nowrap"
|
||||
:class="isUnread ? 'font-medium' : 'font-normal'"
|
||||
>
|
||||
{{ pushTitle }}
|
||||
</span>
|
||||
<span
|
||||
class="font-medium text-slate-600 dark:text-slate-300 text-xs whitespace-nowrap"
|
||||
>
|
||||
{{ lastActivityAt }}
|
||||
</span>
|
||||
@@ -61,6 +56,7 @@
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import PriorityIcon from './PriorityIcon.vue';
|
||||
import StatusIcon from './StatusIcon.vue';
|
||||
@@ -84,6 +80,10 @@ export default {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
active: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -95,9 +95,6 @@ export default {
|
||||
primaryActor() {
|
||||
return this.notificationItem?.primary_actor;
|
||||
},
|
||||
isInboxCardActive() {
|
||||
return this.$route.params.conversation_id === this.primaryActor?.id;
|
||||
},
|
||||
inbox() {
|
||||
return this.$store.getters['inboxes/getInbox'](
|
||||
this.primaryActor.inbox_id
|
||||
@@ -166,11 +163,11 @@ export default {
|
||||
id,
|
||||
primary_actor_id: primaryActorId,
|
||||
primary_actor_type: primaryActorType,
|
||||
primary_actor: { id: conversationId, inbox_id: inboxId },
|
||||
primary_actor: { inbox_id: inboxId },
|
||||
notification_type: notificationType,
|
||||
} = notification;
|
||||
|
||||
if (this.$route.params.conversation_id !== conversationId) {
|
||||
if (this.$route.params.notification_id !== id) {
|
||||
this.$track(INBOX_EVENTS.OPEN_CONVERSATION_VIA_INBOX, {
|
||||
notificationType,
|
||||
});
|
||||
@@ -184,13 +181,14 @@ export default {
|
||||
|
||||
this.$router.push({
|
||||
name: 'inbox_view_conversation',
|
||||
params: { inboxId, conversation_id: conversationId },
|
||||
params: { inboxId, notification_id: id },
|
||||
});
|
||||
}
|
||||
},
|
||||
closeContextMenu() {
|
||||
this.isContextMenuOpen = false;
|
||||
this.contextMenuPosition = { x: null, y: null };
|
||||
this.$emit('context-menu-close');
|
||||
},
|
||||
openContextMenu(e) {
|
||||
this.closeContextMenu();
|
||||
@@ -200,6 +198,7 @@ export default {
|
||||
y: e.pageY || e.clientY,
|
||||
};
|
||||
this.isContextMenuOpen = true;
|
||||
this.$emit('context-menu-open');
|
||||
},
|
||||
handleAction(key) {
|
||||
switch (key) {
|
||||
@@ -218,17 +217,21 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.click-animation {
|
||||
animation: click-animation 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
@keyframes click-animation {
|
||||
0% {
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: scale(0.99);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
@@ -2,10 +2,20 @@
|
||||
<div
|
||||
class="flex gap-2 py-2 ltr:pl-4 rtl:pl-2 h-14 ltr:pr-2 rtl:pr-4 rtl:border-r justify-between items-center w-full border-b border-slate-50 dark:border-slate-800/50"
|
||||
>
|
||||
<woot-button
|
||||
variant="clear link"
|
||||
class="flex md:hidden !pt-1 !pb-1 rounded-md ltr:pr-1 rtl:pl-1 !no-underline"
|
||||
size="medium"
|
||||
color-scheme="primary"
|
||||
icon="chevron-left"
|
||||
@click="onClickGoToInboxList"
|
||||
>
|
||||
{{ $t('INBOX.ACTION_HEADER.BACK') }}
|
||||
</woot-button>
|
||||
<pagination-button
|
||||
v-if="totalLength > 1"
|
||||
:total-length="totalLength"
|
||||
:current-index="currentIndex"
|
||||
:current-index="currentIndex + 1"
|
||||
@next="onClickNext"
|
||||
@prev="onClickPrev"
|
||||
/>
|
||||
@@ -16,6 +26,7 @@
|
||||
size="small"
|
||||
color-scheme="secondary"
|
||||
icon="snooze"
|
||||
class="[&>span]:hidden md:[&>span]:inline-flex"
|
||||
@click="openSnoozeNotificationModal"
|
||||
>
|
||||
{{ $t('INBOX.ACTION_HEADER.SNOOZE') }}
|
||||
@@ -25,6 +36,7 @@
|
||||
size="small"
|
||||
color-scheme="secondary"
|
||||
variant="hollow"
|
||||
class="[&>span]:hidden md:[&>span]:inline-flex"
|
||||
@click="deleteNotification"
|
||||
>
|
||||
{{ $t('INBOX.ACTION_HEADER.DELETE') }}
|
||||
@@ -41,6 +53,7 @@
|
||||
</woot-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import { getUnixTime } from 'date-fns';
|
||||
@@ -73,14 +86,10 @@ export default {
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showCustomSnoozeModal: false,
|
||||
};
|
||||
return { showCustomSnoozeModal: false };
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
meta: 'notifications/getMeta',
|
||||
}),
|
||||
...mapGetters({ meta: 'notifications/getMeta' }),
|
||||
},
|
||||
mounted() {
|
||||
bus.$on(CMD_SNOOZE_NOTIFICATION, this.onCmdSnoozeNotification);
|
||||
@@ -96,15 +105,17 @@ export default {
|
||||
hideCustomSnoozeModal() {
|
||||
this.showCustomSnoozeModal = false;
|
||||
},
|
||||
snoozeNotification(snoozedUntil) {
|
||||
this.$store
|
||||
.dispatch('notifications/snooze', {
|
||||
async snoozeNotification(snoozedUntil) {
|
||||
try {
|
||||
await this.$store.dispatch('notifications/snooze', {
|
||||
id: this.activeNotification?.id,
|
||||
snoozedUntil,
|
||||
})
|
||||
.then(() => {
|
||||
this.showAlert(this.$t('INBOX.ALERTS.SNOOZE'));
|
||||
});
|
||||
|
||||
this.showAlert(this.$t('INBOX.ALERTS.SNOOZE'));
|
||||
} catch (error) {
|
||||
// Silently fail without any change in the UI
|
||||
}
|
||||
},
|
||||
onCmdSnoozeNotification(snoozeType) {
|
||||
if (snoozeType === wootConstants.SNOOZE_OPTIONS.UNTIL_CUSTOM_TIME) {
|
||||
@@ -132,7 +143,7 @@ export default {
|
||||
.then(() => {
|
||||
this.showAlert(this.$t('INBOX.ALERTS.DELETE'));
|
||||
});
|
||||
this.$router.push({ name: 'inbox_view' });
|
||||
this.$router.replace({ name: 'inbox_view' });
|
||||
},
|
||||
onClickNext() {
|
||||
this.$emit('next');
|
||||
@@ -140,6 +151,9 @@ export default {
|
||||
onClickPrev() {
|
||||
this.$emit('prev');
|
||||
},
|
||||
onClickGoToInboxList() {
|
||||
this.$router.replace({ name: 'inbox_view' });
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
<inbox-display-menu
|
||||
v-if="showInboxDisplayMenu"
|
||||
v-on-clickaway="openInboxDisplayMenu"
|
||||
class="absolute top-8"
|
||||
class="absolute top-9 ltr:left-0 rtl:right-0"
|
||||
@filter="onFilterChange"
|
||||
/>
|
||||
</div>
|
||||
@@ -49,7 +49,7 @@
|
||||
<inbox-option-menu
|
||||
v-if="showInboxOptionMenu"
|
||||
v-on-clickaway="openInboxOptionsMenu"
|
||||
class="absolute top-9"
|
||||
class="absolute top-9 ltr:right-0 ltr:md:right-[unset] rtl:left-0 rtl:md:left-[unset]"
|
||||
@option-click="onInboxOptionMenuClick"
|
||||
/>
|
||||
</div>
|
||||
@@ -69,12 +69,29 @@ export default {
|
||||
InboxDisplayMenu,
|
||||
},
|
||||
mixins: [clickaway, alertMixin],
|
||||
props: {
|
||||
isContextMenuOpen: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showInboxDisplayMenu: false,
|
||||
showInboxOptionMenu: false,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
isContextMenuOpen: {
|
||||
handler(val) {
|
||||
if (val) {
|
||||
this.showInboxDisplayMenu = false;
|
||||
this.showInboxOptionMenu = false;
|
||||
}
|
||||
},
|
||||
immediate: true,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
markAllRead() {
|
||||
this.$track(INBOX_EVENTS.MARK_ALL_NOTIFICATIONS_AS_READ);
|
||||
@@ -99,22 +116,19 @@ export default {
|
||||
this.showInboxOptionMenu = !this.showInboxOptionMenu;
|
||||
},
|
||||
onInboxOptionMenuClick(key) {
|
||||
this.showInboxOptionMenu = false;
|
||||
if (key === 'mark_all_read') {
|
||||
this.markAllRead();
|
||||
}
|
||||
if (key === 'delete_all') {
|
||||
this.deleteAll();
|
||||
}
|
||||
if (key === 'delete_all_read') {
|
||||
this.deleteAllRead();
|
||||
}
|
||||
const actions = {
|
||||
mark_all_read: () => this.markAllRead(),
|
||||
delete_all: () => this.deleteAll(),
|
||||
delete_all_read: () => this.deleteAllRead(),
|
||||
};
|
||||
const action = actions[key];
|
||||
if (action) action();
|
||||
this.$emit('redirect');
|
||||
},
|
||||
onFilterChange(option) {
|
||||
this.$emit('filter', option);
|
||||
this.showInboxDisplayMenu = false;
|
||||
if (this.$route.name === 'inbox_view') return;
|
||||
this.$router.push({ name: 'inbox_view' });
|
||||
this.$emit('redirect');
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
<script setup>
|
||||
import { defineProps, defineEmits } from 'vue';
|
||||
|
||||
defineProps({
|
||||
label: {
|
||||
type: String,
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="flex items-center gap-1 whitespace-nowrap">
|
||||
<span class="text-sm font-medium text-gray-600">
|
||||
<span class="text-sm font-medium text-gray-600 tabular-nums">
|
||||
{{ totalLength <= 1 ? '1' : currentIndex }}
|
||||
</span>
|
||||
<span
|
||||
@@ -28,7 +28,7 @@
|
||||
>
|
||||
/
|
||||
</span>
|
||||
<span v-if="totalLength > 1" class="text-sm text-slate-400">
|
||||
<span v-if="totalLength > 1" class="text-sm text-slate-400 tabular-nums">
|
||||
{{ totalLength }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import { frontendURL } from 'dashboard/helper/URLHelper';
|
||||
const InboxListView = () => import('./InboxList.vue');
|
||||
const InboxDetailView = () => import('./InboxView.vue');
|
||||
const InboxEmptyStateView = () => import('./InboxEmptyState.vue');
|
||||
|
||||
export const routes = [
|
||||
{
|
||||
path: frontendURL('accounts/:accountId/inbox-view'),
|
||||
component: InboxListView,
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: 'inbox_view',
|
||||
component: InboxEmptyStateView,
|
||||
roles: ['administrator', 'agent'],
|
||||
},
|
||||
{
|
||||
path: ':notification_id',
|
||||
name: 'inbox_view_conversation',
|
||||
component: InboxDetailView,
|
||||
roles: ['administrator', 'agent'],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
+1
-3
@@ -139,9 +139,7 @@ export default {
|
||||
uiFlags: 'notifications/getUIFlags',
|
||||
}),
|
||||
notificationPanelFooterIconClass() {
|
||||
return this.isRTLView
|
||||
? 'margin-right-minus-slab'
|
||||
: 'margin-left-minus-slab';
|
||||
return this.isRTLView ? '-mr-3' : '-ml-3';
|
||||
},
|
||||
totalUnreadNotifications() {
|
||||
return this.meta.unreadCount;
|
||||
|
||||
+2
-1
@@ -1,9 +1,10 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="w-full">
|
||||
<woot-button
|
||||
size="expanded"
|
||||
color-scheme="secondary"
|
||||
variant="link"
|
||||
class="w-full"
|
||||
@click="onClickOpenNotification()"
|
||||
>
|
||||
<div
|
||||
|
||||
+3
-5
@@ -1,5 +1,7 @@
|
||||
<template>
|
||||
<section class="notification--table-wrap bg-white dark:bg-slate-900">
|
||||
<section
|
||||
class="h-full flex-shrink flex-grow overflow-hidden py-8 px-4 bg-white dark:bg-slate-900"
|
||||
>
|
||||
<woot-submit-button
|
||||
v-if="notificationMetadata.unreadCount"
|
||||
class="button nice success button--fixed-top"
|
||||
@@ -136,10 +138,6 @@ export default {
|
||||
@apply text-sm m-0 text-slate-800 dark:text-slate-100;
|
||||
}
|
||||
|
||||
.notification--table-wrap {
|
||||
@apply overflow-hidden hover:overflow-y-auto flex-shrink flex-grow h-full py-8 px-12;
|
||||
}
|
||||
|
||||
.notifications-table {
|
||||
> tbody {
|
||||
> tr {
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="columns notification--page">
|
||||
<div class="notification--content medium-12">
|
||||
<div class="overflow-y-auto h-full">
|
||||
<div class="flex flex-col h-full">
|
||||
<notification-table
|
||||
:notifications="records"
|
||||
:is-loading="uiFlags.isFetching"
|
||||
|
||||
@@ -15,15 +15,17 @@
|
||||
v-if="icon"
|
||||
:icon="icon"
|
||||
:class="iconClass"
|
||||
class="mr-2 ml-4 rtl:ml-2 rtl:mr-4"
|
||||
class="mr-2 ml-1 rtl:ml-2 rtl:mr-1 hidden md:block"
|
||||
/>
|
||||
<slot />
|
||||
<span class="text-slate-900 dark:text-slate-100">{{ headerTitle }}</span>
|
||||
<span class="text-slate-900 font-medium text-2xl dark:text-slate-100">
|
||||
{{ headerTitle }}
|
||||
</span>
|
||||
</h1>
|
||||
<router-link
|
||||
v-if="showNewButton && isAdmin"
|
||||
:to="buttonRoute"
|
||||
class="button success button--fixed-top"
|
||||
class="button success button--fixed-top px-3.5 py-1 rounded-[5px] flex gap-2"
|
||||
>
|
||||
<fluent-icon icon="add-circle" />
|
||||
<span class="button__content">
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
<script setup>
|
||||
defineProps({
|
||||
isLoading: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
loadingMessage: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<div class="flex flex-col w-full h-full gap-10 font-inter">
|
||||
<slot name="header" />
|
||||
<div>
|
||||
<slot v-if="isLoading" name="loading">
|
||||
<woot-loading-state :message="loadingMessage" />
|
||||
</slot>
|
||||
<slot v-else name="body" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,6 +1,8 @@
|
||||
<template>
|
||||
<div class="flex flex-col w-full items-start">
|
||||
<h2 class="text-xl text-slate-800 dark:text-slate-100 break-words">
|
||||
<h2
|
||||
class="text-xl font-medium mb-1 text-slate-800 dark:text-slate-100 break-words"
|
||||
>
|
||||
{{ headerTitle }}
|
||||
</h2>
|
||||
<p
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
<script setup>
|
||||
defineProps({
|
||||
keepAlive: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="flex flex-col w-full h-full px-5 pt-8 pb-3 m-0 overflow-auto bg-white sm:px-16 sm:pt-16 dark:bg-slate-900"
|
||||
>
|
||||
<div class="flex items-start max-w-[900px] w-full">
|
||||
<keep-alive v-if="keepAlive">
|
||||
<router-view />
|
||||
</keep-alive>
|
||||
<router-view v-else />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div
|
||||
class="flex flex-1 h-full justify-between flex-col m-0 bg-slate-25 dark:bg-slate-900"
|
||||
class="flex flex-1 h-full justify-between flex-col m-0 bg-slate-25 dark:bg-slate-900 overflow-auto"
|
||||
>
|
||||
<settings-header
|
||||
button-route="new"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<div
|
||||
class="flex-grow-0 flex-shrink-0 flex-[25%] min-w-0 py-4 pr-6 pl-0"
|
||||
>
|
||||
<h4 class="block-title text-black-900 dark:text-slate-200">
|
||||
<h4 class="text-lg font-medium text-black-900 dark:text-slate-200">
|
||||
{{ $t('GENERAL_SETTINGS.FORM.GENERAL_SECTION.TITLE') }}
|
||||
</h4>
|
||||
<p>{{ $t('GENERAL_SETTINGS.FORM.GENERAL_SECTION.NOTE') }}</p>
|
||||
@@ -87,12 +87,12 @@
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="p-4 border-slate-25 dark:border-slate-700 text-black-900 dark:text-slate-300 row"
|
||||
class="p-4 border-slate-25 dark:border-slate-700 text-black-900 dark:text-slate-300 flex flex-row"
|
||||
>
|
||||
<div
|
||||
class="flex-grow-0 flex-shrink-0 flex-[25%] min-w-0 py-4 pr-6 pl-0"
|
||||
>
|
||||
<h4 class="block-title text-black-900 dark:text-slate-200">
|
||||
<h4 class="text-lg font-medium text-black-900 dark:text-slate-200">
|
||||
{{ $t('GENERAL_SETTINGS.FORM.ACCOUNT_ID.TITLE') }}
|
||||
</h4>
|
||||
<p>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="flex-1 overflow-auto p-4">
|
||||
<div class="flex flex-row gap-4">
|
||||
<div class="w-[60%]">
|
||||
<div class="w-full lg:w-3/5">
|
||||
<woot-loading-state
|
||||
v-if="uiFlags.isFetching"
|
||||
:message="$t('AGENT_BOTS.LIST.LOADING')"
|
||||
@@ -23,7 +23,7 @@
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="w-[34%]">
|
||||
<div class="hidden lg:block w-1/3">
|
||||
<p v-html="$t('AGENT_BOTS.SIDEBAR_TXT')" />
|
||||
</div>
|
||||
</div>
|
||||
@@ -94,9 +94,11 @@ export default {
|
||||
.bots-list {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.nowrap {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.white-text {
|
||||
color: white;
|
||||
}
|
||||
|
||||
+2
-11
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<tr>
|
||||
<tr class="space-x-2">
|
||||
<td class="agent-bot--details">
|
||||
<div class="agent-bot--link">
|
||||
{{ agentBot.name }}
|
||||
@@ -9,7 +9,7 @@
|
||||
<show-more :text="agentBot.description" :limit="120" />
|
||||
</div>
|
||||
</td>
|
||||
<td class="button-wrapper">
|
||||
<td class="flex justify-end gap-1">
|
||||
<woot-button
|
||||
v-if="isACSMLTypeBot"
|
||||
v-tooltip.top="$t('AGENT_BOTS.EDIT.BUTTON_TEXT')"
|
||||
@@ -75,13 +75,4 @@ export default {
|
||||
.agent-bot--details {
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
.button-wrapper {
|
||||
max-width: var(--space-mega);
|
||||
min-width: auto;
|
||||
|
||||
button:nth-child(2) {
|
||||
margin-left: var(--space-normal);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<span>
|
||||
<span class="inline-flex items-center gap-1">
|
||||
<img
|
||||
v-tooltip="botTypeConfig[botType].label"
|
||||
class="agent-bot-type--thumbnail"
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
<!-- List Agents -->
|
||||
<div class="flex flex-row gap-4">
|
||||
<div class="w-[60%]">
|
||||
<div class="w-full lg:w-3/5">
|
||||
<woot-loading-state
|
||||
v-if="uiFlags.isFetching"
|
||||
:message="$t('AGENT_MGMT.LOADING')"
|
||||
@@ -27,7 +27,6 @@
|
||||
<td>
|
||||
<thumbnail
|
||||
:src="agent.thumbnail"
|
||||
class="columns"
|
||||
:username="agent.name"
|
||||
size="40px"
|
||||
:status="agent.availability_status"
|
||||
@@ -85,7 +84,7 @@
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-[34%]">
|
||||
<div class="w-1/3 hidden lg:block">
|
||||
<span
|
||||
v-dompurify-html="
|
||||
useInstallationName(
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="flex flex-row gap-4 pl-2">
|
||||
<div class="w-[60%]">
|
||||
<div class="flex flex-row gap-4 p-8">
|
||||
<div class="w-full lg:w-3/5">
|
||||
<woot-tabs :index="selectedTabIndex" @change="onClickTabChange">
|
||||
<woot-tabs-item
|
||||
v-for="tab in tabs"
|
||||
@@ -81,7 +81,7 @@
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-[34%]">
|
||||
<div class="hidden lg:block w-1/3">
|
||||
<span v-dompurify-html="$t('ATTRIBUTES_MGMT.SIDEBAR_TXT')" />
|
||||
</div>
|
||||
<woot-modal :show.sync="showEditPopup" :on-close="hideEditPopup">
|
||||
@@ -224,6 +224,7 @@ export default {
|
||||
@apply p-0;
|
||||
}
|
||||
}
|
||||
|
||||
.tabs-title a {
|
||||
font-weight: var(--font-weight-medium);
|
||||
padding-top: 0;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="flex-1 overflow-auto p-4">
|
||||
<div class="flex-1 overflow-auto">
|
||||
<woot-button
|
||||
color-scheme="success"
|
||||
class-names="button--fixed-top"
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
class="woot-table w-full"
|
||||
>
|
||||
<colgroup>
|
||||
<col class="w-[60%]" />
|
||||
<col class="w-3/5" />
|
||||
<col />
|
||||
<col />
|
||||
</colgroup>
|
||||
|
||||
+16
-1
@@ -144,6 +144,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import alertMixin from 'shared/mixins/alertMixin';
|
||||
import automationMethodsMixin from 'dashboard/mixins/automations/methodsMixin';
|
||||
import automationValidationsMixin from 'dashboard/mixins/automations/validationsMixin';
|
||||
@@ -173,7 +174,6 @@ export default {
|
||||
automationTypes: JSON.parse(JSON.stringify(AUTOMATIONS)),
|
||||
automationRuleEvent: AUTOMATION_RULE_EVENTS[0].key,
|
||||
automationRuleEvents: AUTOMATION_RULE_EVENTS,
|
||||
automationActionTypes: AUTOMATION_ACTION_TYPES,
|
||||
automationMutated: false,
|
||||
show: true,
|
||||
automation: {
|
||||
@@ -202,6 +202,10 @@ export default {
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
accountId: 'getCurrentAccountId',
|
||||
isFeatureEnabledonAccount: 'accounts/isFeatureEnabledonAccount',
|
||||
}),
|
||||
hasAutomationMutated() {
|
||||
if (
|
||||
this.automation.conditions[0].values ||
|
||||
@@ -210,6 +214,12 @@ export default {
|
||||
return true;
|
||||
return false;
|
||||
},
|
||||
automationActionTypes() {
|
||||
const isSLAEnabled = this.isFeatureEnabled('sla');
|
||||
return isSLAEnabled
|
||||
? AUTOMATION_ACTION_TYPES
|
||||
: AUTOMATION_ACTION_TYPES.filter(action => action.key !== 'add_sla');
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.$store.dispatch('inboxes/get');
|
||||
@@ -221,6 +231,11 @@ export default {
|
||||
this.allCustomAttributes = this.$store.getters['attributes/getAttributes'];
|
||||
this.manifestCustomAttributes();
|
||||
},
|
||||
methods: {
|
||||
isFeatureEnabled(flag) {
|
||||
return this.isFeatureEnabledonAccount(this.accountId, flag);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
|
||||
+16
-1
@@ -142,6 +142,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import alertMixin from 'shared/mixins/alertMixin';
|
||||
import automationMethodsMixin from 'dashboard/mixins/automations/methodsMixin';
|
||||
import automationValidationsMixin from 'dashboard/mixins/automations/validationsMixin';
|
||||
@@ -175,7 +176,6 @@ export default {
|
||||
automationTypes: JSON.parse(JSON.stringify(AUTOMATIONS)),
|
||||
automationRuleEvent: AUTOMATION_RULE_EVENTS[0].key,
|
||||
automationRuleEvents: AUTOMATION_RULE_EVENTS,
|
||||
automationActionTypes: AUTOMATION_ACTION_TYPES,
|
||||
automationMutated: false,
|
||||
show: true,
|
||||
automation: null,
|
||||
@@ -185,6 +185,10 @@ export default {
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
accountId: 'getCurrentAccountId',
|
||||
isFeatureEnabledonAccount: 'accounts/isFeatureEnabledonAccount',
|
||||
}),
|
||||
hasAutomationMutated() {
|
||||
if (
|
||||
this.automation.conditions[0].values ||
|
||||
@@ -193,12 +197,23 @@ export default {
|
||||
return true;
|
||||
return false;
|
||||
},
|
||||
automationActionTypes() {
|
||||
const isSLAEnabled = this.isFeatureEnabled('sla');
|
||||
return isSLAEnabled
|
||||
? AUTOMATION_ACTION_TYPES
|
||||
: AUTOMATION_ACTION_TYPES.filter(action => action.key !== 'add_sla');
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.manifestCustomAttributes();
|
||||
this.allCustomAttributes = this.$store.getters['attributes/getAttributes'];
|
||||
this.formatAutomation(this.selectedResponse);
|
||||
},
|
||||
methods: {
|
||||
isFeatureEnabled(flag) {
|
||||
return this.isFeatureEnabledonAccount(this.accountId, flag);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
{{ $t('AUTOMATION.HEADER_BTN_TXT') }}
|
||||
</woot-button>
|
||||
<div class="flex flex-row gap-4">
|
||||
<div class="w-[60%]">
|
||||
<div class="w-full lg:w-3/5">
|
||||
<p
|
||||
v-if="!uiFlags.isFetching && !records.length"
|
||||
class="flex h-full items-center flex-col justify-center"
|
||||
@@ -77,7 +77,7 @@
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="w-[34%]">
|
||||
<div class="hidden lg:block w-1/3">
|
||||
<span v-dompurify-html="$t('AUTOMATION.SIDEBAR_TXT')" />
|
||||
</div>
|
||||
</div>
|
||||
@@ -153,6 +153,8 @@ export default {
|
||||
...mapGetters({
|
||||
records: ['automations/getAutomations'],
|
||||
uiFlags: 'automations/getUIFlags',
|
||||
accountId: 'getCurrentAccountId',
|
||||
isFeatureEnabledonAccount: 'accounts/isFeatureEnabledonAccount',
|
||||
}),
|
||||
// Delete Modal
|
||||
deleteConfirmText() {
|
||||
@@ -168,6 +170,9 @@ export default {
|
||||
deleteMessage() {
|
||||
return ` ${this.selectedResponse.name}?`;
|
||||
},
|
||||
isSLAEnabled() {
|
||||
return this.isFeatureEnabledonAccount(this.accountId, 'sla');
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.$store.dispatch('inboxes/get');
|
||||
@@ -177,6 +182,7 @@ export default {
|
||||
this.$store.dispatch('labels/get');
|
||||
this.$store.dispatch('campaigns/get');
|
||||
this.$store.dispatch('automations/get');
|
||||
if (this.isSLAEnabled) this.$store.dispatch('sla/get');
|
||||
},
|
||||
methods: {
|
||||
openAddPopup() {
|
||||
|
||||
@@ -611,4 +611,9 @@ export const AUTOMATION_ACTION_TYPES = [
|
||||
label: 'Change Priority',
|
||||
inputType: 'search_select',
|
||||
},
|
||||
{
|
||||
key: 'add_sla',
|
||||
label: 'Add SLA',
|
||||
inputType: 'search_select',
|
||||
},
|
||||
];
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
</label>
|
||||
|
||||
<label
|
||||
v-if="isOnOffType"
|
||||
v-if="isOneOffType"
|
||||
class="multiselect-wrap--small"
|
||||
:class="{ error: $v.selectedAudience.$error }"
|
||||
>
|
||||
@@ -106,7 +106,7 @@
|
||||
</span>
|
||||
</label>
|
||||
|
||||
<label v-if="isOnOffType">
|
||||
<label v-if="isOneOffType">
|
||||
{{ $t('CAMPAIGN.ADD.FORM.SCHEDULED_AT.LABEL') }}
|
||||
<woot-date-time-picker
|
||||
:value="scheduledAt"
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
<template>
|
||||
<div
|
||||
class="bg-white dark:bg-slate-800 mb-2 border border-slate-50 dark:border-slate-900 rounded-md px-5 py-4"
|
||||
class="px-5 py-4 mb-2 bg-white border rounded-md dark:bg-slate-800 border-slate-50 dark:border-slate-900"
|
||||
>
|
||||
<div class="flex flex-row items-start justify-between">
|
||||
<div class="flex flex-col">
|
||||
<div class="text-base font-medium -mt-1 mb-1">
|
||||
<div
|
||||
class="mb-1 -mt-1 text-base font-medium text-slate-900 dark:text-slate-100"
|
||||
>
|
||||
{{ campaign.title }}
|
||||
</div>
|
||||
<div
|
||||
@@ -35,14 +37,14 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row mt-5 items-center space-x-3">
|
||||
<div class="flex flex-row items-center mt-5 space-x-3">
|
||||
<woot-label
|
||||
small
|
||||
:title="campaignStatus"
|
||||
:color-scheme="colorScheme"
|
||||
class="text-xs mr-3"
|
||||
class="mr-3 text-xs"
|
||||
/>
|
||||
<inbox-name :inbox="campaign.inbox" class="ltr:ml-0 rtl:mr-0 mb-1" />
|
||||
<inbox-name :inbox="campaign.inbox" class="mb-1 ltr:ml-0 rtl:mr-0" />
|
||||
<user-avatar-with-name
|
||||
v-if="campaign.sender"
|
||||
:user="campaign.sender"
|
||||
@@ -50,13 +52,13 @@
|
||||
/>
|
||||
<div
|
||||
v-if="campaign.trigger_rules.url"
|
||||
class="text-xs text-woot-600 mb-1 text-truncate w-1/4"
|
||||
class="w-1/4 mb-1 text-xs text-woot-600 text-truncate"
|
||||
>
|
||||
{{ campaign.trigger_rules.url }}
|
||||
</div>
|
||||
<div
|
||||
v-if="campaign.scheduled_at"
|
||||
class="text-xs text-slate-700 dark:text-slate-500 mb-1"
|
||||
class="mb-1 text-xs text-slate-700 dark:text-slate-500"
|
||||
>
|
||||
{{ messageStamp(new Date(campaign.scheduled_at), 'LLL d, h:mm a') }}
|
||||
</div>
|
||||
|
||||
@@ -18,7 +18,7 @@ export default {
|
||||
},
|
||||
{
|
||||
path: 'ongoing',
|
||||
name: 'settings_account_campaigns',
|
||||
name: 'ongoing_campaigns',
|
||||
roles: ['administrator'],
|
||||
component: Index,
|
||||
},
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
<div class="editor-wrap">
|
||||
<woot-message-editor
|
||||
v-model="content"
|
||||
class="message-editor"
|
||||
class="message-editor [&>div]:px-1"
|
||||
:class="{ editor_warning: $v.content.$error }"
|
||||
:enable-variables="true"
|
||||
:enable-canned-responses="false"
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
<div class="editor-wrap">
|
||||
<woot-message-editor
|
||||
v-model="content"
|
||||
class="message-editor"
|
||||
class="message-editor [&>div]:px-1"
|
||||
:class="{ editor_warning: $v.content.$error }"
|
||||
:enable-variables="true"
|
||||
:enable-canned-responses="false"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="flex-1 overflow-auto p-4">
|
||||
<div class="flex-1 overflow-auto">
|
||||
<woot-button
|
||||
color-scheme="success"
|
||||
class-names="button--fixed-top"
|
||||
@@ -10,11 +10,11 @@
|
||||
</woot-button>
|
||||
|
||||
<!-- List Canned Response -->
|
||||
<div class="flex flex-row gap-4">
|
||||
<div class="w-[60%]">
|
||||
<div class="flex flex-row gap-4 p-8">
|
||||
<div class="w-full xl:w-3/5">
|
||||
<p
|
||||
v-if="!uiFlags.fetchingList && !records.length"
|
||||
class="flex h-full items-center flex-col justify-center"
|
||||
class="flex flex-col items-center justify-center h-full"
|
||||
>
|
||||
{{ $t('CANNED_MGMT.LIST.404') }}
|
||||
</p>
|
||||
@@ -32,6 +32,7 @@
|
||||
<th
|
||||
v-for="thHeader in $t('CANNED_MGMT.LIST.TABLE_HEADER')"
|
||||
:key="thHeader"
|
||||
class="last:text-right"
|
||||
>
|
||||
{{ thHeader }}
|
||||
</th>
|
||||
@@ -42,7 +43,10 @@
|
||||
:key="cannedItem.short_code"
|
||||
>
|
||||
<!-- Short Code -->
|
||||
<td class="w-[8.75rem]">
|
||||
<td
|
||||
class="w-[8.75rem] truncate max-w-[8.75rem]"
|
||||
:title="cannedItem.short_code"
|
||||
>
|
||||
{{ cannedItem.short_code }}
|
||||
</td>
|
||||
<!-- Content -->
|
||||
@@ -50,7 +54,7 @@
|
||||
{{ cannedItem.content }}
|
||||
</td>
|
||||
<!-- Action Buttons -->
|
||||
<td class="button-wrapper">
|
||||
<td class="flex justify-end gap-1 min-w-[12.5rem]">
|
||||
<woot-button
|
||||
v-tooltip.top="$t('CANNED_MGMT.EDIT.BUTTON_TEXT')"
|
||||
variant="smooth"
|
||||
@@ -75,7 +79,7 @@
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="w-[34%]">
|
||||
<div class="hidden w-1/3 xl:block">
|
||||
<span v-dompurify-html="$t('CANNED_MGMT.SIDEBAR_TXT')" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
<script setup>
|
||||
defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
description: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
iconName: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
href: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
linkText: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
});
|
||||
|
||||
const openInNewTab = url => {
|
||||
if (!url) return;
|
||||
window.open(url, '_blank', 'noopener noreferrer');
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex flex-col items-start w-full gap-4">
|
||||
<!-- Header section with icon, title and action button -->
|
||||
<div class="flex items-center justify-between w-full gap-4">
|
||||
<!-- Icon and title container -->
|
||||
<div class="flex items-center gap-3">
|
||||
<div
|
||||
class="flex items-center w-10 h-10 p-1 rounded-full bg-woot-25/60 dark:bg-woot-900/60"
|
||||
>
|
||||
<div
|
||||
class="flex items-center justify-center w-full h-full rounded-full bg-woot-75/70 dark:bg-woot-800/40"
|
||||
>
|
||||
<fluent-icon
|
||||
size="14"
|
||||
:icon="iconName"
|
||||
type="outline"
|
||||
class="flex-shrink-0 text-woot-500 dark:text-woot-500"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<h1
|
||||
class="text-2xl font-medium tracking-[-1.5%] text-slate-900 dark:text-slate-25"
|
||||
>
|
||||
{{ title }}
|
||||
</h1>
|
||||
</div>
|
||||
<!-- Slot for additional actions on larger screens -->
|
||||
<div class="hidden gap-2 sm:flex">
|
||||
<slot name="actions" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- Description and optional link -->
|
||||
<div
|
||||
class="flex flex-col gap-2 text-slate-600 dark:text-slate-300 max-w-[721px] w-full"
|
||||
>
|
||||
<p
|
||||
class="mb-0 text-sm font-normal tracking-[0.5%] line-clamp-5 sm:line-clamp-none"
|
||||
>
|
||||
<slot name="description">{{ description }}</slot>
|
||||
</p>
|
||||
<!-- Conditional link -->
|
||||
<a
|
||||
v-if="href && linkText"
|
||||
:href="href"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="sm:inline-flex hidden tracking-[-0.6%] gap-1 w-fit items-center text-woot-500 dark:text-woot-500 text-sm font-medium tracking=[-0.6%] hover:underline"
|
||||
>
|
||||
{{ linkText }}
|
||||
<fluent-icon
|
||||
size="16"
|
||||
icon="chevron-right"
|
||||
type="outline"
|
||||
class="flex-shrink-0 text-woot-500 dark:text-woot-500"
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
<!-- Mobile view for actions and link -->
|
||||
<div class="flex items-start justify-start w-full gap-3 sm:hidden">
|
||||
<slot name="actions" />
|
||||
<woot-button
|
||||
v-if="href && linkText"
|
||||
color-scheme="secondary"
|
||||
icon="arrow-outwards"
|
||||
class="flex-row-reverse rounded-xl min-w-0 !bg-slate-50 !text-slate-900 dark:!text-white dark:!bg-slate-800"
|
||||
@click="openInNewTab(href)"
|
||||
>
|
||||
{{ linkText }}
|
||||
</woot-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
<script setup>
|
||||
defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
description: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<div
|
||||
class="flex relative flex-col sm:flex-row p-4 gap-4 sm:p-6 justify-between shadow-sm group bg-white border border-solid rounded-xl dark:bg-slate-800 border-slate-75 dark:border-slate-700/50 max-w-[900px] w-full"
|
||||
>
|
||||
<!-- left side section -->
|
||||
<slot name="leftSection">
|
||||
<div class="flex flex-col min-w-0 items-start gap-3 max-w-[480px] w-full">
|
||||
<div
|
||||
class="flex items-center justify-between w-full gap-3 sm:justify-normal whitespace-nowrap"
|
||||
>
|
||||
<h3
|
||||
class="justify-between text-sm tracking-[-0.6%] font-medium truncate w-fit sm:justify-normal text-slate-900 dark:text-slate-25"
|
||||
>
|
||||
<slot name="title">
|
||||
{{ title }}
|
||||
</slot>
|
||||
</h3>
|
||||
<slot name="label" />
|
||||
</div>
|
||||
<p
|
||||
class="text-sm text-slate-600 tracking-[0.5%] dark:text-slate-300 max-w-[400px] w-full line-clamp-2"
|
||||
>
|
||||
<slot name="description">
|
||||
{{ description }}
|
||||
</slot>
|
||||
</p>
|
||||
</div>
|
||||
</slot>
|
||||
|
||||
<!-- right side section -->
|
||||
<slot name="rightSection" />
|
||||
|
||||
<!-- actions section -->
|
||||
<div
|
||||
v-if="$slots.actions"
|
||||
class="absolute flex-col items-center hidden gap-1 border-none ltr:-right-3 rtl:-left-3 top-3 group-hover:flex"
|
||||
>
|
||||
<slot name="actions" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,5 +1,7 @@
|
||||
<template>
|
||||
<div class="wizard-body w-[75%] flex-shrink-0 flex-grow-0 max-w-[75%]">
|
||||
<div
|
||||
class="border border-slate-25 dark:border-slate-800/60 bg-white dark:bg-slate-900 h-full p-6 w-full max-w-full md:w-3/4 md:max-w-[75%] flex-shrink-0 flex-grow-0"
|
||||
>
|
||||
<form class="mx-0 flex flex-wrap" @submit.prevent="addAgents()">
|
||||
<div class="w-full">
|
||||
<page-header
|
||||
@@ -7,7 +9,7 @@
|
||||
:header-content="$t('INBOX_MGMT.ADD.AGENTS.DESC')"
|
||||
/>
|
||||
</div>
|
||||
<div class="w-[60%]">
|
||||
<div class="w-3/5">
|
||||
<div class="w-full">
|
||||
<label :class="{ error: $v.selectedAgents.$error }">
|
||||
{{ $t('INBOX_MGMT.ADD.AGENTS.TITLE') }}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<template>
|
||||
<div class="wizard-body w-[75%] flex-shrink-0 flex-grow-0 max-w-[75%] h-auto">
|
||||
<div
|
||||
class="border border-slate-25 dark:border-slate-800/60 bg-white dark:bg-slate-900 h-full p-6 w-full max-w-full md:w-3/4 md:max-w-[75%] flex-shrink-0 flex-grow-0"
|
||||
>
|
||||
<page-header
|
||||
:header-title="$t('INBOX_MGMT.ADD.AUTH.TITLE')"
|
||||
:header-content="
|
||||
@@ -82,12 +84,3 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.height-auto {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.channel-list {
|
||||
margin-top: var(--space-medium);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<template>
|
||||
<div class="wizard-body w-[75%] flex-shrink-0 flex-grow-0 max-w-[75%]">
|
||||
<div
|
||||
class="border border-slate-25 dark:border-slate-800/60 bg-white dark:bg-slate-900 h-full p-6 w-full max-w-full md:w-3/4 md:max-w-[75%] flex-shrink-0 flex-grow-0"
|
||||
>
|
||||
<empty-state
|
||||
:title="$t('INBOX_MGMT.FINISH.TITLE')"
|
||||
:message="message"
|
||||
@@ -58,7 +60,7 @@
|
||||
</div>
|
||||
<div class="flex justify-center gap-2 mt-4">
|
||||
<router-link
|
||||
class="button hollow primary"
|
||||
class="button hollow primary rounded"
|
||||
:to="{
|
||||
name: 'settings_inbox_show',
|
||||
params: { inboxId: $route.params.inbox_id },
|
||||
@@ -67,7 +69,7 @@
|
||||
{{ $t('INBOX_MGMT.FINISH.MORE_SETTINGS') }}
|
||||
</router-link>
|
||||
<router-link
|
||||
class="button success"
|
||||
class="button success rounded"
|
||||
:to="{
|
||||
name: 'inbox_dashboard',
|
||||
params: { inboxId: $route.params.inbox_id },
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="settings--content">
|
||||
<div class="mx-8">
|
||||
<settings-section
|
||||
:title="$t('INBOX_MGMT.IMAP.TITLE')"
|
||||
:sub-title="$t('INBOX_MGMT.IMAP.SUBTITLE')"
|
||||
@@ -10,16 +10,17 @@
|
||||
<input
|
||||
v-model="isIMAPEnabled"
|
||||
type="checkbox"
|
||||
class="ltr:mr-2 rtl:ml-2"
|
||||
name="toggle-imap-enable"
|
||||
/>
|
||||
{{ $t('INBOX_MGMT.IMAP.TOGGLE_AVAILABILITY') }}
|
||||
</label>
|
||||
<p>{{ $t('INBOX_MGMT.IMAP.TOGGLE_HELP') }}</p>
|
||||
<div v-if="isIMAPEnabled" class="imap-details-wrap">
|
||||
<div v-if="isIMAPEnabled" class="mb-6">
|
||||
<woot-input
|
||||
v-model.trim="address"
|
||||
:class="{ error: $v.address.$error }"
|
||||
class="medium-9 columns"
|
||||
class="max-w-[75%] w-full"
|
||||
:label="$t('INBOX_MGMT.IMAP.ADDRESS.LABEL')"
|
||||
:placeholder="$t('INBOX_MGMT.IMAP.ADDRESS.PLACE_HOLDER')"
|
||||
@blur="$v.address.$touch"
|
||||
@@ -28,7 +29,7 @@
|
||||
v-model="port"
|
||||
type="number"
|
||||
:class="{ error: $v.port.$error }"
|
||||
class="medium-9 columns"
|
||||
class="max-w-[75%] w-full"
|
||||
:label="$t('INBOX_MGMT.IMAP.PORT.LABEL')"
|
||||
:placeholder="$t('INBOX_MGMT.IMAP.PORT.PLACE_HOLDER')"
|
||||
@blur="$v.port.$touch"
|
||||
@@ -36,7 +37,7 @@
|
||||
<woot-input
|
||||
v-model="login"
|
||||
:class="{ error: $v.login.$error }"
|
||||
class="medium-9 columns"
|
||||
class="max-w-[75%] w-full"
|
||||
:label="$t('INBOX_MGMT.IMAP.LOGIN.LABEL')"
|
||||
:placeholder="$t('INBOX_MGMT.IMAP.LOGIN.PLACE_HOLDER')"
|
||||
@blur="$v.login.$touch"
|
||||
@@ -44,7 +45,7 @@
|
||||
<woot-input
|
||||
v-model="password"
|
||||
:class="{ error: $v.password.$error }"
|
||||
class="medium-9 columns"
|
||||
class="max-w-[75%] w-full"
|
||||
:label="$t('INBOX_MGMT.IMAP.PASSWORD.LABEL')"
|
||||
:placeholder="$t('INBOX_MGMT.IMAP.PASSWORD.PLACE_HOLDER')"
|
||||
type="password"
|
||||
@@ -54,6 +55,7 @@
|
||||
<input
|
||||
v-model="isSSLEnabled"
|
||||
type="checkbox"
|
||||
class="ltr:mr-2 rtl:ml-2"
|
||||
name="toggle-enable-ssl"
|
||||
/>
|
||||
{{ $t('INBOX_MGMT.IMAP.ENABLE_SSL') }}
|
||||
@@ -159,8 +161,3 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.imap-details-wrap {
|
||||
margin-bottom: var(--space-medium);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
class="flex flex-row overflow-auto p-4 h-full bg-slate-25 dark:bg-slate-800"
|
||||
>
|
||||
<woot-wizard
|
||||
class="hide-for-small-only w-[25%]"
|
||||
class="hidden md:block w-1/4"
|
||||
:global-config="globalConfig"
|
||||
:items="items"
|
||||
/>
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
<template>
|
||||
<div class="flex-1 overflow-auto p-4">
|
||||
<!-- List Canned Response -->
|
||||
<div class="flex flex-row gap-4">
|
||||
<div class="w-[60%]">
|
||||
<div class="flex-1 overflow-auto">
|
||||
<div class="flex flex-row gap-4 p-8">
|
||||
<div class="w-full lg:w-3/5">
|
||||
<p
|
||||
v-if="!inboxesList.length"
|
||||
class="flex h-full items-center flex-col justify-center"
|
||||
@@ -99,7 +98,7 @@
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="w-[34%]">
|
||||
<div class="w-1/3 hidden lg:block">
|
||||
<span
|
||||
v-dompurify-html="
|
||||
useInstallationName(
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
{{ $t('INBOX_MGMT.PRE_CHAT_FORM.DESCRIPTION') }}
|
||||
</div>
|
||||
<form class="flex flex-col" @submit.prevent="updateInbox">
|
||||
<label class="w-[25%]">
|
||||
<label class="w-1/4">
|
||||
{{ $t('INBOX_MGMT.PRE_CHAT_FORM.ENABLE.LABEL') }}
|
||||
<select v-model="preChatFormEnabled">
|
||||
<option :value="true">
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
</woot-tabs>
|
||||
</setting-intro-banner>
|
||||
|
||||
<div v-if="selectedTabKey === 'inbox_settings'" class="settings--content">
|
||||
<div v-if="selectedTabKey === 'inbox_settings'" class="mx-8">
|
||||
<settings-section
|
||||
:title="$t('INBOX_MGMT.SETTINGS_POPUP.INBOX_UPDATE_TITLE')"
|
||||
:sub-title="$t('INBOX_MGMT.SETTINGS_POPUP.INBOX_UPDATE_SUB_TEXT')"
|
||||
@@ -37,7 +37,7 @@
|
||||
/>
|
||||
<woot-input
|
||||
v-model.trim="selectedInboxName"
|
||||
class="w-[75%] pb-4"
|
||||
class="w-3/4 pb-4"
|
||||
:class="{ error: $v.selectedInboxName.$error }"
|
||||
:label="inboxNameLabel"
|
||||
:placeholder="inboxNamePlaceHolder"
|
||||
@@ -51,7 +51,7 @@
|
||||
<woot-input
|
||||
v-if="isAPIInbox"
|
||||
v-model.trim="webhookUrl"
|
||||
class="w-[75%] pb-4"
|
||||
class="w-3/4 pb-4"
|
||||
:class="{ error: $v.webhookUrl.$error }"
|
||||
:label="
|
||||
$t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_WEBHOOK_URL.LABEL')
|
||||
@@ -69,7 +69,7 @@
|
||||
<woot-input
|
||||
v-if="isAWebWidgetInbox"
|
||||
v-model.trim="channelWebsiteUrl"
|
||||
class="w-[75%] pb-4"
|
||||
class="w-3/4 pb-4"
|
||||
:label="$t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_DOMAIN.LABEL')"
|
||||
:placeholder="
|
||||
$t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_DOMAIN.PLACEHOLDER')
|
||||
@@ -78,7 +78,7 @@
|
||||
<woot-input
|
||||
v-if="isAWebWidgetInbox"
|
||||
v-model.trim="channelWelcomeTitle"
|
||||
class="w-[75%] pb-4"
|
||||
class="w-3/4 pb-4"
|
||||
:label="
|
||||
$t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_WELCOME_TITLE.LABEL')
|
||||
"
|
||||
@@ -92,7 +92,7 @@
|
||||
<woot-input
|
||||
v-if="isAWebWidgetInbox"
|
||||
v-model.trim="channelWelcomeTagline"
|
||||
class="w-[75%] pb-4"
|
||||
class="w-3/4 pb-4"
|
||||
:label="
|
||||
$t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_WELCOME_TAGLINE.LABEL')
|
||||
"
|
||||
@@ -103,17 +103,17 @@
|
||||
"
|
||||
/>
|
||||
|
||||
<label v-if="isAWebWidgetInbox" class="w-[75%] pb-4">
|
||||
<label v-if="isAWebWidgetInbox" class="w-3/4 pb-4">
|
||||
{{ $t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.WIDGET_COLOR.LABEL') }}
|
||||
<woot-color-picker v-model="inbox.widget_color" />
|
||||
</label>
|
||||
|
||||
<label v-if="isAWhatsAppChannel" class="w-[75%] pb-4">
|
||||
<label v-if="isAWhatsAppChannel" class="w-3/4 pb-4">
|
||||
{{ $t('INBOX_MGMT.ADD.WHATSAPP.PROVIDERS.LABEL') }}
|
||||
<input v-model="whatsAppAPIProviderName" type="text" disabled />
|
||||
</label>
|
||||
|
||||
<label class="w-[75%] pb-4">
|
||||
<label class="w-3/4 pb-4">
|
||||
{{
|
||||
$t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_GREETING_TOGGLE.LABEL')
|
||||
}}
|
||||
@@ -157,7 +157,7 @@
|
||||
:richtext="!textAreaChannels"
|
||||
/>
|
||||
</div>
|
||||
<label v-if="isAWebWidgetInbox" class="w-[75%] pb-4">
|
||||
<label v-if="isAWebWidgetInbox" class="w-3/4 pb-4">
|
||||
{{ $t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.REPLY_TIME.TITLE') }}
|
||||
<select v-model="replyTime">
|
||||
<option key="in_a_few_minutes" value="in_a_few_minutes">
|
||||
@@ -180,7 +180,7 @@
|
||||
</p>
|
||||
</label>
|
||||
|
||||
<label v-if="isAWebWidgetInbox" class="w-[75%] pb-4">
|
||||
<label v-if="isAWebWidgetInbox" class="w-3/4 pb-4">
|
||||
{{ $t('INBOX_MGMT.SETTINGS_POPUP.ENABLE_EMAIL_COLLECT_BOX') }}
|
||||
<select v-model="emailCollectEnabled">
|
||||
<option :value="true">
|
||||
@@ -197,7 +197,7 @@
|
||||
</p>
|
||||
</label>
|
||||
|
||||
<label class="w-[75%] pb-4">
|
||||
<label class="w-3/4 pb-4">
|
||||
{{ $t('INBOX_MGMT.SETTINGS_POPUP.ENABLE_CSAT') }}
|
||||
<select v-model="csatSurveyEnabled">
|
||||
<option :value="true">
|
||||
@@ -212,7 +212,7 @@
|
||||
</p>
|
||||
</label>
|
||||
|
||||
<label v-if="isAWebWidgetInbox" class="w-[75%] pb-4">
|
||||
<label v-if="isAWebWidgetInbox" class="w-3/4 pb-4">
|
||||
{{ $t('INBOX_MGMT.SETTINGS_POPUP.ALLOW_MESSAGES_AFTER_RESOLVED') }}
|
||||
<select v-model="allowMessagesAfterResolved">
|
||||
<option :value="true">
|
||||
@@ -231,7 +231,7 @@
|
||||
</p>
|
||||
</label>
|
||||
|
||||
<label v-if="isAWebWidgetInbox" class="w-[75%] pb-4">
|
||||
<label v-if="isAWebWidgetInbox" class="w-3/4 pb-4">
|
||||
{{ $t('INBOX_MGMT.SETTINGS_POPUP.ENABLE_CONTINUITY_VIA_EMAIL') }}
|
||||
<select v-model="continuityViaEmail">
|
||||
<option :value="true">
|
||||
@@ -249,7 +249,7 @@
|
||||
}}
|
||||
</p>
|
||||
</label>
|
||||
<div class="w-[75%] pb-4">
|
||||
<div class="w-3/4 pb-4">
|
||||
<label>
|
||||
{{ $t('INBOX_MGMT.HELP_CENTER.LABEL') }}
|
||||
</label>
|
||||
@@ -265,7 +265,7 @@
|
||||
{{ $t('INBOX_MGMT.HELP_CENTER.SUB_TEXT') }}
|
||||
</p>
|
||||
</div>
|
||||
<label v-if="canLocktoSingleConversation" class="w-[75%] pb-4">
|
||||
<label v-if="canLocktoSingleConversation" class="w-3/4 pb-4">
|
||||
{{ $t('INBOX_MGMT.SETTINGS_POPUP.LOCK_TO_SINGLE_CONVERSATION') }}
|
||||
<select v-model="locktoSingleConversation">
|
||||
<option :value="true">
|
||||
@@ -287,7 +287,7 @@
|
||||
<label v-if="isAWebWidgetInbox">
|
||||
{{ $t('INBOX_MGMT.FEATURES.LABEL') }}
|
||||
</label>
|
||||
<div v-if="isAWebWidgetInbox" class="pt-2 pb-4">
|
||||
<div v-if="isAWebWidgetInbox" class="pt-2 pb-4 flex gap-2">
|
||||
<input
|
||||
v-model="selectedFeatureFlags"
|
||||
type="checkbox"
|
||||
@@ -298,7 +298,7 @@
|
||||
{{ $t('INBOX_MGMT.FEATURES.DISPLAY_FILE_PICKER') }}
|
||||
</label>
|
||||
</div>
|
||||
<div v-if="isAWebWidgetInbox" class="pb-4">
|
||||
<div v-if="isAWebWidgetInbox" class="pb-4 flex gap-2">
|
||||
<input
|
||||
v-model="selectedFeatureFlags"
|
||||
type="checkbox"
|
||||
@@ -309,7 +309,7 @@
|
||||
{{ $t('INBOX_MGMT.FEATURES.DISPLAY_EMOJI_PICKER') }}
|
||||
</label>
|
||||
</div>
|
||||
<div v-if="isAWebWidgetInbox" class="pb-4">
|
||||
<div v-if="isAWebWidgetInbox" class="pb-4 flex gap-2">
|
||||
<input
|
||||
v-model="selectedFeatureFlags"
|
||||
type="checkbox"
|
||||
@@ -320,7 +320,7 @@
|
||||
{{ $t('INBOX_MGMT.FEATURES.ALLOW_END_CONVERSATION') }}
|
||||
</label>
|
||||
</div>
|
||||
<div v-if="isAWebWidgetInbox" class="pb-4">
|
||||
<div v-if="isAWebWidgetInbox" class="pb-4 flex gap-2">
|
||||
<input
|
||||
v-model="selectedFeatureFlags"
|
||||
type="checkbox"
|
||||
@@ -338,7 +338,7 @@
|
||||
:sub-title="$t('INBOX_MGMT.EDIT.SENDER_NAME_SECTION.SUB_TEXT')"
|
||||
:show-border="false"
|
||||
>
|
||||
<div class="w-[75%] pb-4">
|
||||
<div class="w-3/4 pb-4">
|
||||
<sender-name-example-preview
|
||||
:sender-name-type="senderNameType"
|
||||
:business-name="businessName"
|
||||
@@ -400,7 +400,7 @@
|
||||
<facebook-reauthorize v-if="isAFacebookInbox" :inbox-id="inbox.id" />
|
||||
</div>
|
||||
|
||||
<div v-if="selectedTabKey === 'collaborators'" class="settings--content">
|
||||
<div v-if="selectedTabKey === 'collaborators'" class="mx-8">
|
||||
<collaborators-page :inbox="inbox" />
|
||||
</div>
|
||||
<div v-if="selectedTabKey === 'configuration'">
|
||||
@@ -757,11 +757,9 @@ export default {
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.settings {
|
||||
.settings--tabs {
|
||||
::v-deep .tabs {
|
||||
@apply p-0;
|
||||
}
|
||||
.settings--tabs {
|
||||
::v-deep .tabs {
|
||||
@apply p-0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="settings--content">
|
||||
<div class="mx-8">
|
||||
<settings-section
|
||||
:title="$t('INBOX_MGMT.SMTP.TITLE')"
|
||||
:sub-title="$t('INBOX_MGMT.SMTP.SUBTITLE')"
|
||||
@@ -14,11 +14,11 @@
|
||||
{{ $t('INBOX_MGMT.SMTP.TOGGLE_AVAILABILITY') }}
|
||||
</label>
|
||||
<p>{{ $t('INBOX_MGMT.SMTP.TOGGLE_HELP') }}</p>
|
||||
<div v-if="isSMTPEnabled" class="smtp-details-wrap">
|
||||
<div v-if="isSMTPEnabled" class="mb-6">
|
||||
<woot-input
|
||||
v-model.trim="address"
|
||||
:class="{ error: $v.address.$error }"
|
||||
class="medium-9 columns"
|
||||
class="max-w-[75%] w-full"
|
||||
:label="$t('INBOX_MGMT.SMTP.ADDRESS.LABEL')"
|
||||
:placeholder="$t('INBOX_MGMT.SMTP.ADDRESS.PLACE_HOLDER')"
|
||||
@blur="$v.address.$touch"
|
||||
@@ -27,7 +27,7 @@
|
||||
v-model="port"
|
||||
type="number"
|
||||
:class="{ error: $v.port.$error }"
|
||||
class="medium-9 columns"
|
||||
class="max-w-[75%] w-full"
|
||||
:label="$t('INBOX_MGMT.SMTP.PORT.LABEL')"
|
||||
:placeholder="$t('INBOX_MGMT.SMTP.PORT.PLACE_HOLDER')"
|
||||
@blur="$v.port.$touch"
|
||||
@@ -35,7 +35,7 @@
|
||||
<woot-input
|
||||
v-model="login"
|
||||
:class="{ error: $v.login.$error }"
|
||||
class="medium-9 columns"
|
||||
class="max-w-[75%] w-full"
|
||||
:label="$t('INBOX_MGMT.SMTP.LOGIN.LABEL')"
|
||||
:placeholder="$t('INBOX_MGMT.SMTP.LOGIN.PLACE_HOLDER')"
|
||||
@blur="$v.login.$touch"
|
||||
@@ -43,7 +43,7 @@
|
||||
<woot-input
|
||||
v-model="password"
|
||||
:class="{ error: $v.password.$error }"
|
||||
class="medium-9 columns"
|
||||
class="max-w-[75%] w-full"
|
||||
:label="$t('INBOX_MGMT.SMTP.PASSWORD.LABEL')"
|
||||
:placeholder="$t('INBOX_MGMT.SMTP.PASSWORD.PLACE_HOLDER')"
|
||||
type="password"
|
||||
@@ -52,7 +52,7 @@
|
||||
<woot-input
|
||||
v-model.trim="domain"
|
||||
:class="{ error: $v.domain.$error }"
|
||||
class="medium-9 columns"
|
||||
class="max-w-[75%] w-full"
|
||||
:label="$t('INBOX_MGMT.SMTP.DOMAIN.LABEL')"
|
||||
:placeholder="$t('INBOX_MGMT.SMTP.DOMAIN.PLACE_HOLDER')"
|
||||
@blur="$v.domain.$touch"
|
||||
@@ -63,14 +63,14 @@
|
||||
:action="handleEncryptionChange"
|
||||
/>
|
||||
<single-select-dropdown
|
||||
class="medium-9 columns"
|
||||
class="max-w-[75%] w-full"
|
||||
:label="$t('INBOX_MGMT.SMTP.OPEN_SSL_VERIFY_MODE')"
|
||||
:selected="openSSLVerifyMode"
|
||||
:options="openSSLVerifyModes"
|
||||
:action="handleSSLModeChange"
|
||||
/>
|
||||
<single-select-dropdown
|
||||
class="medium-9 columns"
|
||||
class="max-w-[75%] w-full"
|
||||
:label="$t('INBOX_MGMT.SMTP.AUTH_MECHANISM')"
|
||||
:selected="authMechanism"
|
||||
:options="authMechanisms"
|
||||
@@ -237,8 +237,3 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.smtp-details-wrap {
|
||||
margin-bottom: var(--space-medium);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="settings--content">
|
||||
<div class="mx-8">
|
||||
<div class="widget-builder-container">
|
||||
<div class="settings-container w-100 lg:w-[40%]">
|
||||
<div class="settings-content">
|
||||
@@ -123,7 +123,7 @@
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="widget-container w-100 lg:w-[60%]">
|
||||
<div class="widget-container w-100 lg:w-3/5">
|
||||
<input-radio-group
|
||||
name="widget-view-options"
|
||||
:items="getWidgetViewOptions"
|
||||
@@ -422,9 +422,9 @@ export default {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
padding: var(--space-one);
|
||||
@include breakpoint(900px down) {
|
||||
flex-direction: column;
|
||||
}
|
||||
// @include breakpoint(900px down) {
|
||||
// flex-direction: column;
|
||||
// }
|
||||
}
|
||||
|
||||
.settings-container {
|
||||
@@ -450,10 +450,11 @@ export default {
|
||||
padding: var(--space-one) var(--space-one) var(--space-one) var(--space-one);
|
||||
@apply bg-slate-50 dark:bg-slate-700;
|
||||
|
||||
@include breakpoint(500px down) {
|
||||
background: none;
|
||||
}
|
||||
// @include breakpoint(500px down) {
|
||||
// background: none;
|
||||
// }
|
||||
}
|
||||
|
||||
.widget-script {
|
||||
@apply mx-5 p-2.5 bg-slate-50 dark:bg-slate-700;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<template>
|
||||
<div class="wizard-body w-[75%] flex-shrink-0 flex-grow-0 max-w-[75%]">
|
||||
<div
|
||||
class="border border-slate-25 dark:border-slate-800/60 bg-white dark:bg-slate-900 h-full p-6 w-full max-w-full md:w-3/4 md:max-w-[75%] flex-shrink-0 flex-grow-0"
|
||||
>
|
||||
<page-header
|
||||
:header-title="$t('INBOX_MGMT.ADD.API_CHANNEL.TITLE')"
|
||||
:header-content="$t('INBOX_MGMT.ADD.API_CHANNEL.DESC')"
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<template>
|
||||
<div
|
||||
v-if="!provider"
|
||||
class="wizard-body small-12 medium-9 columns height-auto"
|
||||
class="border border-slate-25 dark:border-slate-800/60 bg-white dark:bg-slate-900 h-full p-6 w-full md:w-full max-w-full md:max-w-[75%] flex-shrink-0 flex-grow-0"
|
||||
>
|
||||
<page-header
|
||||
:header-title="$t('INBOX_MGMT.ADD.EMAIL_PROVIDER.TITLE')"
|
||||
:header-content="$t('INBOX_MGMT.ADD.EMAIL_PROVIDER.DESCRIPTION')"
|
||||
/>
|
||||
<div class="row channel-list">
|
||||
<div class="flex flex-row flex-wrap mx-0 mt-6">
|
||||
<channel-selector
|
||||
v-for="emailProvider in emailProviderList"
|
||||
:key="emailProvider.key"
|
||||
@@ -63,9 +63,3 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.channel-list {
|
||||
margin-top: var(--space-medium);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<template>
|
||||
<div class="wizard-body w-[75%] flex-shrink-0 flex-grow-0 max-w-[75%]">
|
||||
<div
|
||||
class="border border-slate-25 dark:border-slate-800/60 bg-white dark:bg-slate-900 h-full p-6 w-full max-w-full md:w-3/4 md:max-w-[75%] flex-shrink-0 flex-grow-0"
|
||||
>
|
||||
<div v-if="!hasLoginStarted" class="login-init h-full">
|
||||
<a href="#" @click="startLogin()">
|
||||
<img
|
||||
@@ -41,7 +43,7 @@
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
<div class="w-[60%]">
|
||||
<div class="w-3/5">
|
||||
<div class="w-full">
|
||||
<div class="input-wrap" :class="{ error: $v.selectedPage.$error }">
|
||||
{{ $t('INBOX_MGMT.ADD.FB.CHOOSE_PAGE') }}
|
||||
@@ -283,3 +285,16 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.login-init {
|
||||
@apply pt-[30%] text-center;
|
||||
|
||||
p {
|
||||
@apply p-6;
|
||||
}
|
||||
|
||||
> a > img {
|
||||
@apply w-60;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<template>
|
||||
<div class="wizard-body w-[75%] flex-shrink-0 flex-grow-0 max-w-[75%]">
|
||||
<div
|
||||
class="border border-slate-25 dark:border-slate-800/60 bg-white dark:bg-slate-900 h-full p-6 w-full max-w-full md:w-3/4 md:max-w-[75%] flex-shrink-0 flex-grow-0"
|
||||
>
|
||||
<page-header
|
||||
:header-title="$t('INBOX_MGMT.ADD.LINE_CHANNEL.TITLE')"
|
||||
:header-content="$t('INBOX_MGMT.ADD.LINE_CHANNEL.DESC')"
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<template>
|
||||
<div class="wizard-body w-[75%] flex-shrink-0 flex-grow-0 max-w-[75%]">
|
||||
<div
|
||||
class="border border-slate-25 dark:border-slate-800/60 bg-white dark:bg-slate-900 h-full p-6 w-full max-w-full md:w-3/4 md:max-w-[75%] flex-shrink-0 flex-grow-0"
|
||||
>
|
||||
<page-header
|
||||
:header-title="$t('INBOX_MGMT.ADD.SMS.TITLE')"
|
||||
:header-content="$t('INBOX_MGMT.ADD.SMS.DESC')"
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<template>
|
||||
<div class="wizard-body w-[75%] flex-shrink-0 flex-grow-0 max-w-[75%]">
|
||||
<div
|
||||
class="border border-slate-25 dark:border-slate-800/60 bg-white dark:bg-slate-900 h-full p-6 w-full max-w-full md:w-3/4 md:max-w-[75%] flex-shrink-0 flex-grow-0"
|
||||
>
|
||||
<page-header
|
||||
:header-title="$t('INBOX_MGMT.ADD.TELEGRAM_CHANNEL.TITLE')"
|
||||
:header-content="$t('INBOX_MGMT.ADD.TELEGRAM_CHANNEL.DESC')"
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="medium-8 columns messagingServiceHelptext">
|
||||
<div class="max-w-[65%] w-full messagingServiceHelptext">
|
||||
<label for="useMessagingService">
|
||||
<input
|
||||
id="useMessagingService"
|
||||
@@ -84,7 +84,7 @@
|
||||
}}</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="medium-8 columns messagingServiceHelptext">
|
||||
<div class="max-w-[65%] w-full messagingServiceHelptext">
|
||||
<label for="useAPIKey">
|
||||
<input
|
||||
id="useAPIKey"
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<template>
|
||||
<div class="wizard-body w-[75%] flex-shrink-0 flex-grow-0 max-w-[75%]">
|
||||
<div
|
||||
class="border border-slate-25 dark:border-slate-800/60 bg-white dark:bg-slate-900 h-full p-6 w-full max-w-full md:w-3/4 md:max-w-[75%] flex-shrink-0 flex-grow-0"
|
||||
>
|
||||
<div class="login-init h-full text-center">
|
||||
<form @submit.prevent="requestAuthorization">
|
||||
<woot-submit-button
|
||||
@@ -40,3 +42,14 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.login-init {
|
||||
@apply pt-[30%] text-center;
|
||||
p {
|
||||
@apply p-6;
|
||||
}
|
||||
> a > img {
|
||||
@apply w-60;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<template>
|
||||
<div class="wizard-body w-[75%] flex-shrink-0 flex-grow-0 max-w-[75%] h-auto">
|
||||
<div
|
||||
class="border border-slate-25 dark:border-slate-800/60 bg-white dark:bg-slate-900 h-full p-6 w-full max-w-full md:w-3/4 md:max-w-[75%] flex-shrink-0 flex-grow-0"
|
||||
>
|
||||
<page-header
|
||||
:header-title="$t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.TITLE')"
|
||||
:header-content="$t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.DESC')"
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<template>
|
||||
<div class="wizard-body w-[75%] flex-shrink-0 flex-grow-0 max-w-[75%]">
|
||||
<div
|
||||
class="border border-slate-25 dark:border-slate-800/60 bg-white dark:bg-slate-900 h-full p-6 w-full max-w-full md:w-3/4 md:max-w-[75%] flex-shrink-0 flex-grow-0"
|
||||
>
|
||||
<page-header
|
||||
:header-title="$t('INBOX_MGMT.ADD.WHATSAPP.TITLE')"
|
||||
:header-content="$t('INBOX_MGMT.ADD.WHATSAPP.DESC')"
|
||||
|
||||
+3
-1
@@ -1,5 +1,7 @@
|
||||
<template>
|
||||
<div class="wizard-body w-[75%] flex-shrink-0 flex-grow-0 max-w-[75%]">
|
||||
<div
|
||||
class="border border-slate-25 dark:border-slate-800/60 bg-white dark:bg-slate-900 h-full p-6 w-full max-w-full md:w-3/4 md:max-w-[75%] flex-shrink-0 flex-grow-0"
|
||||
>
|
||||
<page-header
|
||||
:header-title="$t('INBOX_MGMT.ADD.EMAIL_CHANNEL.TITLE')"
|
||||
:header-content="$t('INBOX_MGMT.ADD.EMAIL_CHANNEL.DESC')"
|
||||
|
||||
+3
-1
@@ -1,5 +1,7 @@
|
||||
<template>
|
||||
<div class="wizard-body w-[75%] flex-shrink-0 flex-grow-0 max-w-[75%]">
|
||||
<div
|
||||
class="border border-slate-25 dark:border-slate-800/60 bg-white dark:bg-slate-900 h-full p-6 w-full max-w-full md:w-3/4 md:max-w-[75%] flex-shrink-0 flex-grow-0"
|
||||
>
|
||||
<settings-sub-page-header
|
||||
:header-title="$t('INBOX_MGMT.ADD.MICROSOFT.TITLE')"
|
||||
:header-content="$t('INBOX_MGMT.ADD.MICROSOFT.DESCRIPTION')"
|
||||
|
||||
+2
-2
@@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<div class="settings--content">
|
||||
<div class="mx-8">
|
||||
<settings-section
|
||||
:title="$t('INBOX_MGMT.MICROSOFT.TITLE')"
|
||||
:sub-title="$t('INBOX_MGMT.MICROSOFT.SUBTITLE')"
|
||||
>
|
||||
<div class="smtp-details-wrap">
|
||||
<div class="mb-6">
|
||||
<form @submit.prevent="requestAuthorization">
|
||||
<woot-submit-button
|
||||
icon="brand-twitter"
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="settings--content">
|
||||
<div class="mx-8">
|
||||
<loading-state v-if="uiFlags.isFetching || uiFlags.isFetchingAgentBot" />
|
||||
<form
|
||||
v-else
|
||||
@@ -10,7 +10,7 @@
|
||||
:title="$t('AGENT_BOTS.BOT_CONFIGURATION.TITLE')"
|
||||
:sub-title="$t('AGENT_BOTS.BOT_CONFIGURATION.DESC')"
|
||||
>
|
||||
<div class="w-[60%]">
|
||||
<div class="w-3/5">
|
||||
<label>
|
||||
<select v-model="selectedAgentBotId">
|
||||
<option value="" disabled selected>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user