Skip to content

Commit

Permalink
Merge pull request #2151 from RitvikSardana/comment-box-refactor
Browse files Browse the repository at this point in the history
refactor: comment box
  • Loading branch information
RitvikSardana authored Jan 28, 2025
2 parents 9901118 + 030cd8b commit 9ecf7c4
Show file tree
Hide file tree
Showing 17 changed files with 243 additions and 84 deletions.
131 changes: 117 additions & 14 deletions desk/src/components/CommentBox.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<div class="flex-col text-base">
<div class="flex-col text-base flex-1" ref="commentBoxRef">
<div class="mb-1 ml-0.5 flex items-center justify-between">
<div class="text-gray-600 flex items-center gap-2">
<Avatar
Expand All @@ -17,15 +17,26 @@
</span>
</p>
</div>
<div class="flex items-center">
<div class="flex items-center gap-1">
<Tooltip :text="dateFormat(creation, dateTooltipFormat)">
<span class="pl-0.5 text-sm text-gray-600">
{{ timeAgo(creation) }}
</span>
</Tooltip>
<div v-if="authStore.userId === commentedBy">
<div v-if="authStore.userId === commentedBy && !editable">
<Dropdown
:options="[{ label: 'Delete', onClick: () => (showDialog = true) }]"
:options="[
{
label: 'Edit',
onClick: () => handleEditMode(),
icon: 'edit-2',
},
{
label: 'Delete',
onClick: () => (showDialog = true),
icon: 'trash-2',
},
]"
>
<Button
icon="more-horizontal"
Expand All @@ -36,10 +47,31 @@
</div>
</div>
</div>
<div
class="prose-f grow cursor-pointer rounded bg-gray-50 px-4 py-3 text-base leading-6 transition-all duration-300 ease-in-out"
v-html="content"
/>
<div class="rounded bg-gray-50 px-4 py-3">
<TextEditor
ref="editorRef"
:editor-class="'prose-f shrink text-p-sm transition-all duration-300 ease-in-out block w-full content'"
:content="_content"
:editable="editable"
:bubble-menu="textEditorMenuButtons"
@change="(event:string) => {_content = event}"
>
<template #bottom v-if="editable">
<div class="flex flex-row-reverse gap-2">
<Button label="Save" @click="handleSaveComment" variant="solid" />
<Button label="Discard" @click="handleDiscard" />
</div>
</template>
</TextEditor>
<div class="flex flex-wrap gap-2" v-if="!editable">
<AttachmentItem
v-for="a in attachments"
:key="a.file_url"
:label="a.file_name"
:url="a.file_url"
/>
</div>
</div>
</div>
<Dialog
v-model="showDialog"
Expand All @@ -59,25 +91,57 @@
</template>

<script setup lang="ts">
import { ref } from "vue";
import { Dropdown, createResource, Dialog, Avatar } from "frappe-ui";
import { dateFormat, timeAgo, dateTooltipFormat, createToast } from "@/utils";
import { ref, PropType, onMounted } from "vue";
import {
Dropdown,
createResource,
Dialog,
Avatar,
TextEditor,
} from "frappe-ui";
import {
dateFormat,
timeAgo,
dateTooltipFormat,
createToast,
textEditorMenuButtons,
isContentEmpty,
} from "@/utils";
import { AttachmentItem } from "@/components";
import { useAuthStore } from "@/stores/auth";
import { useUserStore } from "@/stores/user";

import { CommentActivity } from "@/types";
import { updateRes as updateComment } from "@/stores/knowledgeBase";
const authStore = useAuthStore();
const props = defineProps({
activity: {
type: Object,
type: Object as PropType<CommentActivity>,
required: true,
},
});
const { getUser } = useUserStore();

const { name, creation, content, commenter, commentedBy } = props.activity;
const { name, creation, content, commenter, commentedBy, attachments } =
props.activity;

const emit = defineEmits(["update"]);
const showDialog = ref(false);
const editable = ref(false);
const _content = ref(content);

// HTML refs
const commentBoxRef = ref(null);
const editorRef = ref(null);

function handleEditMode() {
editable.value = true;
editorRef.value.editor.chain().focus("start");
}

