Skip to content

Commit cdff4a6

Browse files
Merge pull request #2235 from frappe/develop
chore(release): dev to main
2 parents 49fee44 + 62f4257 commit cdff4a6

26 files changed

+117
-138
lines changed

Diff for: desk/src/components/CommunicationArea.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<template>
22
<div class="flex flex-col comm-area">
33
<div
4-
class="flex justify-between gap-3 border-t px-4 lg:px-10 py-4 md:py-2.5"
4+
class="flex justify-between gap-3 border-t px-4 lg:px-6 py-4 md:py-2.5"
55
>
66
<div class="flex gap-1.5">
77
<Button

Diff for: desk/src/components/EmailArea.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
@click="
4747
emit('reply', {
4848
content: content,
49-
to: to ?? sender.name,
49+
to: sender?.name ?? to,
5050
cc: cc,
5151
bcc: bcc,
5252
})

Diff for: desk/src/components/desk/global/NewContactDialog.vue

-8
Original file line numberDiff line numberDiff line change
@@ -174,14 +174,6 @@ const contactResource = createResource({
174174
});
175175
emit("contactCreated");
176176
},
177-
onError: (error: Error) => {
178-
createToast({
179-
title: "Contact Creation Failed",
180-
message: error.message,
181-
icon: "error",
182-
iconClasses: "text-red-600",
183-
});
184-
},
185177
});
186178
187179
function createContact() {

Diff for: desk/src/components/layouts/Sidebar.vue

+4-1
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,10 @@
9393
</Section>
9494
</div>
9595
<div class="grow" />
96-
<TrialBanner v-if="isFCSite" :isSidebarCollapsed="!isExpanded" />
96+
<TrialBanner
97+
v-if="isFCSite && !isCustomerPortal"
98+
:isSidebarCollapsed="!isExpanded"
99+
/>
97100
<SidebarLink
98101
:icon="isExpanded ? LucideArrowLeftFromLine : LucideArrowRightFromLine"
99102
:is-active="false"

Diff for: desk/src/components/ticket/ActivityHeader.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<template>
22
<div
3-
class="md:mx-10 md:my-4 flex items-center justify-between text-lg font-medium mx-5 mb-4 mt-8"
3+
class="md:mx-8 md:my-4 flex items-center justify-between text-lg font-medium mx-5 mb-4 mt-8"
44
>
55
<div class="flex h-8 items-center text-xl font-semibold text-gray-800">
66
{{ title }}

Diff for: desk/src/components/ticket/TicketAgentActivities.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ function scrollToLatestActivity() {
129129
let e = document.getElementsByClassName("activity");
130130
el = e[e.length - 1];
131131
if (el && !useElementVisibility(el).value) {
132-
el.scrollIntoView({ behavior: "smooth" });
132+
el.scrollIntoView();
133133
el.focus();
134134
}
135135
}, 500);

Diff for: desk/src/components/ticket/TicketAgentDetails.vue

