fix: added email template modal which is showed when row in listview is clicked

This commit is contained in:
Shariq Ansari 2024-01-26 18:46:09 +05:30
parent b261506559
commit 2a5d4425d0
4 changed files with 220 additions and 46 deletions

View File

@ -43,6 +43,7 @@ class CustomEmailTemplate(EmailTemplate):
"enabled",
"reference_doctype",
"subject",
"response",
"modified",
]
return {'columns': columns, 'rows': rows}

View File

@ -3,10 +3,7 @@
:columns="columns"
:rows="rows"
:options="{
getRowRoute: (row) => ({
name: 'Email Template',
params: { emailTemplateId: row.name },
}),
onRowClick: (row) => emit('showEmailTemplate', row.name),
selectable: options.selectable,
}"
row-key="name"
@ -72,6 +69,7 @@ import {
ListRowItem,
ListFooter,
} from 'frappe-ui'
import { defineModel } from 'vue'
const props = defineProps({
rows: {
@ -92,7 +90,7 @@ const props = defineProps({
},
})
const emit = defineEmits(['loadMore'])
const emit = defineEmits(['loadMore', 'showEmailTemplate'])
const pageLengthCount = defineModel()
</script>

View File

@ -0,0 +1,190 @@
<template>
<Dialog
v-model="show"
:options="{
title: editMode ? 'Edit Email Template' : 'Create Email Template',
size: 'xl',
actions: [
{
label: editMode ? 'Update' : 'Create',
variant: 'solid',
onClick: () => (editMode ? updateEmailTemplate() : callInsertDoc()),
},
],
}"
>
<template #body-content>
<div class="flex flex-col gap-4">
<div>
<div class="mb-1.5 text-sm text-gray-600">
Name
<span class="text-red-500">*</span>
</div>
<TextInput
variant="outline"
v-model="_emailTemplate.name"
placeholder="Add name"
/>
</div>
<div>
<div class="mb-1.5 text-sm text-gray-600">Doctype</div>
<TextInput
variant="outline"
v-model="_emailTemplate.reference_doctype"
placeholder="Add Doctype"
/>
</div>
<div>
<div class="mb-1.5 text-sm text-gray-600">
Subject
<span class="text-red-500">*</span>
</div>
<TextInput
ref="subject"
variant="outline"
v-model="_emailTemplate.subject"
placeholder="Add subject"
/>
</div>
<div>
<div class="mb-1.5 text-sm text-gray-600">
Content
<span class="text-red-500">*</span>
</div>
<TextEditor
variant="outline"
ref="content"
editor-class="!prose-sm overflow-auto min-h-[180px] max-h-80 py-1.5 px-2 rounded border border-gray-300 bg-white hover:border-gray-400 hover:shadow-sm focus:bg-white focus:border-gray-500 focus:shadow-sm focus:ring-0 focus-visible:ring-2 focus-visible:ring-gray-400 text-gray-800 transition-colors"
:bubbleMenu="true"
:content="_emailTemplate.response"
@change="(val) => (_emailTemplate.response = val)"
placeholder="Type a Content"
/>
</div>
<div>
<Checkbox v-model="_emailTemplate.enabled" label="Enabled" />
</div>
<ErrorMessage :message="errorMessage" />
</div>
</template>
</Dialog>
</template>
<script setup>
import { Checkbox, TextEditor, call } from 'frappe-ui'
import { ref, defineModel, nextTick, watch } from 'vue'
const props = defineProps({
emailTemplate: {
type: Object,
default: {},
},
})
const show = defineModel()
const emailTemplates = defineModel('reloadEmailTemplates')
const errorMessage = ref('')
const emit = defineEmits(['after'])
const subject = ref(null)
const editMode = ref(false)
let _emailTemplate = ref({})
async function updateEmailTemplate() {
if (!validate()) return
const old = { ...props.emailTemplate }
const newEmailTemplate = { ..._emailTemplate.value }
const nameChanged = old.name !== newEmailTemplate.name
delete old.name
delete newEmailTemplate.name
const otherFieldChanged =
JSON.stringify(old) !== JSON.stringify(newEmailTemplate)
const values = newEmailTemplate
if (!nameChanged && !otherFieldChanged) {
show.value = false
return
}
let name
if (nameChanged) {
name = await callRenameDoc()
}
if (otherFieldChanged) {
name = await callSetValue(values)
}
handleEmailTemplateUpdate({ name })
}
async function callRenameDoc() {
const d = await call('frappe.client.rename_doc', {
doctype: 'Email Template',
old_name: props.emailTemplate.name,
new_name: _emailTemplate.value.name,
})
return d
}
async function callSetValue(values) {
const d = await call('frappe.client.set_value', {
doctype: 'Email Template',
name: _emailTemplate.value.name,
fieldname: values,
})
return d.name
}
async function callInsertDoc() {
if (!validate()) return
const doc = await call('frappe.client.insert', {
doc: {
doctype: 'Email Template',
..._emailTemplate.value,
},
})
doc.name && handleEmailTemplateUpdate(doc)
}
function handleEmailTemplateUpdate(doc) {
emailTemplates.value?.reload()
show.value = false
}
function validate() {
if (!_emailTemplate.value.name) {
errorMessage.value = 'Name is required'
return false
}
if (!_emailTemplate.value.subject) {
errorMessage.value = 'Subject is required'
return false
}
if (
!_emailTemplate.value.response ||
_emailTemplate.value.response === '<p></p>'
) {
errorMessage.value = 'Content is required'
return false
}
return true
}
watch(
() => show.value,
(value) => {
if (!value) return
editMode.value = false
errorMessage.value = ''
nextTick(() => {
subject.value.el.focus()
_emailTemplate.value = { ...props.emailTemplate }
if (_emailTemplate.value.name) {
editMode.value = true
}
})
}
)
</script>

View File

@ -19,6 +19,7 @@
totalCount: emailTemplates.data.total_count,
}"
@loadMore="() => loadMore++"
@showEmailTemplate="showEmailTemplate"
/>
<div
v-else-if="emailTemplates.data"
@ -27,31 +28,27 @@
<div
class="flex flex-col items-center gap-3 text-xl font-medium text-gray-500"
>
<PhoneIcon class="h-10 w-10" />
<span>No Logs Found</span>
<EmailIcon class="h-10 w-10" />
<span>No Email Templates Found</span>
</div>
</div>
<EmailTemplateModal
v-model="showEmailTemplateModal"
v-model:reloadEmailTemplates="emailTemplates"
:emailTemplate="emailTemplate"
/>
</template>
<script setup>
import PhoneIcon from '@/components/Icons/PhoneIcon.vue'
import EmailIcon from '@/components/Icons/EmailIcon.vue'
import LayoutHeader from '@/components/LayoutHeader.vue'
import ViewControls from '@/components/ViewControls.vue'
import EmailTemplatesListView from '@/components/ListViews/EmailTemplatesListView.vue'
import {
secondsToDuration,
dateFormat,
dateTooltipFormat,
timeAgo,
} from '@/utils'
import { usersStore } from '@/stores/users'
import { contactsStore } from '@/stores/contacts'
import EmailTemplateModal from '@/components/Modals/EmailTemplateModal.vue'
import { dateFormat, dateTooltipFormat, timeAgo } from '@/utils'
import { Breadcrumbs } from 'frappe-ui'
import { computed, ref } from 'vue'
const { getUser } = usersStore()
const { getContact, getLeadContact } = contactsStore()
const breadcrumbs = [
{ label: 'Email Templates', route: { name: 'Email Templates' } },
]
@ -67,12 +64,7 @@ const rows = computed(() => {
emailTemplates.value?.data.rows.forEach((row) => {
_rows[row] = emailTemplate[row]
if (row === 'status') {
_rows[row] = {
label: statusLabelMap[emailTemplate.status],
color: statusColorMap[emailTemplate.status],
}
} else if (['modified', 'creation'].includes(row)) {
if (['modified', 'creation'].includes(row)) {
_rows[row] = {
label: dateFormat(emailTemplate[row], dateTooltipFormat),
timeAgo: timeAgo(emailTemplate[row]),
@ -83,27 +75,20 @@ const rows = computed(() => {
})
})
const statusLabelMap = {
Completed: 'Completed',
Initiated: 'Initiated',
Busy: 'Declined',
Failed: 'Failed',
Queued: 'Queued',
Cancelled: 'Cancelled',
Ringing: 'Ringing',
'No Answer': 'Missed Call',
'In Progress': 'In Progress',
}
const showEmailTemplateModal = ref(false)
const statusColorMap = {
Completed: 'green',
Busy: 'orange',
Failed: 'red',
Initiated: 'gray',
Queued: 'gray',
Cancelled: 'gray',
Ringing: 'gray',
'No Answer': 'red',
'In Progress': 'blue',
const emailTemplate = ref({})
function showEmailTemplate(name) {
let et = rows.value?.find((row) => row.name === name)
emailTemplate.value = {
subject: et.subject,
response: et.response,
name: et.name,
enabled: et.enabled,
owner: et.owner,
reference_doctype: et.reference_doctype,
}
showEmailTemplateModal.value = true
}
</script>