function handleDiscard() {
_content.value = content;
editable.value = false;
}

const deleteComment = createResource({
url: "frappe.client.delete",
Expand All @@ -94,4 +158,43 @@ const deleteComment = createResource({
});
},
});

function handleSaveComment() {
if (content === _content.value) {
editable.value = false;
return;
}
if (isContentEmpty(_content.value)) {
createToast({
title: "Comment cannot be empty",
icon: "x",
iconClasses: "text-red-600",
});
return;
}

updateComment.submit(
{
doctype: "HD Ticket Comment",
name: name,
fieldname: "content",
value: _content.value,
},
{
onSuccess: () => {
editable.value = false;
emit("update");
createToast({
title: "Comment updated",
icon: "check",
iconClasses: "text-green-500",
});
},
}
);
}

onMounted(() => {
commentBoxRef.value.style.width = "0px";
});
</script>
4 changes: 4 additions & 0 deletions desk/src/components/CommentTextEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -154,12 +154,16 @@ async function submitComment() {
method: "new_comment",
args: {
content: newComment.value,
attachments: attachments.value,
},
}),
onSuccess: () => {
emit("submit");
loading.value = false;
},
onError: () => {
loading.value = false;
},
});

comment.submit();
Expand Down
10 changes: 2 additions & 8 deletions desk/src/components/EmailArea.vue
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,7 @@
</span>
<span v-if="bcc">{{ bcc }}</span>
</div>
<!-- <div
class="email-content prose-f max-h-[500px] overflow-y-auto"
v-html="content"
/> -->
<EmailContent :content="content" :emailBox="emailBox" />
<EmailContent :content="content" />
<div class="flex flex-wrap gap-2">
<AttachmentItem
v-for="a in attachments"
Expand All @@ -88,11 +84,10 @@
</template>

<script setup lang="ts">
import { UserAvatar, AttachmentItem } from "@/components";
import { AttachmentItem } from "@/components";
import { dateFormat, timeAgo, dateTooltipFormat } from "@/utils";
import { ReplyIcon, ReplyAllIcon } from "./icons";
import { useScreenSize } from "@/composables/screen";
import { inject } from "vue";

