Skip to content
Open
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
175 changes: 175 additions & 0 deletions components/inbox-mail/CreateNewMailModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
import BaseModal from "@/src/components/Common/ModalComponents/Modal";
import ModalCreateFooter from "@/src/components/Common/ModalComponents/ModalCreateFooter";
import { Dialog } from "@headlessui/react";
import { useCallback, useMemo, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import { useRouter } from "next/router";
import { sendNewMail } from "./service-mail";
import useRefState from "../../hooks/useRefState";
import { InfoButton } from "../InfoButton";
import { MemoIconMail } from "../kern-icons/icons";

type CreateNewMailModalProps = {
open: boolean;
setOpen: (open: boolean) => void;
};

export default function CreateNewMailModal(props: CreateNewMailModalProps) {
const router = useRouter();
const { t } = useTranslation('projectOverview');
const projectId = router.query.projectId as string;
const chatId = router.query.chatId as string;
const { state: sendTo, setState: setSendTo, ref: sendToRef } = useRefState([]);
const { state: subject, setState: setSubject, ref: subjectRef } = useRefState('');
const { state: content, setState: setContent, ref: contentRef } = useRefState('');
const { state: includeProject, setState: setIncludeProject, ref: includeProjectRef } = useRefState(false);
const { state: includeChat, setState: setIncludeChat, ref: includeChatRef } = useRefState(false);
const { state: markAsImportant, setState: setMarkAsImportant, ref: markAsImportantRef } = useRefState(false);
const [availableEmails, setAvailableEmails] = useState<string[]>(['test@gmail.com', 'test1@gmail.com']);
const [selectedEmails, setSelectedEmails] = useState<string[]>([]);

const cancelButtonRef = useRef(null);

const initModal = useCallback(() => {
setSendTo([]);
setSubject('');
setContent('');
setIncludeProject(false);
setIncludeChat(false);
setMarkAsImportant(false);
}, []);

const onTransitionComplete = useCallback(initModal, []);

const disabledSend = useMemo(() => {
return sendTo.length === 0 || subject.trim() === '' || content.trim() === '';
}, [sendTo, subject, content]);

const handleCreateMail = useCallback(() => {
const metaData = {
includeProject: includeProjectRef.current,
includeChat: includeChatRef.current
};
sendNewMail(sendToRef.current, subjectRef.current, contentRef.current, markAsImportantRef.current, metaData, (result) => {
props.setOpen(false);
initModal();
});
}, []);

return (
<BaseModal
open={props.open}
setOpen={props.setOpen}
onTransitionComplete={onTransitionComplete}
maxWidth="2xl"
initialFocus={cancelButtonRef}
>
<div className="p-6">
<div className="sm:flex sm:items-start">
<div className="mx-auto flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full bg-green-100 sm:mx-0 sm:h-10 sm:w-10">
<MemoIconMail className="h-6 w-6 text-green-600" />
</div>
<div className="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left w-full">
<Dialog.Title as="h3" className="text-lg font-medium leading-6 text-gray-900">
{t("inboxMail.modalTitle")}
</Dialog.Title>
<div className='mt-2 flex flex-col gap-y-2'>
<div>
<label htmlFor="sendTo" className="block text-sm font-medium text-gray-700">
{t("inboxMail.sendTo")}:
</label>
<div className="mt-1">
<input
type="text"
name="sendTo"
id="sendTo"
className="shadow-sm focus:ring-purple-500 focus:border-purple-500 block w-full sm:text-sm border-gray-300 rounded-md"
value={sendTo}
onChange={(e) => setSendTo([e.target.value])}
/>
</div>
</div>
<div>
<label htmlFor="subject" className="block text-sm font-medium text-gray-700">
{t("inboxMail.subject")}:
</label>
<div className="mt-1">
<input
type="text"
name="subject"
id="subject"
className="shadow-sm focus:ring-purple-500 focus:border-purple-500 block w-full sm:text-sm border-gray-300 rounded-md"
value={subject}
onChange={(e) => setSubject(e.target.value)}
/>
</div>
</div>
<div>
<label htmlFor="content" className="block text-sm font-medium text-gray-700">
{t("inboxMail.content")}:
</label>
<div className="mt-1">
<textarea
name="content"
id="content"
className="shadow-sm focus:ring-purple-500 focus:border-purple-500 block w-full sm:text-sm border-gray-300 rounded-md"
value={content}
onChange={(e) => setContent(e.target.value)}
rows={8}
/>
</div>
</div>
<div className="flex items-center gap-x-2">
<input
type="checkbox"
name="markAsImportant"
id="markAsImportant"
checked={markAsImportant}
onChange={(e) => setMarkAsImportant(e.target.checked)}
className="shadow-sm focus:ring-purple-500 focus:border-purple-500 block w-full sm:text-sm border-gray-300 rounded-md"
/>
<label htmlFor="markAsImportant" className="block text-sm font-medium text-gray-700 cursor-pointer">
{t("inboxMail.markAsImportant")}
</label>
<InfoButton content={t("inboxMail.markAsImportantInfo")} infoButtonSize="sm" />
</div>
{projectId && <div className="flex items-center gap-x-2">
<input
type="checkbox"
name="includeProject"
id="includeProject"
checked={includeProject}
onChange={(e) => setIncludeProject(e.target.checked)}
className="shadow-sm focus:ring-purple-500 focus:border-purple-500 block w-full sm:text-sm border-gray-300 rounded-md"
/>
<label htmlFor="includeProject" className="block text-sm font-medium text-gray-700 cursor-pointer">
{t("inboxMail.includeProjectInfo")}
</label>
</div>}
{chatId && <div className="flex items-center gap-x-2">
<input
type="checkbox"
name="includeChat"
id="includeChat"
checked={includeChat}
onChange={(e) => setIncludeChat(e.target.checked)}
className="shadow-sm focus:ring-purple-500 focus:border-purple-500 block w-full sm:text-sm border-gray-300 rounded-md"
/>
<label htmlFor="includeChat" className="block text-sm font-medium text-gray-700 cursor-pointer">
{t("inboxMail.includeChatInfo")}
</label>
</div>}
</div>
</div>
</div>
<ModalCreateFooter
handleCreate={handleCreateMail}
closeDialog={() => props.setOpen(false)}
cancelButtonRef={cancelButtonRef}
createButtonName={t("inboxMail.sendButton")}
disabledButton={disabledSend}
/>
</div>
</BaseModal>
)
}
36 changes: 36 additions & 0 deletions components/inbox-mail/InboxMail.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { MemoIconMail } from "@/submodules/react-components/components/kern-icons/icons";
import { useRouter } from "next/router";
import { useCallback, useMemo } from "react";
import tinycolor from 'tinycolor2'

type InboxMailProps = {
project: { customerColorPrimary: string; id: string; };
forChatArea?: boolean;
chatId?: string;
}

export default function InboxMail(props: InboxMailProps) {
const router = useRouter();
const navigateToMailPage = useCallback(() => {
const chatIdParam = props.chatId ? `?chatId=${props.chatId}` : '';
const projectIdParam = props.project ? props.chatId ? `&projectId=${props.project.id}` : `?projectId=${props.project.id}` : '';
router.push(`/inbox-mail${chatIdParam}${projectIdParam}`);
}, [props.chatId, props.project]);

const isLightDesign = useMemo(() => tinycolor(props.project?.customerColorPrimary).isLight(), [props.project?.customerColorPrimary]);

const buttonClasses = useMemo(() => {
if (props.forChatArea) {
const classes = "items-center justify-center w-8 h-8 border group flex -x-3 rounded-md p-1 text-sm leading-6 font-semibold"
if (isLightDesign) return 'bg-gray-100 text-gray-700 border-gray-300 ' + classes;
else return 'bg-zinc-900 text-zinc-100 border-zinc-700 ' + classes;
}
return "text-gray-400 hover:text-green-600 hover:bg-zinc-800 border-gray-700 items-center justify-center w-10 h-10 border group flex -x-3 rounded-md p-2 text-sm leading-6 font-semibold"
}, [props.forChatArea, isLightDesign]);

return <div className="relative">
<button className={buttonClasses} onClick={navigateToMailPage}>
<MemoIconMail />
</button>
</div>
}
65 changes: 65 additions & 0 deletions components/inbox-mail/InboxMailView.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@

import { useEffect, useState } from "react";
import CreateNewMailModal from "./CreateNewMailModal";
import { InboxMail } from "./types-mail";
import { getInboxMessages } from "./service-mail";
import KernButton from "../kern-button/KernButton";
import { MemoIconPlus } from "../kern-icons/icons";

export default function InboxMailView() {
const [inboxMessages, setInboxMessages] = useState<InboxMail[]>([]);
const [openCreateMail, setOpenCreateMail] = useState(false);
const [selectedMail, setSelectedMail] = useState<InboxMail | null>(null);

useEffect(() => {
getInboxMessages((res) => setInboxMessages(res));
}, []);

return (
<div className='pt-16'>
<div className="flex items-center w-full justify-between mb-4 px-4 py-2 border border-gray-200">
<div className="flex justify-between items-center">
<div>
<h2 className="font-semibold">
Inbox Mail
</h2>
<p>
Manage your inbox messages.
</p>
</div>
</div>
<KernButton
text="Send new mail"
icon={MemoIconPlus}
onClick={() => setOpenCreateMail(true)} />
</div>

{inboxMessages?.length === 0 ? (
<div className="flex flex-col items-center justify-center mt-20">
<div className="text-2xl font-semibold mb-4">No Inbox Messages</div>
<div className="text-gray-500 mb-6">You have no messages in your inbox</div>
</div>
) : <div className="grid grid-cols-2 gap-x-4">
<div>
{inboxMessages.map((mail) => (
<div key={mail.id} className="border border-gray-300 rounded-lg p-2 m-4">
<div className="font-bold text-md mb-2">Subject: {mail.subject}</div>
<div className="text-sm text-gray-600 mb-4">From: {mail.sendFrom}</div>
<div className="text-gray-800">{mail.content}</div>
</div>
))}
</div>
<div>
{selectedMail ? (
<>DISPLAY SEQUENCE OF MESSAGES</>
) : <div className="flex flex-col items-center justify-center mt-20">
<div className="text-gray-500 mb-6">Select mail to see the details</div>
</div>}
</div>
</div>}

<CreateNewMailModal open={openCreateMail} setOpen={setOpenCreateMail} />
</div>

)
}
18 changes: 18 additions & 0 deletions components/inbox-mail/service-mail.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { FetchType, jsonFetchWrapper } from "@/submodules/javascript-functions/basic-fetch";

export const BACKEND_BASE_URI = '/cognition-gateway';
const url = `${BACKEND_BASE_URI}/api/v1/inbox-mail`;

export function sendNewMail(sendTo: string[], subject: string, content: string, markAsImportant: boolean, metaData: any, onResult: (result: any) => void) {
const body = JSON.stringify({ sendTo, subject, content, markAsImportant, metaData });
jsonFetchWrapper(url, FetchType.POST, onResult, body);
}

export function getInboxMessages(onResult: (result: any) => void) {
jsonFetchWrapper(url, FetchType.GET, onResult);
}

export function getAccessibleSendToEmails(onResult: (result: any) => void) {
const fetchUrl = `${url}/accessible-emails`;
jsonFetchWrapper(fetchUrl, FetchType.GET, onResult);
}
15 changes: 15 additions & 0 deletions components/inbox-mail/types-mail.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export type InboxMail = {
id: string;
sendFrom: string;
sendTo: string[];
subject: string;
content: string;
beingWorkedOn: boolean;
childId: string;
parentId: string;
createdAt: string;
isSeen: boolean;
metaData: any;
organizationId: string;
markAsImportant: boolean;
}
Loading