Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
178 changes: 120 additions & 58 deletions components/inbox-mail/InboxMailAdminPanel.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import React, { useCallback } from "react";
import { InboxMailThread, InboxMailThreadSupportProgressState, User } from "./types-mail";
import { IconExternalLink, IconProgressCheck } from "@tabler/icons-react";
import React, { useCallback, useEffect, useState } from "react";
import { InboxMailThread, InboxMailThreadSupportProgressState, JumpDestination, User } from "./types-mail";
import { IconExternalLink, IconProgressCheck, IconAlertTriangle } from "@tabler/icons-react";
import KernDropdown from "../KernDropdown";
import { addUserToOrganization, removeUserFromOrganization, updateInboxMailThreadsUnreadByContent, updateInboxMailThreadsUnreadByProject } from "./service-mail";
import { addUserToOrganization, removeUserFromOrganization, updateInboxMailThreadsUnreadByContent, updateInboxMailThreadsUnreadByProject, updateInboxMailThreadUnreadLast, deleteInboxMailThreadsSimilar } from "./service-mail";
import { Tooltip } from "@nextui-org/react";
import KernButton from "../kern-button/KernButton";


Expand All @@ -17,36 +18,50 @@ interface InboxMailAdminPanelProps {
handleInboxMailProgressChange: (value: InboxMailThreadSupportProgressState) => void;
currentUser: User;
refetchInboxMailOverview: () => void;
translator: (key: string) => string;
}

