Refactor alertDropDown components

Adjust singleAlertComponent's formatting for better readability and add a custom hook to handle click outside functionality in alertDropdown component.
This commit is contained in:
Gabriel Almeida 2023-04-27 17:01:51 -03:00
commit 917cc51148
6 changed files with 509 additions and 451 deletions

View file

@ -1,15 +1,23 @@
import { XCircleIcon, XMarkIcon, InformationCircleIcon, CheckCircleIcon } from "@heroicons/react/24/outline"; import {
XCircleIcon,
XMarkIcon,
InformationCircleIcon,
CheckCircleIcon,
} from "@heroicons/react/24/outline";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import { Transition } from "@headlessui/react"; import { Transition } from "@headlessui/react";
import { useState } from "react"; import { useState } from "react";
import { SingleAlertComponentType } from "../../../../types/alerts"; import { SingleAlertComponentType } from "../../../../types/alerts";
export default function SingleAlert({ dropItem, removeAlert}:SingleAlertComponentType) { export default function SingleAlert({
const [show, setShow] = useState(true); dropItem,
const type = dropItem.type; removeAlert,
}: SingleAlertComponentType) {
const [show, setShow] = useState(true);
const type = dropItem.type;
return ( return (
<Transition <Transition
className="relative" className="relative"
show={show} show={show}
appear={true} appear={true}
@ -20,115 +28,127 @@ export default function SingleAlert({ dropItem, removeAlert}:SingleAlertComponen
leaveFrom={"transform translate-x-0"} leaveFrom={"transform translate-x-0"}
leaveTo={"transform translate-x-[-100%]"} leaveTo={"transform translate-x-[-100%]"}
> >
{type === "error"? {type === "error" ? (
<div className="flex bg-red-50 rounded-md p-3 mb-2 mx-2" key={dropItem.id}> <div
<div className="flex-shrink-0"> className="flex bg-red-50 rounded-md p-3 mb-2 mx-2"
<XCircleIcon key={dropItem.id}
className="h-5 w-5 text-red-400" >
aria-hidden="true" <div className="flex-shrink-0">
/> <XCircleIcon className="h-5 w-5 text-red-400" aria-hidden="true" />
</div>
<div className="ml-3">
<h3 className="text-sm font-medium text-red-800">
{dropItem.title}
</h3>
{dropItem.list ? (
<div className="mt-2 text-sm text-red-700">
<ul className="list-disc space-y-1 pl-5">
{dropItem.list.map((item, idx) => (
<li key={idx}>{item}</li>
))}
</ul>
</div>
) : (
<></>
)}
</div>
<div className="ml-auto pl-3">
<div className="-mx-1.5 -my-1.5">
<button
type="button"
onClick={() => {
setShow(false);
setTimeout(() => {
removeAlert(dropItem.id);
}, 500);
}}
className="inline-flex rounded-md bg-red-50 p-1.5 text-red-500"
>
<span className="sr-only">Dismiss</span>
<XMarkIcon className="h-5 w-5" aria-hidden="true" />
</button>
</div> </div>
<div className="ml-3"> </div>
<h3 className="text-sm font-medium text-red-800"> </div>
{dropItem.title} ) : type === "notice" ? (
</h3> <div
{dropItem.list ? ( className="flex rounded-md bg-blue-50 p-3 mb-2 mx-2"
<div className="mt-2 text-sm text-red-700"> key={dropItem.id}
<ul className="list-disc space-y-1 pl-5"> >
{dropItem.list.map((item, idx) => ( <div className="flex-shrink-0">
<li key={idx}>{item}</li> <InformationCircleIcon
))} className="h-5 w-5 text-blue-400"
</ul> aria-hidden="true"
</div> />
</div>
<div className="ml-3 flex-1 md:flex md:justify-between">
<p className="text-sm text-blue-700">{dropItem.title}</p>
<p className="mt-3 text-sm md:mt-0 md:ml-6">
{dropItem.link ? (
<Link
to={dropItem.link}
className="whitespace-nowrap font-medium text-blue-700 hover:text-blue-600"
>
Details
</Link>
) : ( ) : (
<></> <></>
)} )}
</div> </p>
<div className="ml-auto pl-3"> </div>
<div className="-mx-1.5 -my-1.5"> <div className="ml-auto pl-3">
<button <div className="-mx-1.5 -my-1.5">
type="button" <button
onClick={() => { type="button"
setShow(false); setTimeout(() => {removeAlert(dropItem.id);}, 500); onClick={() => {
}} setShow(false);
className="inline-flex rounded-md bg-red-50 p-1.5 text-red-500" setTimeout(() => {
> removeAlert(dropItem.id);
<span className="sr-only">Dismiss</span> }, 500);
<XMarkIcon className="h-5 w-5" aria-hidden="true" /> }}
</button> className="inline-flex rounded-md bg-blue-50 p-1.5 text-blue-500"
</div> >
<span className="sr-only">Dismiss</span>
<XMarkIcon className="h-5 w-5" aria-hidden="true" />
</button>
</div> </div>
</div> </div>
:(type === "notice" ? </div>
<div className="flex rounded-md bg-blue-50 p-3 mb-2 mx-2" key={dropItem.id}> ) : (
<div className="flex-shrink-0"> <div
<InformationCircleIcon className="flex bg-green-50 p-3 mb-2 mx-2 rounded-md"
className="h-5 w-5 text-blue-400" key={dropItem.id}
aria-hidden="true" >
/> <div className="flex-shrink-0">
</div> <CheckCircleIcon
<div className="ml-3 flex-1 md:flex md:justify-between"> className="h-5 w-5 text-green-400"
<p className="text-sm text-blue-700">{dropItem.title}</p> aria-hidden="true"
<p className="mt-3 text-sm md:mt-0 md:ml-6"> />
{dropItem.link ? ( </div>
<Link <div className="ml-3">
to={dropItem.link} <p className="text-sm font-medium text-green-800">
className="whitespace-nowrap font-medium text-blue-700 hover:text-blue-600" {dropItem.title}
> </p>
Details </div>
</Link> <div className="ml-auto pl-3">
) : ( <div className="-mx-1.5 -my-1.5">
<></> <button
)} type="button"
</p> onClick={() => {
</div> setShow(false);
<div className="ml-auto pl-3"> setTimeout(() => {
<div className="-mx-1.5 -my-1.5"> removeAlert(dropItem.id);
<button }, 500);
type="button" }}
onClick={() => { className="inline-flex rounded-md bg-green-50 p-1.5 text-green-500"
setShow(false); setTimeout(() => {removeAlert(dropItem.id);}, 500); >
}} <span className="sr-only">Dismiss</span>
className="inline-flex rounded-md bg-blue-50 p-1.5 text-blue-500" <XMarkIcon className="h-5 w-5" aria-hidden="true" />
> </button>
<span className="sr-only">Dismiss</span>
<XMarkIcon className="h-5 w-5" aria-hidden="true" />
</button>
</div>
</div> </div>
</div> </div>
: </div>
<div className="flex bg-green-50 p-3 mb-2 mx-2 rounded-md" key={dropItem.id}> )}
<div className="flex-shrink-0">
<CheckCircleIcon
className="h-5 w-5 text-green-400"
aria-hidden="true"
/>
</div>
<div className="ml-3">
<p className="text-sm font-medium text-green-800">
{dropItem.title}
</p>
</div>
<div className="ml-auto pl-3">
<div className="-mx-1.5 -my-1.5">
<button
type="button"
onClick={() => {
setShow(false); setTimeout(() => {removeAlert(dropItem.id);}, 500);
}}
className="inline-flex rounded-md bg-green-50 p-1.5 text-green-500"
>
<span className="sr-only">Dismiss</span>
<XMarkIcon className="h-5 w-5" aria-hidden="true" />
</button>
</div>
</div>
</div>
)
}
</Transition> </Transition>
) );
}
}

View file

@ -5,73 +5,62 @@ import { TrashIcon } from "@heroicons/react/24/outline";
import SingleAlert from "./components/singleAlertComponent"; import SingleAlert from "./components/singleAlertComponent";
import { AlertDropdownType } from "../../types/alerts"; import { AlertDropdownType } from "../../types/alerts";
import { PopUpContext } from "../../contexts/popUpContext"; import { PopUpContext } from "../../contexts/popUpContext";
import { useOnClickOutside } from "../hooks/useOnClickOutside";
export default function AlertDropdown({}: AlertDropdownType) { export default function AlertDropdown({}: AlertDropdownType) {
const { closePopUp } = useContext(PopUpContext); const { closePopUp } = useContext(PopUpContext);
const componentRef = useRef<HTMLDivElement>(null); const componentRef = useRef<HTMLDivElement>(null);
useEffect(() => { // Use the custom hook
function handleClickOutside(event: MouseEvent) { useOnClickOutside(componentRef, () => {
if ( closePopUp();
componentRef.current && });
!componentRef.current.contains(event.target as Node)
) {
closePopUp();
}
}
// Bind the event listener const {
document.addEventListener("mousedown", handleClickOutside); notificationList,
clearNotificationList,
removeFromNotificationList,
} = useContext(alertContext);
// Cleanup the event listener when the component is unmounted return (
return () => { <div
document.removeEventListener("mousedown", handleClickOutside); ref={componentRef}
}; className="z-10 py-3 pb-4 rounded-md bg-white dark:bg-gray-800 ring-1 ring-black ring-opacity-5 shadow-lg focus:outline-none overflow-hidden w-[16rem] h-[28rem] flex flex-col"
}, [componentRef]); >
<div className="flex pl-3 flex-row justify-between text-md font-medium text-gray-800 dark:text-gray-200">
const { Notifications
notificationList, <div className="flex gap-2 pr-3 ">
clearNotificationList, <button
removeFromNotificationList, className="text-gray-800 hover:text-red-500 dark:text-gray-200 dark:hover:text-red-500"
} = useContext(alertContext); onClick={() => {
closePopUp();
return ( setTimeout(clearNotificationList, 100);
<div }}
ref={componentRef} >
className="z-10 py-3 pb-4 rounded-md bg-white ring-1 ring-black ring-opacity-5 shadow-lg focus:outline-none overflow-hidden w-[16rem] h-[28rem] flex flex-col" <TrashIcon className="w-[1.1rem] h-[1.1rem]" />
> </button>
<div className="flex pl-3 flex-row justify-between text-md font-medium text-gray-800"> <button
Notifications className="text-gray-800 hover:text-red-500 dark:text-gray-200 dark:hover:text-red-500"
<div className="flex gap-2 pr-3 "> onClick={closePopUp}
<button >
className="hover:text-red-500" <XMarkIcon className="h-5 w-5" />
onClick={() => { </button>
closePopUp(); </div>
setTimeout(clearNotificationList, 100); </div>
}} <div className="mt-2 flex flex-col overflow-y-scroll w-full h-full scrollbar-hide text-gray-900 dark:text-gray-300">
> {notificationList.length !== 0 ? (
<TrashIcon className="w-[1.1rem] h-[1.1rem]" /> notificationList.map((alertItem, index) => (
</button> <SingleAlert
<button className="hover:text-red-500" onClick={closePopUp}> key={alertItem.id}
<XMarkIcon className="h-5 w-5" /> dropItem={alertItem}
</button> removeAlert={removeFromNotificationList}
</div> />
</div> ))
<div className="mt-2 flex flex-col overflow-y-scroll w-full h-full scrollbar-hide"> ) : (
{notificationList.length !== 0 ? ( <div className="h-full w-full pb-16 text-gray-500 dark:text-gray-500 flex justify-center items-center">
notificationList.map((alertItem, index) => ( No new notifications
<SingleAlert </div>
key={alertItem.id} )}
dropItem={alertItem} </div>
removeAlert={removeFromNotificationList} </div>
/> );
))
) : (
<div className="h-full w-full pb-16 text-gray-500 flex justify-center items-center">
No new notifications
</div>
)}
</div>
</div>
);
} }

