fix: add empty state in contact feedback

This commit is contained in:
Ritvik Sardana
2026-06-23 10:37:00 +05:30
parent d3fc9b8168
commit 3393842de3
7 changed files with 57 additions and 22 deletions
+7 -5
View File
@@ -344,12 +344,14 @@ function onInput(e) {
function onSelect(val) {
if (!val) return;
addValue(val);
if (!error.value) {
query.value = "";
tempSelection.value = null;
showOptions.value = true;
nextTick(() => setFocus());
if (error.value) {
showOptions.value = false;
return;
}
query.value = "";
tempSelection.value = null;
showOptions.value = true;
nextTick(() => setFocus());
}
// Commit the current query as a pill on Enter, comma or space.
+26 -3
View File
@@ -12,8 +12,26 @@
/>
</div>
<!-- Loading -->
<div v-if="feedbackListResource.loading" class="flex justify-center py-10">
<LoadingIndicator :scale="10" />
</div>
<!-- Empty state -->
<div
v-else-if="!feedbackListResource.data?.length"
class="flex flex-col items-center justify-center gap-3 py-16 text-center h-full flex-1"
>
<LucideMessageSquare class="h-10 w-10 text-ink-gray-4" />
<div>
<p class="text-lg font-medium text-ink-gray-7">
{{ __("No reviews found") }}
</p>
</div>
</div>
<!-- List -->
<div class="flex flex-col gap-2 max-h-[65vh] overflow-y-auto">
<div v-else class="flex flex-col gap-2 max-h-[65vh] overflow-y-auto">
<template v-for="ticket in feedbackListResource.data" :key="ticket.name">
<div
class="flex cursor-pointer flex-col gap-2 rounded-md border border-outline-gray-1 bg-surface-white p-2.5 hover:bg-surface-gray-1"
@@ -75,9 +93,10 @@
<script setup lang="ts">
import { useContactFeedback } from "@/composables/contact";
import { __ } from "@/translation";
import { TabButtons, Tooltip, dayjs } from "frappe-ui";
import { ref } from "vue";
import { dayjs, LoadingIndicator, TabButtons, Tooltip } from "frappe-ui";
import { onMounted, ref } from "vue";
import { useRouter } from "vue-router";
import LucideMessageSquare from "~icons/lucide/message-square";
import LucideStar from "~icons/lucide/star";
const props = defineProps<{
@@ -158,4 +177,8 @@ function ratingBadgeClass(rating: number | undefined | null): string {
if (stars >= 2.5) return "bg-yellow-100 text-yellow-700";
return "bg-red-100 text-red-700";
}
onMounted(() => {
onSortChange(activeSort.value);
});
</script>
@@ -26,7 +26,7 @@
<div>
<!-- make font larger -->
<p class="text-lg font-medium text-ink-gray-7">
{{ __("No contacts found.") }}
{{ __("No contacts found") }}
</p>
</div>
</div>
@@ -87,7 +87,7 @@
>
<li
:class="[
'flex items-center rounded px-2.5 py-1.5 text-base',
'flex items-center rounded px-2.5 py-1.5 text-base cursor-pointer',
{ 'bg-surface-gray-2': active },
]"
>
+1
View File
@@ -25,6 +25,7 @@ html,
body {
color: var(--ink-gray-9);
background-color: var(--surface-white);
overscroll-behavior: none;
}
:root {
+2 -2
View File
@@ -41,7 +41,7 @@
</div>
</template>
</PageInfo>
<div class="overflow-y-auto flex-1">
<div class="overflow-y-auto flex-1 flex flex-col">
<TicketStats :dt="'Contact'" :dn="id" v-if="!isMobileView" />
<Tabs v-model="activeTab" :tabs="tabs" class="tabs-sticky-header">
<template #tab-item="{ tab, selected }: any">
@@ -67,7 +67,7 @@
</button>
</template>
<template #tab-panel="{ tab }">
<div class="p-5 overflow-hidden">
<div class="p-5 overflow-hidden flex flex-col flex-1 min-h-0">
<TicketsTab
v-if="tab.label === __('Tickets')"
:doc="contact"
+19 -10
View File
@@ -32,7 +32,7 @@
</div>
</template>
</PageInfo>
<div class="overflow-y-auto flex-1">
<div class="overflow-y-auto flex-1 flex flex-col">
<TicketStats
:dt="'HD Customer'"
:dn="customer.doc.name"
@@ -63,21 +63,14 @@
</button>
</template>
<template #tab-panel="{ tab }">
<div class="p-5 overflow-hidden">
<div class="p-5 overflow-hidden flex flex-col flex-1 min-h-0">
<div v-if="tab.label === __('Tickets')">
<!-- Tickets tab content -->
<TicketsTab
:doc="customer"
:ticketsListResource="ticketsListResource"
:baseFilter="{ customer: props.id }"
:additionalFilter="{
key: 'contact',
placeholder: __('Contact'),
doctype: 'Contact',
filters: customer.getContacts.data?.length
? { name: ['in', customer.getContacts.data.map((c: { contact_name: string }) => c.contact_name)] }
: undefined,
}"
:additionalFilter="contactFilter"
/>
</div>
<CustomerContactTab v-if="tab.label === __('Contacts')" />
@@ -167,6 +160,22 @@ const tabs = computed(() => [
const { doc: customer, handleDelete } = useCustomer(props.id);
provide(CustomerResourceSymbol, customer);
const contactFilter = computed(() => {
const contacts = customer.getContacts.data ?? [];
if (contacts.length <= 1) return undefined;
return {
key: "contact",
placeholder: __("Contact"),
doctype: "Contact",
filters: {
name: [
"in",
contacts.map((c: { contact_name: string }) => c.contact_name),
],
},
};
});
const activeTab = computed<number>({
get() {
const index = tabs.value.findIndex((t) => t.hash === route.hash.slice(1));