function InboxMailAdminPanel(props: InboxMailAdminPanelProps) {
// No translations needed, admin only
const assignAndJump = useCallback((toConversation: boolean) => {
const t = props.translator;
const [canMarkLastUnread, setCanMarkLastUnread] = useState(true);

useEffect(() => {
if (props.selectedThread.metaData?.unreadMailCountAdmin > 0) {
setCanMarkLastUnread(false);
} else {
setCanMarkLastUnread(true);
}
}, [props.selectedThread.id, props.selectedThread.metaData?.unreadMailCountAdmin]);

const assignAndJump = useCallback((destination: JumpDestination) => {
if (!props.currentUser) return;
const currentOrganizationId = props.currentUser?.organizationId;
if (!currentOrganizationId) {
addUserToOrganization(props.currentUser.mail, props.selectedThread.organizationName, (res) => {
jumptoConversationOrProject(toConversation);

jumpTo(destination);
});
} else if (currentOrganizationId === props.selectedThread.organizationId) {
jumptoConversationOrProject(toConversation);

jumpTo(destination);
} else {
removeUserFromOrganization(props.currentUser.mail, (res) => {
addUserToOrganization(props.currentUser.mail, props.selectedThread.organizationName, (res) => {
jumptoConversationOrProject(toConversation);
jumpTo(destination);
});
});
}
}, [props.currentUser, props.selectedThread]);

const jumptoConversationOrProject = useCallback((toConversation: boolean) => {
if (toConversation) {
window.open(`/cognition/projects/${props.selectedThread.metaData?.projectId}/ui/${props.selectedThread.metaData?.conversationId}`, '_blank');
}
else {
window.open(`/cognition/projects/${props.selectedThread.metaData.projectId}/pipeline`, '_blank');
const jumpTo = useCallback((destination: JumpDestination) => {
switch (destination) {
case JumpDestination.CONVERSATION:
window.open(`/cognition/projects/${props.selectedThread.metaData?.projectId}/ui/${props.selectedThread.metaData?.conversationId}`, '_blank');
break;
case JumpDestination.PROJECT:
window.open(`/cognition/projects/${props.selectedThread.metaData?.projectId}/pipeline`, '_blank');
break;
case JumpDestination.ORGANIZATION:
window.open('/cognition', '_blank');
break;
}
}, [props.selectedThread.metaData]);

Expand All @@ -61,7 +76,18 @@ function InboxMailAdminPanel(props: InboxMailAdminPanelProps) {
updateInboxMailThreadsUnreadByProject(props.selectedThread.id, (res) => {
props.refetchInboxMailOverview();
});
}, [props.selectedThread?.id, props.refetchInboxMailOverview]);

const handleMarkLastUnread = useCallback(() => {
setCanMarkLastUnread(false);
updateInboxMailThreadUnreadLast(props.selectedThread.id, (res) => {
props.refetchInboxMailOverview();
});
}, [props.selectedThread?.id, props.refetchInboxMailOverview]);

const handleDeleteSimilar = useCallback(() => {
if (!confirm("Are you sure you want to delete all similar inbox mails? This action cannot be undone.")) return;
deleteInboxMailThreadsSimilar(props.selectedThread.id, (res) => props.refetchInboxMailOverview());
}, [props.selectedThread?.id, props.refetchInboxMailOverview]);

return (
Expand Down Expand Up @@ -89,20 +115,61 @@ function InboxMailAdminPanel(props: InboxMailAdminPanelProps) {
{props.selectedThread.metaData.supportOwnerName?.last}
</div>
)}
{props.selectedThread?.metaData?.autoGenerated &&
<div className="flex items-center gap-3 ml-auto my-2 px-3 py-1 ">
<KernButton
className="ml-auto"
text="Read all by error"
onClick={handleSameContentRead}
/>
<KernButton
text="Read all by project"
onClick={handleSameProjectRead}
/>
</div>
}
<div className="flex items-center gap-3 ml-auto my-2 px-3 py-1">
{props.selectedThread?.metaData?.autoGenerated && (
<>
<KernButton
text={t("inboxMail.readAllByError")}
onClick={handleSameContentRead}
/>
<KernButton
text={t("inboxMail.readAllByProject")}
onClick={handleSameProjectRead}
/>
</>
)}
<KernButton
text={t("inboxMail.markLastUnread")}
onClick={handleMarkLastUnread}
disabled={!canMarkLastUnread}
/>
{props.selectedThread?.metaData?.autoGenerated && (
<Tooltip
content={<div className="w-52">{t("inboxMail.deleteAllByContentTooltip")}</div>}
placement="top"
color="invert"
>
<KernButton
text={t("inboxMail.deleteAllByContent")}
onClick={handleDeleteSimilar}
icon={() => <IconAlertTriangle className="w-4 h-4 text-red-500" />}
/>
</Tooltip>
)}
</div>
</div>
{props.selectedThread.organizationId && (
<div className="flex items-center gap-3 ml-2 my-2 px-3 py-1 rounded-xl bg-indigo-400/60 text-white w-fit">
<div className="flex items-center gap-1.5 text-xs">
<span className="font-semibold">Organization</span>
</div>

<div className="flex items-center gap-1.5 text-xs bg-indigo-400 px-2 py-0.5 rounded-md">
<span>ID:</span>
<span>{props.selectedThread.organizationId}</span>
</div>
<div className="flex items-center gap-1.5 text-xs bg-indigo-400 px-2 py-0.5 rounded-md">
<span>{props.selectedThread.organizationName}</span>
</div>
<button
className="flex items-center gap-1.5 text-xs bg-indigo-400 px-2 py-0.5 rounded-md"
onClick={() => assignAndJump(JumpDestination.ORGANIZATION)}
>
<IconExternalLink className="w-4 h-4" />
</button>
</div>
)}

{props.selectedThread.metaData?.projectId && (
<div className="flex items-center gap-3 ml-2 my-2 px-3 py-1 rounded-xl bg-slate-400/60 text-white w-fit">
<div className="flex items-center gap-1.5 text-xs">
Expand All @@ -118,39 +185,34 @@ function InboxMailAdminPanel(props: InboxMailAdminPanelProps) {
</div>
<button
className="flex items-center gap-1.5 text-xs bg-slate-400 px-2 py-0.5 rounded-md"
onClick={() =>
assignAndJump(false)
}
onClick={() => assignAndJump(JumpDestination.PROJECT)}
>
<IconExternalLink className="w-4 h-4" />
</button>
</div>
)
}

{
props.selectedThread.metaData?.conversationId && (
<div className="flex items-center gap-3 ml-2 my-2 px-3 py-1 rounded-xl bg-gray-400/60 text-white w-fit">
<div className="flex items-center gap-1.5 text-xs">
<span className="font-semibold">Conversation</span>
</div>

<div className="flex items-center gap-1.5 text-xs bg-gray-400 px-2 py-0.5 rounded-md">
<span>ID:</span>
<span>{props.selectedThread.metaData.conversationId}</span>
</div>
<div className="flex items-center gap-1.5 text-xs bg-gray-400 px-2 py-0.5 rounded-md">
<span>{props.selectedThread.metaData.conversationHeader || "N/A"}</span>
</div>
<button
className="flex items-center gap-1.5 text-xs bg-gray-400 px-2 py-0.5 rounded-md"
onClick={() => assignAndJump(true)}
>
<IconExternalLink className="w-4 h-4" />
</button>
)}

{props.selectedThread.metaData?.conversationId && (
<div className="flex items-center gap-3 ml-2 my-2 px-3 py-1 rounded-xl bg-gray-400/60 text-white w-fit">
<div className="flex items-center gap-1.5 text-xs">
<span className="font-semibold">Conversation</span>
</div>

<div className="flex items-center gap-1.5 text-xs bg-gray-400 px-2 py-0.5 rounded-md">
<span>ID:</span>
<span>{props.selectedThread.metaData.conversationId}</span>
</div>
<div className="flex items-center gap-1.5 text-xs bg-gray-400 px-2 py-0.5 rounded-md">
<span>{props.selectedThread.metaData.conversationHeader || "N/A"}</span>
</div>
)
}
<button
className="flex items-center gap-1.5 text-xs bg-gray-400 px-2 py-0.5 rounded-md"
onClick={() => assignAndJump(JumpDestination.CONVERSATION)}
>
<IconExternalLink className="w-4 h-4" />
</button>
</div>
)}
</div >
);
};
Expand Down
11 changes: 9 additions & 2 deletions components/inbox-mail/InboxMailThreadOverview.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useMemo } from "react";
import { InboxMailThread, InboxMailThreadSupportProgressState } from "./types-mail";
import { Tooltip } from "@nextui-org/react";
import { MemoIconAlertTriangle, MemoIconCircleCheck, MemoIconHelpCircle, MemoIconProgressCheck, MemoIconUser } from "../kern-icons/icons";
import { MemoIconAlertTriangle, MemoIconCircleCheck, MemoIconHelpCircle, MemoIconProgressCheck, MemoIconUser, MemoIconUsers } from "../kern-icons/icons";
import { formatDisplayTimestamp } from "@/submodules/javascript-functions/date-parser";

interface InboxMailThreadOverviewProps {
Expand Down Expand Up @@ -61,10 +61,17 @@ export default function InboxMailThreadOverview(props: InboxMailThreadOverviewPr

<div className="grow min-w-0">
<div className="flex items-start justify-between gap-x-2 flex-nowrap">
<div className="flex items-center">
<div className="flex items-center gap-x-2">
<div className="text-gray-800 font-medium truncate mt-0.5">
{displayName ?? `<${t("inboxMail.unknownUser")}>`}
</div>
{props.isAdmin && (
<Tooltip content={`Org: ${props.thread.organizationName}`} placement="top" color="invert">
<div className="flex items-center justify-center text-gray-500 cursor-help">
<MemoIconUsers className="h-4 w-4" />
</div>
</Tooltip>
)}
{unreadMailCount > 0 && (
<span className="ml-2 inline-flex items-center justify-center bg-slate-400 text-white text-[0.625rem] font-semibold rounded-full h-4 min-w-4 px-1.5 whitespace-nowrap">
{unreadMailCount} {t("inboxMail.newBadge")}
Expand Down
Loading