View file

@ -0,0 +1,33 @@
import { useEffect } from "react";
export function useOnClickOutside(ref, handler) {
useEffect(() => {
const listener = (event) => {
// Do nothing if clicking ref's element or its children
if (!ref.current || ref.current.contains(event.target)) {
return;
}
handler(event);
};
// Attach the listener to the document
document.addEventListener("mousedown", listener, { passive: true });
// Attach the listener to the react-flow instance
const reactFlowContainer = document.querySelector(".react-flow");
if (reactFlowContainer) {
reactFlowContainer.addEventListener("mousedown", listener, {
passive: true,
});
}
// Clean up the listener when the component is unmounted
return () => {
document.removeEventListener("mousedown", listener);
if (reactFlowContainer) {
reactFlowContainer.removeEventListener("mousedown", listener);
}
};
}, [ref, handler]); // Rerun only if ref or handler changes
}

View file

@ -1,9 +1,9 @@
import { Dialog, Transition } from "@headlessui/react"; import { Dialog, Transition } from "@headlessui/react";
import { import {
XMarkIcon, XMarkIcon,
ArrowDownTrayIcon, ArrowDownTrayIcon,
DocumentDuplicateIcon, DocumentDuplicateIcon,
ComputerDesktopIcon, ComputerDesktopIcon,
} from "@heroicons/react/24/outline"; } from "@heroicons/react/24/outline";
import { Fragment, useContext, useRef, useState } from "react"; import { Fragment, useContext, useRef, useState } from "react";
import { alertContext } from "../../contexts/alertContext"; import { alertContext } from "../../contexts/alertContext";
@ -12,165 +12,169 @@ import { TabsContext } from "../../contexts/tabsContext";
import { removeApiKeys } from "../../utils"; import { removeApiKeys } from "../../utils";
export default function ExportModal() { export default function ExportModal() {
const [open, setOpen] = useState(true); const [open, setOpen] = useState(true);
const { closePopUp } = useContext(PopUpContext); const { closePopUp } = useContext(PopUpContext);
const ref = useRef(); const ref = useRef();
const {setErrorData}= useContext(alertContext) const { setErrorData } = useContext(alertContext);
const { flows, tabIndex, updateFlow, downloadFlow } = useContext(TabsContext); const { flows, tabIndex, updateFlow, downloadFlow } = useContext(TabsContext);
function setModalOpen(x: boolean) { function setModalOpen(x: boolean) {
setOpen(x); setOpen(x);
if (x === false) { if (x === false) {
setTimeout(() => { setTimeout(() => {
closePopUp(); closePopUp();
}, 300); }, 300);
} }
} }
const [checked,setChecked] = useState(true) const [checked, setChecked] = useState(true);
const [name,setName] = useState(flows[tabIndex].name) const [name, setName] = useState(flows[tabIndex].name);
return ( return (
<Transition.Root show={open} appear={true} as={Fragment}> <Transition.Root show={open} appear={true} as={Fragment}>
<Dialog <Dialog
as="div" as="div"
className="relative z-10" className="relative z-10"
onClose={setModalOpen} onClose={setModalOpen}
initialFocus={ref} initialFocus={ref}
> >
<Transition.Child <Transition.Child
as={Fragment} as={Fragment}
enter="ease-out duration-300" enter="ease-out duration-300"
enterFrom="opacity-0" enterFrom="opacity-0"
enterTo="opacity-100" enterTo="opacity-100"
leave="ease-in duration-200" leave="ease-in duration-200"
leaveFrom="opacity-100" leaveFrom="opacity-100"
leaveTo="opacity-0" leaveTo="opacity-0"
> >
<div className="fixed inset-0 bg-gray-500 dark:bg-gray-600 dark:bg-opacity-75 bg-opacity-75 transition-opacity" /> <div className="fixed inset-0 bg-gray-500 dark:bg-gray-600 dark:bg-opacity-75 bg-opacity-75 transition-opacity" />
</Transition.Child> </Transition.Child>
<div className="fixed inset-0 z-10 overflow-y-auto"> <div className="fixed inset-0 z-10 overflow-y-auto">
<div className="flex h-full items-end justify-center p-4 text-center sm:items-center sm:p-0"> <div className="flex h-full items-end justify-center p-4 text-center sm:items-center sm:p-0">
<Transition.Child <Transition.Child
as={Fragment} as={Fragment}
enter="ease-out duration-300" enter="ease-out duration-300"
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enterTo="opacity-100 translate-y-0 sm:scale-100" enterTo="opacity-100 translate-y-0 sm:scale-100"
leave="ease-in duration-200" leave="ease-in duration-200"
leaveFrom="opacity-100 translate-y-0 sm:scale-100" leaveFrom="opacity-100 translate-y-0 sm:scale-100"
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
> >
<Dialog.Panel className="relative flex flex-col justify-between transform h-[600px] overflow-hidden rounded-lg bg-white dark:bg-gray-800 text-left shadow-xl transition-all sm:my-8 w-[700px]"> <Dialog.Panel className="relative flex flex-col justify-between transform h-[600px] overflow-hidden rounded-lg bg-white dark:bg-gray-800 text-left shadow-xl transition-all sm:my-8 w-[700px]">
<div className=" z-50 absolute top-0 right-0 hidden pt-4 pr-4 sm:block"> <div className=" z-50 absolute top-0 right-0 hidden pt-4 pr-4 sm:block">
<button <button
type="button" type="button"
className="rounded-md text-gray-400 hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2" className="rounded-md text-gray-400 hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
onClick={() => { onClick={() => {
setModalOpen(false); setModalOpen(false);
}} }}
> >
<span className="sr-only">Close</span> <span className="sr-only">Close</span>
<XMarkIcon className="h-6 w-6" aria-hidden="true" /> <XMarkIcon className="h-6 w-6" aria-hidden="true" />
</button> </button>
</div> </div>
<div className="h-full w-full flex flex-col justify-center items-center"> <div className="h-full w-full flex flex-col justify-center items-center">
<div className="flex w-full pb-4 z-10 justify-center shadow-sm"> <div className="flex w-full pb-4 z-10 justify-center shadow-sm">
<div className="mx-auto mt-4 flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full bg-blue-100 dark:bg-gray-900 sm:mx-0 sm:h-10 sm:w-10"> <div className="mx-auto mt-4 flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full bg-blue-100 dark:bg-gray-900 sm:mx-0 sm:h-10 sm:w-10">
<ArrowDownTrayIcon <ArrowDownTrayIcon
className="h-6 w-6 text-blue-600" className="h-6 w-6 text-blue-600"
aria-hidden="true" aria-hidden="true"
/> />
</div> </div>
<div className="mt-4 text-center sm:ml-4 sm:text-left"> <div className="mt-4 text-center sm:ml-4 sm:text-left">
<Dialog.Title <Dialog.Title
as="h3" as="h3"
className="text-lg font-medium dark:text-white leading-10 text-gray-900" className="text-lg font-medium dark:text-white leading-10 text-gray-900"
> >
Export as Export as
</Dialog.Title> </Dialog.Title>
</div> </div>
</div> </div>
<div className="pt-16 flex flex-col items-start justify-start h-full w-full bg-gray-200 dark:bg-gray-900 p-4 gap-16"> <div className="pt-16 flex flex-col items-start justify-start h-full w-full bg-gray-200 dark:bg-gray-900 p-4 gap-16">
<div className="w-full"> <div className="w-full">
<label <label
htmlFor="name" htmlFor="name"
className="block mb-2 font-medium text-gray-700 dark:text-white" className="block mb-2 font-medium text-gray-700 dark:text-white"
> >
Name Name
</label> </label>
<input <input
onChange={(event) => { onChange={(event) => {
if(event.target.value!=""){ if (event.target.value != "") {
let newFlow = flows[tabIndex]; let newFlow = flows[tabIndex];
newFlow.name = event.target.value; newFlow.name = event.target.value;
setName(event.target.value) setName(event.target.value);
updateFlow(newFlow); updateFlow(newFlow);
} } else {
else{ setName(event.target.value);
setName(event.target.value) }
} }}
}} type="text"
type="text" name="name"
name="name" value={name ?? null}
value={name ?? null} placeholder="File name"
placeholder="File name" id="name"
id="name" className="focus:border focus:border-blue block w-full px-3 py-2 border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-800 dark:border-gray-600 dark:focus:border-blue-500 dark:focus:ring-blue-500 text-gray-900 dark:text-gray-100"
className="focus:border focus:border-blue block w-full px-3 py-2 border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-800 dark:border-gray-600 dark:focus:border-blue-500 dark:focus:ring-blue-500" />
/> </div>
</div> <div className="w-full">
<div className="w-full"> <label
<label htmlFor="description"
htmlFor="description" className="block mb-2 font-medium text-gray-700 dark:text-white"
className="block mb-2 font-medium text-gray-700 dark:text-white" >
> Description{" "}
Description <span className="text-gray-400 text-sm"> (optional)</span> <span className="text-gray-400 text-sm">
</label> {" "}
<textarea (optional)
name="description" </span>
id="description" </label>
onChange={(event) => { <textarea
let newFlow = flows[tabIndex]; name="description"
newFlow.description = event.target.value; id="description"
updateFlow(newFlow); onChange={(event) => {
}} let newFlow = flows[tabIndex];
value={flows[tabIndex].description ?? null} newFlow.description = event.target.value;
placeholder="Flow description" updateFlow(newFlow);
rows={3} }}
className=" focus:border focus:border-blue block w-full px-3 py-2 border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-800 dark:border-gray-600 dark:focus:border-blue-500 dark:focus:ring-blue-500" value={flows[tabIndex].description ?? null}
></textarea> placeholder="Flow description"
</div> rows={3}
<div> className=" focus:border focus:border-blue block w-full px-3 py-2 border-gray-300 text-gray-900 dark:text-gray-100 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-800 dark:border-gray-600 dark:focus:border-blue-500 dark:focus:ring-blue-500"
<label htmlFor="checkbox" className="flex items-center"> ></textarea>
<input </div>
onChange={(event) => {
setChecked(event.target.checked) <div>
}} <label htmlFor="checkbox" className="flex items-center">
checked={checked} <input
id="checkbox" onChange={(event) => {
type="checkbox" setChecked(event.target.checked);
className="h-4 w-4 text-blue-600 border-gray-300 rounded dark:bg-gray-800 dark:border-gray-600 dark:focus:border-blue-500 dark:focus:ring-blue-500" }}
/> checked={checked}
<span className="ml-2 font-medium text-gray-700 dark:text-white"> id="checkbox"
Save with my API keys type="checkbox"
</span> className="h-4 w-4 text-blue-600 border-gray-300 rounded dark:bg-gray-800 dark:border-gray-600 dark:focus:border-blue-500 dark:focus:ring-blue-500"
</label> />
</div> <span className="ml-2 font-medium text-gray-700 dark:text-white">
<div className="w-full flex justify-end"> Save with my API keys
<button </span>
onClick={() => { </label>
if(checked) downloadFlow(flows[tabIndex]); </div>
else downloadFlow(removeApiKeys(flows[tabIndex])) <div className="w-full flex justify-end">
}} <button
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded" onClick={() => {
> if (checked) downloadFlow(flows[tabIndex]);
Download Flow else downloadFlow(removeApiKeys(flows[tabIndex]));
</button> }}
</div> className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
</div> >
</div> Download Flow
</Dialog.Panel> </button>
</Transition.Child> </div>
</div> </div>
</div> </div>
</Dialog> </Dialog.Panel>
</Transition.Root> </Transition.Child>
); </div>
</div>
</Dialog>
</Transition.Root>
);
} }

