diff --git a/frontend/public/images/ProfessionalServices.svg b/frontend/public/images/ProfessionalServices.svg new file mode 100644 index 00000000..164b6917 --- /dev/null +++ b/frontend/public/images/ProfessionalServices.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/public/images/SecurityConsultation.svg b/frontend/public/images/SecurityConsultation.svg new file mode 100644 index 00000000..05614a4d --- /dev/null +++ b/frontend/public/images/SecurityConsultation.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/public/images/Support.svg b/frontend/public/images/Support.svg new file mode 100644 index 00000000..83a18f00 --- /dev/null +++ b/frontend/public/images/Support.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/public/images/Training.svg b/frontend/public/images/Training.svg new file mode 100644 index 00000000..b01a9901 --- /dev/null +++ b/frontend/public/images/Training.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/public/images/icons/API.svg b/frontend/public/images/icons/API.svg new file mode 100644 index 00000000..447b94de --- /dev/null +++ b/frontend/public/images/icons/API.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/public/images/icons/about_us.svg b/frontend/public/images/icons/about_us.svg new file mode 100644 index 00000000..c77e7e8e --- /dev/null +++ b/frontend/public/images/icons/about_us.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/public/images/icons/about_us_hover.svg b/frontend/public/images/icons/about_us_hover.svg new file mode 100644 index 00000000..2c693ca9 --- /dev/null +++ b/frontend/public/images/icons/about_us_hover.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/public/images/icons/articles.svg b/frontend/public/images/icons/articles.svg new file mode 100644 index 00000000..763d960f --- /dev/null +++ b/frontend/public/images/icons/articles.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/public/images/icons/articles_hover.svg b/frontend/public/images/icons/articles_hover.svg new file mode 100644 index 00000000..6b51f294 --- /dev/null +++ b/frontend/public/images/icons/articles_hover.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/public/images/icons/contact_us.svg b/frontend/public/images/icons/contact_us.svg new file mode 100644 index 00000000..5fbc3568 --- /dev/null +++ b/frontend/public/images/icons/contact_us.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/public/images/icons/contact_us_hover.svg b/frontend/public/images/icons/contact_us_hover.svg new file mode 100644 index 00000000..0da02b7c --- /dev/null +++ b/frontend/public/images/icons/contact_us_hover.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/public/images/icons/discord.svg b/frontend/public/images/icons/discord.svg new file mode 100644 index 00000000..b982260b --- /dev/null +++ b/frontend/public/images/icons/discord.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/frontend/public/images/icons/docs.svg b/frontend/public/images/icons/docs.svg new file mode 100644 index 00000000..a568538d --- /dev/null +++ b/frontend/public/images/icons/docs.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/public/images/icons/docs_hover.svg b/frontend/public/images/icons/docs_hover.svg new file mode 100644 index 00000000..a711ba59 --- /dev/null +++ b/frontend/public/images/icons/docs_hover.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/public/images/icons/faq.svg b/frontend/public/images/icons/faq.svg new file mode 100644 index 00000000..7345040f --- /dev/null +++ b/frontend/public/images/icons/faq.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/public/images/icons/faq_hover.svg b/frontend/public/images/icons/faq_hover.svg new file mode 100644 index 00000000..4d29215a --- /dev/null +++ b/frontend/public/images/icons/faq_hover.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/public/images/icons/github.svg b/frontend/public/images/icons/github.svg new file mode 100644 index 00000000..de6c0200 --- /dev/null +++ b/frontend/public/images/icons/github.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/public/images/icons/linkedIn.svg b/frontend/public/images/icons/linkedIn.svg new file mode 100644 index 00000000..605e7804 --- /dev/null +++ b/frontend/public/images/icons/linkedIn.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/frontend/public/images/icons/usecases.svg b/frontend/public/images/icons/usecases.svg new file mode 100644 index 00000000..cc96e086 --- /dev/null +++ b/frontend/public/images/icons/usecases.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/public/images/icons/usecases_hover.svg b/frontend/public/images/icons/usecases_hover.svg new file mode 100644 index 00000000..6841b21e --- /dev/null +++ b/frontend/public/images/icons/usecases_hover.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/public/images/icons/x.svg b/frontend/public/images/icons/x.svg new file mode 100644 index 00000000..815e4e30 --- /dev/null +++ b/frontend/public/images/icons/x.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/frontend/public/images/logos/singul.svg b/frontend/public/images/logos/singul.svg new file mode 100644 index 00000000..5f27d7a3 --- /dev/null +++ b/frontend/public/images/logos/singul.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 9fc34790..cd8d49d5 100755 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -62,6 +62,7 @@ import Drift from "react-driftjs"; import { AppContext } from './context/ContextApi.jsx'; import Workflows2 from "./views/Workflows2.jsx"; import AppExplorer from "./views/AppExplorer.jsx"; +import Navbar from "./views/Navbar.jsx"; // Production - backend proxy forwarding in nginx var globalUrl = window.location.origin; @@ -213,7 +214,20 @@ const App = (message, props) => { { window?.location?.pathname === "/" || window?.location?.pathname === "/training" || !(isLoggedIn && isLoaded) ? (
-
*/} + {
{ + const theme = useTheme(); + return ( + + + + + + + ); +}; + +// Add this new component for mobile menu +const MobileMenu = ({ anchorEl, handleClose, isLoggedIn, navigate, isCloud }) => { + const [openSection, setOpenSection] = useState(null); + const theme = useTheme(); + + // Add useEffect to handle body scroll + useEffect(() => { + if (Boolean(anchorEl)) { + // Disable scroll + document.body.style.overflow = 'hidden'; + } else { + // Re-enable scroll + document.body.style.overflow = 'auto'; + } + + // Cleanup function to ensure scroll is re-enabled when component unmounts + return () => { + document.body.style.overflow = 'auto'; + }; + }, [anchorEl]); + + const handleSectionClick = (section) => { + setOpenSection(openSection === section ? null : section); + }; + + const handleItemClick = (path) => { + handleClose(); + navigate(path); + }; + + const showDesktopToast = () => { + toast.info("Please open on desktop for the full experience"); + handleClose(); + }; + + return ( + + + {Object.keys(menuData).map((section) => ( + + + + + {section === 'Resources' ? ( + + {menuData.Resources.columns.map((column, index) => ( + + + {column.title} + + + {column.social ? ( + <> + + {column.platforms.map((platform) => ( + { + if (isCloud) { + ReactGA.event(platform.gaData); + } + window.open(platform.link, '_blank') + return; + }} + // onClick={() => showDesktopToast()} + > + {platform.name} + + ))} + + + Follow Us + + + {column.followUs.map((platform) => ( + { + if (isCloud) { + ReactGA.event(platform.gaData); + } + window.open(platform.link, '_blank') + return; + }} + > + {platform.name} + + ))} + + + ) : ( + column.items.map((item) => ( + + )) + )} + + ))} + + ) : ( + + {menuData[section].map((item) => ( + + ))} + + )} + + + ))} + + {/* Static menu items */} + + + + {/* Action buttons */} + + + + + + + ); +}; + +const Navbar = (props) => { + const { + globalUrl, + isLoaded, + isLoggedIn, + removeCookie, + homePage, + userdata, + // isMobile, + serverside, + billingInfo, + + notifications, + } = props; + const theme = useTheme(); + const [searchBarModalOpen, setSearchBarModalOpen] = useState(false); + const [pricingModalOpen, setPricingModalOpen] = useState(false); + const isTabletOrMobile = useMediaQuery(theme.breakpoints.down("lg")); + const isMobile = useMediaQuery(theme.breakpoints.down("md")); + const [anchorElNav, setAnchorElNav] = useState(null); + const [openMenu, setOpenMenu] = useState(null); + const [selectedOrganization, setSelectedOrganization] = useState({}); + const navigate = useNavigate(); + const [anchorElUser, setAnchorElUser] = useState(null); + const [anchorElOrg, setAnchorElOrg] = useState(null); + const [isOrgChanging, setIsOrgChanging] = useState(false); + const [isHovered, setIsHovered] = useState(""); + const [orgSelectOpen, setOrgSelectOpen] = useState(false); + const [showTopbar, setShowTopbar] = useState(true) // Set to true to show top bar + const isCloud = + serverside === true || typeof window === "undefined" + ? true + : window.location.host === "localhost:3002" || + window.location.host === "shuffler.io" || + window.location.host === "localhost:5002"; + + + const stripeKey = typeof window === 'undefined' || window.location === undefined ? "" : window.location.origin === "https://shuffler.io" ? "pk_live_51PXYYMEJjT17t98N20qEqItyt1fLQjrnn41lPeG2PjnSlZHTDNKHuisAbW00s4KAn86nGuqB9uSVU4ds8MutbnMU00DPXpZ8ZD" : "pk_test_51PXYYMEJjT17t98NbDkojZ3DRvsFUQBs35LGMx3i436BXwEBVFKB9nCvHt0Q3M4MG3dz4mHheuWvfoYvpaL3GmsG00k1Rb2ksO" + + const topbar_var = "topbar_closed5" + useEffect(() => { + // Manually setShowTopbar(true) to show topbar by default + const topbar = localStorage.getItem(topbar_var) + if (topbar === "true") { + setShowTopbar(false) + } + }, []) + + const pricingModal = + { + setPricingModalOpen(false); + }} + PaperProps={{ + style: { + color: "white", + minWidth: 850, + minHeight: 370, + padding: 20, + backgroundColor: "rgba(0, 0, 0, 1)", + borderRadius: theme.palette?.borderRadius, + }, + }} + > + + + Upgrade your plan + + { + if (isCloud) { + ReactGA.event({ + category: "navbar", + action: "close_upgrade_modal", + label: "navbar_upgrade_modal", + }) + }; + setPricingModalOpen(false); + }} + style={{ + marginLeft: "auto", + position: "absolute", + top: 20, + right: 20, + }} + > + + + +
+ +
+
+ + + const modalView = ( + { + setSearchBarModalOpen(false); + }} + PaperProps={{ + style: { + color: "white", + minWidth: 750, + height: 785, + borderRadius: 16, + border: "1px solid var(--Container-Stroke, #494949)", + background: "var(--Container, #000000)", + boxShadow: "0px 16px 24px 8px rgba(0, 0, 0, 0.25)", + }, + }} + sx={{ + zIndex: 50005, + '& .MuiBackdrop-root': { + backgroundColor: 'rgba(0, 0, 0, 0.8)', + }, + }} + > + + + Search for Docs, Apps, Workflows and more + + setSearchBarModalOpen(false)} + sx={{ + color: 'white', + '&:hover': { + backgroundColor: 'rgba(255, 255, 255, 0.1)' + } + }} + > + + + + + + + + + + + ); + + const handleOpenNavMenu = (event) => { + setAnchorElNav(event.currentTarget); + }; + + const handleCloseNavMenu = () => { + setAnchorElNav(null); + }; + + const handleMenuOpen = (menu) => { + setOpenMenu(menu); + }; + + const handleMenuClose = () => { + setOpenMenu(null); + }; + + const handleOpenUserMenu = (event) => { + setAnchorElUser(event.currentTarget); + }; + + const handleCloseUserMenu = () => { + setAnchorElUser(null); + }; + + const handleOpenOrgMenu = (event) => { + setAnchorElOrg(event.currentTarget); + }; + + const handleCloseOrgMenu = () => { + setAnchorElOrg(null); + }; + + const menuStyles = { + "& .MuiPaper-root": { + backgroundColor: "#212121", + marginTop: 1, + backdropFilter: "blur(10px)", + fontFamily: theme.typography.fontFamily, + }, + }; + + const menuItemBox = { + display: "flex", + alignItems: "flex-start", + padding: 2, + paddingTop: "20px", + paddingBottom: "20px", + paddingLeft: "20px", + gap: 2, + width: "100%", + backgroundColor: "#212121", + transition: "all 0.2s ease-in-out", + borderBottom: "1px solid #494949", + }; + + const buttonStyles = { + fontFamily: theme.typography.fontFamily, + color: "white", + textTransform: "none", + fontSize: "16px", + fontWeight: 400, + padding: "6px 12px", + "& .MuiSvgIcon-root": { + transition: "transform 0.2s ease-in-out", + }, + "&:hover": { + backgroundColor: "transparent", + color: theme.palette.primary.main, + "& .MuiSvgIcon-root": { + transform: "rotate(180deg)", + }, + }, + }; + + // Render menu content based on type + const renderMenuContent = (item, isCloud) => { + if (item === "Resources") { + return ( + + {menuData.Resources.columns.map((column, index) => ( + + + {column.title} + + + {column.social ? ( + <> + + {column.platforms.map((platform) => ( + { + if (isCloud) { + ReactGA.event(platform.gaData); + } + handleMenuClose(); + }} + sx={{ + padding: 0, + width: 48, + height: 48, + "&:hover": { + backgroundColor: "transparent", + opacity: 0.8, + }, + }} + > + {platform.name} + + ))} + + + Follow Us + + + {column.followUs.map((platform) => ( + { + if (isCloud) { + ReactGA.event(platform.gaData); + } + handleMenuClose(); + }} + sx={{ + padding: 0, + width: 48, + height: 48, + "&:hover": { + backgroundColor: "transparent", + opacity: 0.8, + }, + }} + > + {platform.name} + + ))} + + + ) : ( + + {column.items.map((item) => ( + + ))} + + )} + + ))} + + ); + } + + return menuData[item].map((menuItem, index) => ( + { + if (menuItem.title === "Singul") { + window.open(menuItem.path, '_blank'); + return; + } + if(isCloud) { + ReactGA.event(menuItem.gaData); + } + handleCloseNavMenu(); + handleMenuClose(); + if(isCloud) { + navigate(menuItem.path); + } else { + if(menuItem.path.includes("docs")){ + navigate(menuItem.path); + handleMenuClose(); + }else{ + window.open("https://shuffler.io" + menuItem.path, '_blank'); + return; + } + } + }} + sx={{ + padding: 0, + backgroundColor: "#212121", + "&:hover": { + backgroundColor: "#212121", + }, + "&:last-child": { + borderBottomLeftRadius: "4px", + borderBottomRightRadius: "4px", + }, + "&:first-of-type": { + paddingTop: "4px", + }, + }} + > + + + + + + {menuItem.title} + + {menuItem.title === "Singul" && ( + + Coming Soon + + )} + + + {menuItem.description} + + + + + )); + }; + + const renderDesktopMenu = () => ( + + {Object.keys(menuData).map((item) => ( + + + + {/* Custom Dropdown */} + handleMenuOpen(item)} + onMouseLeave={handleMenuClose} + sx={{ + position: "absolute", + top: "130%", + left: + item === "Products" + ? 0 + : item === "Services" + ? -50 + : item === "Resources" + ? isTabletOrMobile ? -330 : -250 + : 0, + backgroundColor: "#212121", + borderTopLeftRadius: 0, + borderTopRightRadius: 0, + borderBottomLeftRadius: "4px", + borderBottomRightRadius: "4px", + boxShadow: + "0 8px 16px rgba(0, 0, 0, 0.25), 0 2px 4px rgba(0, 0, 0, 0.1)", + backdropFilter: "blur(10px)", + zIndex: -20, + opacity: openMenu === item ? 1 : 0, + visibility: openMenu === item ? "visible" : "hidden", + transform: openMenu === item ? "translateY(0)" : "translateY(-8px)", + transition: "transform 0.3s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.3s ease", + pointerEvents: openMenu === item ? "auto" : "none", + ...(item === "Resources" && { + width: "900px", + padding: 3, + }), + }} + > + {renderMenuContent(item, isCloud)} + + + ))} + + + + ); + + const menuItemStyles = { + fontFamily: theme.typography.fontFamily, + color: "white", + "&:hover": { + backgroundColor: "rgba(255, 133, 68, 0.1)", + }, + }; + + const searchButtonStyles = { + fontFamily: theme.typography.fontFamily, + color: "rgba(255, 255, 255, 0.7)", + border: "1px solid rgba(26, 26, 26, 0.8)", + backgroundColor: "#2F2F2F", + textTransform: "none", + borderRadius: "8px", + fontSize: "14px", + padding: "6px 12px", + display: "flex", + alignItems: "center", + height: "42px", + gap: 1, + minWidth: "110px", + justifyContent: "space-between", + "&:hover": { + borderColor: "rgba(255, 255, 255, 0.1)", + }, + }; + + const searchIconButtonStyles = { + color: "rgba(255, 255, 255, 0.7)", + padding: "8px", + minWidth: "unset", + height: "42px", + "&:hover": { + backgroundColor: "#3F3F3F", + }, + }; + + // Add this shared button style + const sharedButtonStyles = { + fontFamily: theme.typography.fontFamily, + textTransform: "none", + fontSize: "16px", + fontWeight: 600, + padding: "6px 24px", + }; + + + useEffect(() => { + Mousetrap.bind(['command+k', 'ctrl+k'], () => { + setSearchBarModalOpen(true); + return false; // Prevent the default action + }); + Mousetrap.bind(['esc'], () => { + setSearchBarModalOpen(false); + return false; // Prevent the default action + }); + + return () => { + Mousetrap.unbind(['command+k', 'ctrl+k']); + }; + }, []); + + useEffect(() => { + if (isLoggedIn && userdata?.active_org?.id?.length > 0) { + handleGetOrg(userdata.active_org.id); + } + }, [isLoggedIn]); + + const handleGetOrg = (orgId) => { + fetch(`${globalUrl}/api/v1/orgs/${orgId}`, { + method: "GET", + credentials: "include", + headers: { + "Content-Type": "application/json", + }, + }) + .then((response) => { + if (response.status === 401) { + } + + return response.json(); + }) + .then((responseJson) => { + if (responseJson["success"] === false) { + console.log("Error getting org: ", responseJson); + } else { + setSelectedOrganization(responseJson); + } + }) + .catch((error) => { + console.log("Error getting org: ", error); + }); + }; + + const handleClickLogout = () => { + console.log("SHOULD LOG OUT"); + + toast.info("Logging out..."); + // Don't really care about the logout + fetch(globalUrl + "/api/v1/logout", { + credentials: "include", + method: "POST", + headers: { + "Content-Type": "application/json", + }, + }) + .then(() => { + // Log out anyway + removeCookie("session_token", { path: "/" }); + removeCookie("session_token", { path: "/" }); + removeCookie("session_token", { path: "/" }); + + removeCookie("__session", { path: "/" }); + removeCookie("__session", { path: "/" }); + removeCookie("__session", { path: "/" }); + + removeCookie("__session", { path: "/" }); + + window.location.pathname = "/"; + + localStorage.setItem("globalUrl", "") + + // Delete userinfo from localstorage + localStorage.removeItem("apps") + localStorage.removeItem("workflows") + localStorage.removeItem("userinfo") + }) + .catch((error) => { + console.log(error); + }); + }; + + const topbarHeight = showTopbar ? 40 : 0 + const topbar = !isCloud || !showTopbar ? null : + curpath === "/" || curpath.includes("/docs") || curpath === "/pricing" || curpath === "/contact" || curpath === "/search" || curpath === "/usecases" || curpath === "/usecases2" || curpath === "/training" || curpath === "/professional-services" ? + +
+ + {/* Shuffle 1.4.0 is out! Read more about  */} + New  + + { + ReactGA.event({ + category: "landingpage", + action: "click_header_training", + label: "", + }) + + navigate("/training") + + }} style={{ cursor: "pointer", textDecoration: "none", fontWeight: 600, color: "rgba(255,255,255,0.9)" }}> + Public Training + + +  Dates Released! + + { + setShowTopbar(false) + + // Set storage that it's clicked + localStorage.setItem(topbar_var, "true") + }}> + + +
+
+ : + null + + const handleClickChangeOrg = (orgId) => { + setIsOrgChanging(true); + const data = { org_id: orgId }; + + localStorage.setItem("globalUrl", ""); + localStorage.setItem("getting_started_sidebar", "open"); + toast.info("Changing organization..."); + fetch(`${globalUrl}/api/v1/orgs/${orgId}/change`, { + mode: "cors", + credentials: "include", + crossDomain: true, + method: "POST", + body: JSON.stringify(data), + withCredentials: true, + headers: { + "Content-Type": "application/json; charset=utf-8", + }, + }) + .then(function (response) { + if (response.status !== 200) { + console.log("Error in response"); + } else { + localStorage.removeItem("apps"); + localStorage.removeItem("workflows"); + localStorage.removeItem("userinfo"); + } + + return response.json(); + }) + .then(function (responseJson) { + if (responseJson.success === true) { + if ( + responseJson.region_url !== undefined && + responseJson.region_url !== null && + responseJson.region_url.length > 0 + ) { + console.log("Region Change: ", responseJson.region_url); + localStorage.setItem("globalUrl", responseJson.region_url); + //globalUrl = responseJson.region_url + } + + if (responseJson["reason"] === "SSO_REDIRECT") { + toast.info("Redirecting to SSO login page as SSO is required for this organization."); + setTimeout(() => { + window.location.href = responseJson["url"]; + }, 2000); + } else { + toast("Successfully changed active organization - refreshing!"); + setTimeout(() => { + window.location.reload(); + }, 2000); + } + } else { + setIsOrgChanging(false); + if ( + responseJson.reason !== undefined && + responseJson.reason !== null && + responseJson.reason.length > 0 + ) { + toast(responseJson.reason); + } else { + toast("Failed changing org. Try again or contact support@shuffler.io if this persists."); + } + } + }) + .catch((error) => { + console.log("error changing: ", error); + setIsOrgChanging(false); + }); + }; + + // Add these helper functions from LeftSideBar + const getRegionTag = (region_url) => { + let regiontag = "EU"; + if (region_url !== undefined && region_url !== null && region_url.length > 0) { + const regionsplit = region_url.split("."); + if (regionsplit.length > 2 && !regionsplit[0].includes("shuffler")) { + const namesplit = regionsplit[0].split("/"); + regiontag = namesplit[namesplit.length - 1]; + + if (regiontag === "california") { + regiontag = "US"; + } else if (regiontag === "frankfurt") { + regiontag = "EU-2"; + } else if (regiontag === "ca") { + regiontag = "CA"; + } + } + } + return regiontag; + }; + + const getRegionFlag = (region_url) => { + const regionTag = getRegionTag(region_url); + const regionMapping = { + "US": "us", + "EU": "eu", + "EU-2": "de", + "CA": "ca", + "UK": "gb" + }; + + const region = regionMapping[regionTag] || "eu"; + return `https://flagcdn.com/48x36/${region}.png`; + }; + + // Add this useEffect to prevent scroll locking + useEffect(() => { + // Remove modal classes that cause scroll locking + const removeModalClasses = () => { + document.body.style.overflow = 'auto'; + document.body.style.paddingRight = '0px'; + }; + + // Create observer to watch for class changes + const observer = new MutationObserver((mutations) => { + mutations.forEach((mutation) => { + if (mutation.attributeName === 'class') { + if (document.body.classList.contains('MuiModal-open')) { + removeModalClasses(); + } + } + }); + }); + + // Start observing + observer.observe(document.body, { + attributes: true, + attributeFilter: ['class'], + }); + + // Cleanup + return () => { + observer.disconnect(); + removeModalClasses(); + }; + }, []); + + const handleOrgSelectClick = (event) => { + // Prevent the default Select behavior + event.preventDefault(); + if(isCloud){ + ReactGA.event({ + category: "navbar", + action: "org_dropdown_click", + label: "org_dropdown_click", + }) + } + // Toggle the select open state + setOrgSelectOpen(!orgSelectOpen); + }; + + return ( + + {topbar} + + + + { + if (isCloud) { + ReactGA.event({ + category: "navbar", + action: "home_click", + label: "shuffle_logo", + }); + } + }} + > + shuffle logo + + + + {isMobile ? ( + /* Mobile Navigation Icons */ + + setSearchBarModalOpen(true)} + > + + + { + if(Boolean(anchorElNav)) { + handleCloseNavMenu(); + }else{ + handleOpenNavMenu(e); + } + } + } + sx={{ color: "white" }} + > + {Boolean(anchorElNav) ? ( + + ) : ( + + )} + + + + ) : ( + <> + {modalView} + {pricingModal} + {renderDesktopMenu()} + {/* Right Side Buttons */} + + {!isLoaded ? ( + + ) : isLoggedIn ? ( + <> + {isOrgChanging ? ( + + ) : ( + <> + + + + K +
+ } + placement="bottom" + arrow + componentsProps={{ + tooltip: { + sx: { + backgroundColor: "rgba(33, 33, 33, 1)", + color: "rgba(241, 241, 241, 1)", + fontSize: 12, + border: "1px solid rgba(73, 73, 73, 1)", + fontFamily: theme?.typography?.fontFamily, + } + }, + popper: { + sx: { + zIndex: 1000019, + } + } + }} + > + { + if (isCloud) { + ReactGA.event({ + category: "navbar", + action: "search_icon_click", + label: "search_icon_click", + }) + } + setSearchBarModalOpen(true); + }} + > + + + + {isCloud && (userdata.org_status === undefined || userdata.org_status === null || userdata.org_status.length === 0) ? + + : null} + + + {/* Organization Dropdown */} + {/* */} + + {/* User Avatar Menu */} + { + if (isCloud) { + ReactGA.event({ + category: "navbar", + action: "click_user_menu", + label: "open_user_dropdown" + }); + } + handleOpenUserMenu(e); + }} + sx={{ + padding: 0, + "&:hover": { + backgroundColor: "rgba(47, 47, 47, 0.5)", + }, + }} + > + + + + + + + {/* User Info Section */} + + + + + + {userdata?.username} + + + + + + + + {/* Menu Items */} + { + if (isCloud) { + ReactGA.event({ + category: "navbar", + action: "user_dropdown_click", + label: "go_to_admin" + }); + } + handleCloseUserMenu(); + navigate("/admin"); + }} + onMouseEnter={() => setIsHovered("organization")} + onMouseLeave={() => setIsHovered("")} + sx={{ + py: 1.5, + px: 2, + fontFamily: theme.typography.fontFamily, + transition: "color 0.1s ease", + '&:hover': { + backgroundColor: 'rgba(255, 255, 255, 0.1)', + color: isHovered === "organization" ? "#FF8544" : "white", + }, + }} + > + + + + Organization + + + + + { + if (isCloud) { + ReactGA.event({ + category: "navbar", + action: "user_dropdown_click", + label: "go_to_settings", + }) + } + handleCloseUserMenu(); + navigate("/settings"); + }} + onMouseEnter={() => setIsHovered("settings")} + onMouseLeave={() => setIsHovered("")} + sx={{ + py: 1.5, + px: 2, + fontFamily: theme.typography.fontFamily, + transition: "color 0.1s ease", + '&:hover': { + backgroundColor: 'rgba(255, 255, 255, 0.1)', + color: isHovered === "settings" ? "#FF8544" : "white", + }, + }} + > + + + + Settings + + + + + { + if (isCloud) { + ReactGA.event({ + category: "navbar", + action: "user_dropdown_click", + label: "go_to_notifications", + }) + } + handleCloseUserMenu(); + navigate("/admin?admin_tab=notifications"); + }} + onMouseEnter={() => setIsHovered("notifications")} + onMouseLeave={() => setIsHovered("")} + sx={{ + py: 1.5, + px: 2, + fontFamily: theme.typography.fontFamily, + transition: "color 0.1s ease", + '&:hover': { + backgroundColor: 'rgba(255, 255, 255, 0.1)', + color: isHovered === "notifications" ? "#FF8544" : "white", + }, + }} + > + + + + Notifications ({notifications === undefined || notifications === null ? 0 : + notifications?.filter((notification) => notification.read === false).length}) + + + + + + + + { + if (isCloud) { + ReactGA.event({ + category: "navbar", + action: "user_dropdown_click", + label: "go_to_about", + }) + } + handleCloseUserMenu(); + navigate("/docs/about"); + }} + onMouseEnter={() => setIsHovered("about")} + onMouseLeave={() => setIsHovered("")} + sx={{ + py: 1.5, + px: 2, + fontFamily: theme.typography.fontFamily, + transition: "color 0.1s ease", + '&:hover': { + backgroundColor: 'rgba(255, 255, 255, 0.1)', + color: isHovered === "about" ? "#FF8544" : "white", + }, + }} + > + + + + About + + + + + { + if (isCloud) { + ReactGA.event({ + category: "navbar", + action: "user_dropdown_click", + label: "logout_click", + }) + } + handleCloseUserMenu(); + handleClickLogout(); + }} + onMouseEnter={() => setIsHovered("logout")} + onMouseLeave={() => setIsHovered("")} + sx={{ + py: 1.5, + px: 2, + fontFamily: theme.typography.fontFamily, + '&:hover': { + backgroundColor: 'rgba(255, 255, 255, 0.1)', + color: isHovered === "logout" ? "#FD4C62" : "white", + }, + }} + > + + + + Logout + + + + + + + + + Version 1.4.5 + + + + + )} + + ) : ( + <> + + + + K + + } + placement="bottom" + arrow + componentsProps={{ + tooltip: { + sx: { + backgroundColor: "rgba(33, 33, 33, 1)", + color: "rgba(241, 241, 241, 1)", + fontSize: 12, + border: "1px solid rgba(73, 73, 73, 1)", + fontFamily: theme?.typography?.fontFamily, + } + }, + popper: { + sx: { + zIndex: 1000019, + } + } + }} + > + { + if (isCloud) { + ReactGA.event({ + category: "navbar", + action: "search_icon_click", + label: "search_icon_click", + }) + } + setSearchBarModalOpen(true); + }} + > + + + + + + + + + )} + + + )} + + + + ); +}; + +export default Navbar;