1
0
forked from test/crm

refactor: added email templates in settings modal

(cherry picked from commit 1c3ee8b557bf9371aad2d6803876095a1c0a8026)
This commit is contained in:
Shariq Ansari 2025-06-24 15:35:48 +05:30 committed by Mergify
parent aa59703709
commit 14ac102d6d
3 changed files with 210 additions and 0 deletions

View File

@ -94,6 +94,7 @@ declare module 'vue' {
EmailIcon: typeof import('./src/components/Icons/EmailIcon.vue')['default']
EmailProviderIcon: typeof import('./src/components/Settings/EmailProviderIcon.vue')['default']
EmailTemplateModal: typeof import('./src/components/Modals/EmailTemplateModal.vue')['default']
EmailTemplates: typeof import('./src/components/Settings/EmailTemplate/EmailTemplates.vue')['default']
EmailTemplateSelectorModal: typeof import('./src/components/Modals/EmailTemplateSelectorModal.vue')['default']
EmailTemplatesListView: typeof import('./src/components/ListViews/EmailTemplatesListView.vue')['default']
ERPNextIcon: typeof import('./src/components/Icons/ERPNextIcon.vue')['default']

View File

@ -0,0 +1,203 @@
<template>
<div class="flex h-full flex-col gap-6 p-8 text-ink-gray-8">
<!-- Header -->
<div class="flex justify-between">
<div class="flex flex-col gap-1 w-9/12">
<h2 class="flex gap-2 text-xl font-semibold leading-none h-5">
{{ __('Email templates') }}
</h2>
<p class="text-p-base text-ink-gray-6">
{{
__(
'Add, edit, and manage email templates for various CRM communications',
)
}}
</p>
</div>
<div class="flex item-center space-x-2 w-3/12 justify-end">
<Button :label="__('New')" icon-left="plus" variant="solid" />
</div>
</div>
<!-- loading state -->
<div
v-if="templates.loading"
class="flex mt-28 justify-between w-full h-full"
>
<Button
:loading="templates.loading"
variant="ghost"
class="w-full"
size="2xl"
/>
</div>
<!-- Empty State -->
<div
v-if="!templates.loading && !templates.data?.length"
class="flex justify-between w-full h-full"
>
<div
class="text-ink-gray-4 border border-dashed rounded w-full flex items-center justify-center"
>
{{ __('No email templates found') }}
</div>
</div>
<!-- Email template list -->
<div
class="flex flex-col overflow-hidden"
v-if="!templates.loading && templates.data?.length"
>
<div
v-if="templates.data?.length > 10"
class="flex items-center justify-between mb-4"
>
<TextInput
ref="searchRef"
v-model="search"
:placeholder="__('Search template')"
class="w-1/3"
:debounce="300"
>
<template #prefix>
<FeatherIcon name="search" class="h-4 w-4 text-ink-gray-6" />
</template>
</TextInput>
<FormControl
type="select"
v-model="currentDoctype"
:options="[
{ label: __('All'), value: 'All' },
{ label: __('Lead'), value: 'CRM Lead' },
{ label: __('Deal'), value: 'CRM Deal' },
]"
/>
</div>
<div class="flex items-center p-2 text-sm border-b text-ink-gray-5">
<div class="w-4/6">{{ __('Template name') }}</div>
<div class="w-1/6">{{ __('For') }}</div>
<div class="w-1/6">{{ __('Enabled') }}</div>
</div>
<ul class="divide-y divide-outline-gray-modals overflow-y-auto">
<template v-for="template in templatesList" :key="template.name">
<li class="flex items-center justify-between px-2 py-3">
<div class="flex flex-col w-4/6 pr-5">
<div class="text-base font-medium text-ink-gray-7">
{{ template.name }}
</div>
<div class="text-p-base text-ink-gray-5 truncate">
{{ template.subject }}
</div>
</div>
<div class="text-base text-ink-gray-6 w-1/6">
{{ template.reference_doctype.replace('CRM ', '') }}
</div>
<div class="flex items-center justify-between w-1/6">
<Switch
size="sm"
v-model="template.enabled"
@update:model-value="toggleEmailTemplate(template)"
/>
<Dropdown
:options="[
{
label: __('Edit'),
icon: 'edit-2',
onClick: () => {},
},
{
label: __('Duplicate'),
icon: 'copy',
onClick: () => {},
},
{
label: __('Delete'),
icon: 'trash-2',
onClick: () => {},
},
]"
placement="right"
:button="{
icon: 'more-horizontal',
variant: 'ghost',
}"
/>
</div>
</li>
</template>
<!-- Load More Button -->
<div
v-if="!templates.loading && templates.hasNextPage"
class="flex justify-center"
>
<Button
class="mt-3.5 p-2"
@click="() => templates.next()"
:loading="templates.loading"
:label="__('Load More')"
icon-left="refresh-cw"
/>
</div>
</ul>
</div>
</div>
</template>
<script setup>
import {
TextInput,
FormControl,
Switch,
createListResource,
Dropdown,
} from 'frappe-ui'
import { ref, computed } from 'vue'
const templates = createListResource({
type: 'list',
doctype: 'Email Template',
cache: 'emailTemplates',
fields: [
'name',
'enabled',
'use_html',
'reference_doctype',
'subject',
'response',
'response_html',
'modified',
'owner',
],
auto: true,
filters: { reference_doctype: ['in', ['CRM Lead', 'CRM Deal']] },
orderBy: 'modified desc',
pageLength: 20,
})
const search = ref('')
const currentDoctype = ref('All')
const templatesList = computed(() => {
let list = templates.data || []
if (search.value) {
list = list.filter(
(template) =>
template.name.toLowerCase().includes(search.value.toLowerCase()) ||
template.subject.toLowerCase().includes(search.value.toLowerCase()),
)
}
if (currentDoctype.value !== 'All') {
list = list.filter(
(template) => template.reference_doctype === currentDoctype.value,
)
}
return list
})
function toggleEmailTemplate(template) {
templates.setValue.submit({
name: template.name,
enabled: template.enabled ? 1 : 0,
})
}
</script>

View File

@ -51,6 +51,7 @@ import InviteUserPage from '@/components/Settings/InviteUserPage.vue'
import ProfileSettings from '@/components/Settings/ProfileSettings.vue'
import WhatsAppSettings from '@/components/Settings/WhatsAppSettings.vue'
import ERPNextSettings from '@/components/Settings/ERPNextSettings.vue'
import EmailTemplates from '@/components/Settings/EmailTemplate/EmailTemplates.vue'
import TelephonySettings from '@/components/Settings/TelephonySettings.vue'
import EmailConfig from '@/components/Settings/EmailConfig.vue'
import SidebarLink from '@/components/SidebarLink.vue'
@ -107,6 +108,11 @@ const tabs = computed(() => {
component: markRaw(EmailConfig),
condition: () => isManager(),
},
{
label: __('Email Templates'),
icon: Email2Icon,
component: markRaw(EmailTemplates),
},
],
},
{