const props = defineProps({
activity: {
Expand All @@ -106,7 +101,6 @@ const { sender, to, cc, bcc, creation, subject, attachments, content } =

const emit = defineEmits(["reply"]);

let emailBox = inject("communicationArea");
const { isMobileView } = useScreenSize();

// TODO: Implement reply functionality using this way instead of emit drillup
Expand Down
1 change: 0 additions & 1 deletion desk/src/components/EmailEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,6 @@ import {
} from "@/components";
import { AttachmentIcon, EmailIcon } from "@/components/icons";
import { PreserveVideoControls } from "@/tiptap-extensions";
import { useError } from "@/composables/error";

const editorRef = ref(null);
const showCannedResponseSelectorModal = ref(false);
Expand Down
84 changes: 44 additions & 40 deletions desk/src/components/HistoryBox.vue
Original file line number Diff line number Diff line change
@@ -1,52 +1,56 @@
<template>
<div class="mt-1.5 flex justify-between text-base">
<div class="text-gray-600">
<span class="font-medium text-gray-800">
{{ user }}
</span>
<span> {{ content }}</span>
</div>
<Tooltip :text="dateFormat(creation, dateTooltipFormat)">
<div class="text-gray-600">
{{ timeAgo(creation) }}
</div>
</Tooltip>
</div>
<div v-if="show_others && content !== 'created this ticket'">
<div
v-for="relatedActivity in relatedActivities"
:key="relatedActivity.creation"
class="mt-2 flex justify-between text-base"
>
<div class="flex-1">
<div class="mt-1.5 flex justify-between text-base items-center">
<div class="text-gray-600">
<span class="font-medium text-gray-800">
{{ relatedActivity.user }}
{{ user }}
</span>
<span> {{ relatedActivity.content }}</span>
<span> {{ content }}</span>
</div>
<Tooltip :text="dateFormat(relatedActivity.creation, dateTooltipFormat)">
<div class="text-gray-600">
{{ timeAgo(relatedActivity.creation) }}
<Tooltip :text="dateFormat(creation, dateTooltipFormat)">
<div class="text-gray-600 text-sm">
{{ timeAgo(creation) }}
</div>
</Tooltip>
</div>
<div v-if="show_others && content !== 'created this ticket'">
<div
v-for="relatedActivity in relatedActivities"
:key="relatedActivity.creation"
class="mt-2 flex justify-between text-base"
>
<div class="text-gray-600">
<span class="font-medium text-gray-800">
{{ relatedActivity.user }}
</span>
<span> {{ relatedActivity.content }}</span>
</div>
<Tooltip
:text="dateFormat(relatedActivity.creation, dateTooltipFormat)"
>
<div class="text-gray-600 text-sm">
{{ timeAgo(relatedActivity.creation) }}
</div>
</Tooltip>
</div>
</div>
<Button
v-if="relatedActivities.length && content !== 'created this ticket'"
:label="
show_others ? 'Hide' : `${relatedActivities.length} other activities`
"
variant="outline"
class="mt-2"
@click="show_others = !show_others"
>
<template #suffix>
<FeatherIcon
:name="show_others ? 'chevron-up' : 'chevron-down'"
class="h-4 text-gray-600"
/>
</template>
</Button>
</div>
<Button
v-if="relatedActivities.length && content !== 'created this ticket'"
:label="
show_others ? 'Hide' : `${relatedActivities.length} other activities`
"
variant="outline"
class="mt-2"
@click="show_others = !show_others"
>
<template #suffix>
<FeatherIcon
:name="show_others ? 'chevron-up' : 'chevron-down'"
class="h-4 text-gray-600"
/>
</template>
</Button>
</template>

<script setup lang="ts">
Expand Down
2 changes: 1 addition & 1 deletion desk/src/components/layouts/MobileSidebar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
<!-- user dropwdown -->
<div><UserMenu class="p-2 mb-2" :options="profileSettings" /></div>
<!-- notifications -->
<div class="overflow-y-auto px-2">
<div class="overflow-y-auto px-2" v-if="!isCustomerPortal">
<div class="mb-3 flex flex-col">
<SidebarLink
class="relative"
Expand Down
4 changes: 3 additions & 1 deletion desk/src/components/layouts/Sidebar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@
<template #right>
<Badge
v-if="isExpanded && notificationStore.unread"
:label="notificationStore.unread"
:label="
notificationStore.unread > 9 ? '9+' : notificationStore.unread
"
theme="gray"
variant="subtle"
/>
Expand Down
8 changes: 4 additions & 4 deletions desk/src/components/ticket/TicketAgentActivities.vue
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
<DotIcon v-else class="text-gray-600" />
</div>
</div>
<div class="mb-4 w-full">
<div class="mb-4 flex flex-1">
<EmailArea
v-if="activity.type === 'email'"
:activity="activity"
Expand Down Expand Up @@ -74,7 +74,7 @@
</template>

<script setup lang="ts">
import { Ref, inject, h, computed, onMounted, watch } from "vue";
import { Ref, inject, h, computed, onMounted, watch, PropType } from "vue";
import { useElementVisibility } from "@vueuse/core";
import {
DotIcon,
Expand All @@ -86,10 +86,10 @@ import {
import { EmailArea, CommentBox, HistoryBox } from "@/components";
import { useUserStore } from "@/stores/user";
import { Avatar } from "frappe-ui";

import { TicketActivity } from "@/types";
const props = defineProps({
activities: {
type: Array,
type: Array as PropType<TicketActivity[]>,
required: true,
},
title: {
Expand Down
2 changes: 1 addition & 1 deletion desk/src/components/ticket/TicketAgentSidebar.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<div class="flex w-[382px] flex-col justify-between border-l">
<div class="h-10.5 flex items-center justify-between border-b px-5 py-2.5">
<div class="h-[2.83rem] flex items-center justify-between border-b px-5">
<span
class="cursor-copy text-lg font-semibold"
@click="copyToClipboard(ticket.name, ticket.name)"
Expand Down
Loading

0 comments on commit 9ecf7c4

Please sign in to comment.