+48-37
Original file line numberDiff line numberDiff line change
@@ -32,47 +32,35 @@ import { dateFormat, dateTooltipFormat } from "@/utils";
3232
import { computed } from "vue";
3333
3434
const props = defineProps({
35-
agreementStatus: {
36-
type: String,
37-
required: true,
38-
},
39-
ticketCreatedOn: {
40-
type: String,
41-
required: true,
42-
},
43-
firstRespondedOn: {
44-
type: String,
45-
required: true,
46-
},
47-
responseBy: {
48-
type: String,
49-
required: true,
50-
},
51-
resolutionDate: {
52-
type: String,
53-
required: true,
54-
},
55-
resolutionBy: {
56-
type: String,
57-
required: true,
58-
},
59-
source: {
60-
type: String,
35+
ticket: {
36+
type: Object,
6137
required: true,
6238
},
6339
});
6440
6541
const firstResponseBadge = computed(() => {
6642
let firstResponse = null;
67-
if (!props.firstRespondedOn && dayjs().isBefore(dayjs(props.responseBy))) {
43+
if (
44+
!props.ticket.first_responded_on &&
45+
dayjs().isBefore(dayjs(props.ticket.response_by))
46+
) {
6847
firstResponse = {
69-
label: `Due in ${formatTime(dayjs(props.responseBy).diff(dayjs(), "s"))}`,
48+
label: `Due in ${formatTime(
49+
dayjs(props.ticket.response_by).diff(dayjs(), "s")
50+
)}`,
7051
color: "orange",
7152
};
72-
} else if (dayjs(props.firstRespondedOn).isBefore(dayjs(props.responseBy))) {
53+
} else if (
54+
dayjs(props.ticket.first_responded_on).isBefore(
55+
dayjs(props.ticket.response_by)
56+
)
57+
) {
7358
firstResponse = {
7459
label: `Fulfilled in ${formatTime(
75-
dayjs(props.firstRespondedOn).diff(dayjs(props.ticketCreatedOn), "s")
60+
dayjs(props.ticket.first_responded_on).diff(
61+
dayjs(props.ticket.creation),
62+
"s"
63+
)
7664
)}`,
7765
color: "green",
7866
};
@@ -87,17 +75,40 @@ const firstResponseBadge = computed(() => {
8775
8876
const resolutionBadge = computed(() => {
8977
let resolution = null;
90-
if (!props.resolutionDate && dayjs().isBefore(props.resolutionBy)) {
78+
if (
79+
props.ticket.status === "Replied" &&
80+
props.ticket.on_hold_since &&
81+
dayjs(props.ticket.resolution_by).isAfter(dayjs(props.ticket.on_hold_since))
82+
) {
83+
let time_left = formatTime(
84+
dayjs(props.ticket.resolution_by).diff(
85+
dayjs(props.ticket.on_hold_since),
86+
"s"
87+
)
88+
);
89+
resolution = {
90+
label: `${time_left} left (On Hold)`,
91+
color: "blue",
92+
};
93+
} else if (
94+
!props.ticket.resolution_date &&
95+
dayjs().isBefore(props.ticket.resolution_by)
96+
) {
9197
resolution = {
9298
label: `Due in ${formatTime(
93-
dayjs(props.resolutionBy).diff(dayjs(), "s")
99+
dayjs(props.ticket.resolution_by).diff(dayjs(), "s")
94100
)}`,
95101
color: "orange",
96102
};
97-
} else if (dayjs(props.resolutionDate).isBefore(props.resolutionBy)) {
103+
} else if (
104+
dayjs(props.ticket.resolution_date).isBefore(props.ticket.resolution_by)
105+
) {
98106
resolution = {
99107
label: `Fulfilled in ${formatTime(
100-
dayjs(props.resolutionDate).diff(dayjs(props.ticketCreatedOn), "s")
108+
dayjs(props.ticket.resolution_date).diff(
109+
dayjs(props.ticket.creation),
110+
"s"
111+
)
101112
)}`,
102113
color: "green",
103114
};
@@ -114,7 +125,7 @@ const sections = computed(() => [
114125
{
115126
label: "First Response",
116127
tooltipValue: dateFormat(
117-
props.firstRespondedOn || props.responseBy,
128+
props.ticket.first_responded_on || props.ticket.response_by,
118129
dateTooltipFormat
119130
),
120131
badgeText: firstResponseBadge.value.label,
@@ -123,15 +134,15 @@ const sections = computed(() => [
123134
{
124135
label: "Resolution",
125136
tooltipValue: dateFormat(
126-
props.resolutionDate || props.resolutionBy,
137+
props.ticket.resolution_date || props.ticket.resolution_by,
127138
dateTooltipFormat
128139
),
129140
badgeText: resolutionBadge.value.label,
130141
badgeColor: resolutionBadge.value.color,
131142
},
132143
{
133144
label: "Source",
134-
value: props.source,
145+
value: props.ticket.via_customer_portal ? "Portal" : "Mail",
135146
},
136147
]);
137148
</script>

Diff for: desk/src/components/ticket/TicketAgentSidebar.vue

+4-10
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
<template>
22
<div class="flex w-[382px] flex-col justify-between border-l">
3-
<div class="h-[2.83rem] flex items-center justify-between border-b px-5">
3+
<div
4+
class="flex h-10.5 cursor-copy items-center border-b px-5 py-2.5 text-lg font-medium text-ink-gray-9"
5+
>
46
<span
57
class="cursor-copy text-lg font-semibold"
68
@click="copyToClipboard(ticket.name, ticket.name)"
@@ -18,15 +20,7 @@
1820
:ticket="ticket"
1921
/>
2022
<!-- ticket details -->
21-
<TicketAgentDetails
22-
:agreement-status="ticket.agreement_status"
23-
:first-responded-on="ticket.first_responded_on"
24-
:response-by="ticket.response_by"
25-
:resolution-date="ticket.resolution_date"
26-
:resolution-by="ticket.resolution_by"
27-
:ticket-created-on="ticket.creation"
28-
:source="ticket.via_customer_portal ? 'Portal' : 'Mail'"
29-
/>
23+
<TicketAgentDetails :ticket="ticket" />
3024
<!-- fields -->
3125
<TicketAgentFields :ticket="ticket" @update="update" />
3226
</div>

Diff for: desk/src/components/ticket/TicketCustomerSidebar.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858
<!-- feedback component -->
5959
<TicketFeedback
6060
v-if="ticket.data.feedback_rating"
61-
class="border-b px-6 py-3 text-base text-gray-600"
61+
class="border-b text-base text-gray-600"
6262
:ticket="ticket.data"
6363
/>
6464
<div class="flex flex-col gap-4 pt-0 px-5 py-3">

Diff for: desk/src/components/ticket/TicketFeedback.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<template>
2-
<div class="flex flex-col gap-3 border-b px-6 py-3">
2+
<div class="flex flex-col gap-4 border-b px-5 pb-3">
33
<div class="flex items-center text-base leading-5">
44
<div class="min-w-[126px] text-sm">Rating</div>
55
<div class="">

Diff for: desk/src/main.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,12 @@ const globalComponents = {
3535

3636
setConfig("resourceFetcher", frappeRequest);
3737
setConfig("fallbackErrorHandler", (error) => {
38+
const text = error.exc_type
39+
? (error.messages || error.message || []).join(", ")
40+
: error.message;
3841
createToast({
3942
title: error.exc_type || "Error",
40-
text: (error.messages || []).join(", "),
43+
text,
4144
icon: "alert-triangle",
4245
iconClasses: "text-red-500",
4346
});

Diff for: desk/src/pages/desk/contact/ContactDialog.vue

-3
Original file line numberDiff line numberDiff line change
@@ -147,9 +147,6 @@ const contact = createDocumentResource({
147147
onSuccess() {
148148
emit("contactUpdated");
149149
},
150-
onError() {
151-
useError({ title: "Error updating contact" });
152-
},
153150
},
154151
});
155152

Diff for: desk/src/pages/desk/team/Teams.vue

-1
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,6 @@ const newTeam = createResource({
9191
},
9292
});
9393
},
94-
onError: useError({ title: "Error creating team" }),
9594
});
9695
9796
usePageMeta(() => {

Diff for: desk/src/pages/ticket/MobileTicketAgent.vue

+1-23
Original file line numberDiff line numberDiff line change
@@ -76,15 +76,7 @@
7676
/>
7777
<!-- SLA Section -->
7878
<h3 class="px-6 pt-3 font-semibold text-base">SLA</h3>
79-
<TicketAgentDetails
80-
:agreement-status="ticket.data.agreement_status"
81-
:first-responded-on="ticket.data.first_responded_on"
82-
:response-by="ticket.data.response_by"
83-
:resolution-date="ticket.data.resolution_date"
84-
:resolution-by="ticket.data.resolution_by"
85-
:ticket-created-on="ticket.data.creation"
86-
:source="ticket.data.via_customer_portal ? 'Portal' : 'Mail'"
87-
/>
79+
<TicketAgentDetails :ticket="ticket.data" />
8880
<!-- Ticket Fields -->
8981
<h3 class="px-6 pt-3 font-semibold text-base">Details</h3>
9082
<TicketAgentFields
@@ -423,20 +415,6 @@ function updateTicket(fieldname: string, value: string) {
423415
iconClasses: "text-green-600",
424416
});
425417
},
426-
onError: (e) => {
427-
isLoading.value = false;
428-
429-
const title =
430-
e.messages && e.messages.length > 0
431-
? e.messages[0]
432-
: "Failed to update ticket";
433-
434-
createToast({
435-
title,
436-
icon: "x",
437-
iconClasses: "text-red-600",
438-
});
439-
},
440418
});
441419
}
442420
onMounted(() => {

Diff for: desk/src/pages/ticket/TicketAgent.vue

+11-5
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,7 @@ function filterActivities(eventType: TicketTab) {
362362
363363
function updateTicket(fieldname: string, value: string) {
364364
if (value === ticket.data[fieldname]) return;
365+
updateOptimistic(fieldname, value);
365366
isLoading.value = true;
366367
createResource({
367368
url: "frappe.client.set_value",
@@ -375,15 +376,20 @@ function updateTicket(fieldname: string, value: string) {
375376
auto: true,
376377
onSuccess: () => {
377378
isLoading.value = false;
378-
createToast({
379-
title: "Ticket updated",
380-
icon: "check",
381-
iconClasses: "text-green-600",
382-
});
379+
ticket.reload();
383380
},
384381
});
385382
}
386383
384+
function updateOptimistic(fieldname: string, value: string) {
385+
ticket.data[fieldname] = value;
386+
createToast({
387+
title: "Ticket updated",
388+
icon: "check",
389+
iconClasses: "text-green-600",
390+
});
391+
}
392+
387393
onMounted(() => {
388394
document.title = props.ticketId;
389395
socket.on("helpdesk:ticket-update", (ticketID) => {

Diff for: desk/src/pages/ticket/TicketConversation.vue

+13-3
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,21 @@ const communications = computed(() => {
6262
return orderBy(_communications, (c) => dayjs(c.creation));
6363
});
6464
65+
function isElementInViewport(el: HTMLElement) {
66+
if (!el) return false;
67+
const rect = el.getBoundingClientRect();
68+
return (
69+
rect.top >= 0 &&
70+
rect.left >= 0 &&
71+
rect.bottom <= window.innerHeight &&
72+
rect.right <= window.innerWidth
73+
);
74+
}
75+
6576
function scroll(id: string) {
6677
const e = document.getElementById(id);
67-
if (!useElementVisibility(e).value) {
68-
e.scrollIntoView({ behavior: "smooth" });
69-
e.focus();
78+
if (!isElementInViewport(e)) {
79+
e.scrollIntoView();
7080
}
7181
}
7282

0 commit comments

Comments
 (0)