View file

@ -5,11 +5,11 @@ import { TabsContext } from "../../../../contexts/tabsContext";
import FlowPage from "../.."; import FlowPage from "../..";
import { darkContext } from "../../../../contexts/darkContext"; import { darkContext } from "../../../../contexts/darkContext";
import { import {
ArrowDownTrayIcon, ArrowDownTrayIcon,
ArrowUpTrayIcon, ArrowUpTrayIcon,
BellIcon, BellIcon,
MoonIcon, MoonIcon,
SunIcon, SunIcon,
} from "@heroicons/react/24/outline"; } from "@heroicons/react/24/outline";
import { PopUpContext } from "../../../../contexts/popUpContext"; import { PopUpContext } from "../../../../contexts/popUpContext";
import AlertDropdown from "../../../../alerts/alertDropDown"; import AlertDropdown from "../../../../alerts/alertDropDown";
@ -18,103 +18,98 @@ import ImportModal from "../../../../modals/importModal";
import ExportModal from "../../../../modals/exportModal"; import ExportModal from "../../../../modals/exportModal";
export default function TabsManagerComponent() { export default function TabsManagerComponent() {
const { flows, addFlow, tabIndex, setTabIndex, uploadFlow, downloadFlow } = const { flows, addFlow, tabIndex, setTabIndex, uploadFlow, downloadFlow } =
useContext(TabsContext); useContext(TabsContext);
const { openPopUp } = useContext(PopUpContext); const { openPopUp } = useContext(PopUpContext);
const AlertWidth = 256; const AlertWidth = 256;
const { dark, setDark } = useContext(darkContext); const { dark, setDark } = useContext(darkContext);
const { notificationCenter, setNotificationCenter } = const { notificationCenter, setNotificationCenter } =
useContext(alertContext); useContext(alertContext);
useEffect(() => { useEffect(() => {
//create the first flow //create the first flow
if (flows.length === 0) { if (flows.length === 0) {
addFlow(); addFlow();
} }
}, [addFlow, flows.length]); }, [addFlow, flows.length]);
return ( return (
<div className="h-full w-full flex flex-col"> <div className="h-full w-full flex flex-col">
<div className="w-full flex pr-2 flex-row text-center items-center bg-gray-100 dark:bg-gray-800 px-2"> <div className="w-full flex pr-2 flex-row text-center items-center bg-gray-100 dark:bg-gray-800 px-2">
{flows.map((flow, index) => { {flows.map((flow, index) => {
return ( return (
<TabComponent <TabComponent
onClick={() => setTabIndex(index)} onClick={() => setTabIndex(index)}
selected={index === tabIndex} selected={index === tabIndex}
key={index} key={index}
flow={flow} flow={flow}
/> />
); );
})} })}
<TabComponent <TabComponent
onClick={() => { onClick={() => {
addFlow(); addFlow();
}} }}
selected={false} selected={false}
flow={null} flow={null}
/> />
<div className="ml-auto mr-2 flex gap-3"> <div className="ml-auto mr-2 flex gap-3">
<button <button
onClick={() => onClick={() => openPopUp(<ImportModal />)}
openPopUp( className="flex items-center gap-1 pr-2 border-gray-400 border-r text-sm text-gray-600 hover:text-gray-500"
<ImportModal >
/> Import <ArrowUpTrayIcon className="w-5 h-5" />
) </button>
} <button
className="flex items-center gap-1 pr-2 border-gray-400 border-r text-sm text-gray-600 hover:text-gray-500" onClick={() => openPopUp(<ExportModal />)}
> className="flex items-center gap-1 mr-2 text-sm text-gray-600 hover:text-gray-500"
Import <ArrowUpTrayIcon className="w-5 h-5" /> >
</button> Export <ArrowDownTrayIcon className="h-5 w-5" />
<button </button>
onClick={() =>openPopUp(<ExportModal/>)} <button
className="flex items-center gap-1 mr-2 text-sm text-gray-600 hover:text-gray-500" className="text-gray-600 hover:text-gray-500 "
> onClick={() => {
Export <ArrowDownTrayIcon className="h-5 w-5" /> setDark(!dark);
</button> }}
<button >
className="text-gray-600 hover:text-gray-500 " {dark ? (
onClick={() => { <SunIcon className="h-5 w-5" />
setDark(!dark); ) : (
}} <MoonIcon className="h-5 w-5" />
> )}
{dark ? ( </button>
<SunIcon className="h-5 w-5" /> <button
) : ( className="text-gray-600 hover:text-gray-500 relative"
<MoonIcon className="h-5 w-5" /> onClick={(event: React.MouseEvent<HTMLElement>) => {
)} setNotificationCenter(false);
</button> const top = (event.target as Element).getBoundingClientRect().top;
<button const left = (event.target as Element).getBoundingClientRect()
className="text-gray-600 hover:text-gray-500 relative" .left;
onClick={(event: React.MouseEvent<HTMLElement>) => { openPopUp(
setNotificationCenter(false); <div
const top = (event.target as Element).getBoundingClientRect().top; className="z-10 absolute"
const left = (event.target as Element).getBoundingClientRect() style={{ top: top + 20, left: left - AlertWidth }}
.left; >
openPopUp( <AlertDropdown />
<div </div>
className="z-10 absolute" );
style={{ top: top + 20, left: left - AlertWidth }} }}
> >
<AlertDropdown /> {notificationCenter && (
</div> <div className="absolute w-1.5 h-1.5 rounded-full bg-red-600 right-[3px]"></div>
); )}
}} <BellIcon className="h-5 w-5" aria-hidden="true" />
> </button>
{notificationCenter && ( </div>
<div className="absolute w-1.5 h-1.5 rounded-full bg-red-600 right-[3px]"></div> </div>
)} <div className="w-full h-full">
<BellIcon className="h-5 w-5" aria-hidden="true" /> <ReactFlowProvider>
</button> {flows[tabIndex] ? (
</div> <FlowPage flow={flows[tabIndex]}></FlowPage>
</div> ) : (
<div className="w-full h-full"> <></>
<ReactFlowProvider> )}
{flows[tabIndex] ? ( </ReactFlowProvider>
<FlowPage flow={flows[tabIndex]}></FlowPage> </div>
) : ( </div>
<></> );
)}
</ReactFlowProvider>
</div>
</div>
);
} }

View file

@ -1,12 +1,29 @@
export type ErrorAlertType = {title:string,list:Array<string>,id:string,removeAlert:(id:string)=>void} export type ErrorAlertType = {
export type NoticeAlertType = {title:string,link:string,id:string,removeAlert:(id:string)=>void} title: string;
export type SuccessAlertType = {title:string,id:string, removeAlert:(id:string)=>void} list: Array<string>;
export type SingleAlertComponentType = {dropItem:AlertItemType,removeAlert:(index:string)=>void} id: string;
removeAlert: (id: string) => void;
};
export type NoticeAlertType = {
title: string;
link: string;
id: string;
removeAlert: (id: string) => void;
};
export type SuccessAlertType = {
title: string;
id: string;
removeAlert: (id: string) => void;
};
export type SingleAlertComponentType = {
dropItem: AlertItemType;
removeAlert: (index: string) => void;
};
export type AlertDropdownType = {}; export type AlertDropdownType = {};
export type AlertItemType = { export type AlertItemType = {
type: "notice" | "error" | "success"; type: "notice" | "error" | "success";
title: string; title: string;
link?: string; link?: string;
list?: Array<string>; list?: Array<string>;
id: string; id: string;
}; };