import React, { useState, useEffect } from "react"; import { toast } from "react-toastify"; import theme from "../theme.jsx"; import { BrowserView, MobileView } from "react-device-detect"; import { useNavigate, Link } from "react-router-dom"; import ReactGA from "react-ga4"; import LicencePopup from "../components/LicencePopup.jsx"; import SearchField from "../components/Searchfield.jsx"; import { Paper, Typography, Badge, Tooltip, List, ListItem, Avatar, Menu, MenuItem, Select, Button, ButtonGroup, Grid, IconButton, Divider, LinearProgress, AppBar, Dialog, DialogTitle, } from "@mui/material"; import { makeStyles } from "@mui/styles"; import { Close as CloseIcon, MeetingRoom as MeetingRoomIcon, HelpOutline as HelpOutlineIcon, Settings as SettingsIcon, Notifications as NotificationsIcon, Home as HomeIcon, Apps as AppsIcon, Description as DescriptionIcon, EmojiObjects as EmojiObjectsIcon, Business as BusinessIcon, Polyline as PolylineIcon, Add as AddIcon, Analytics as AnalyticsIcon, Lightbulb as LightbulbIcon, ExpandMore as ExpandMoreIcon, KeyboardArrowDown as KeyboardArrowDownIcon } from "@mui/icons-material"; import zIndex from "@mui/material/styles/zIndex.js"; const useStyles = makeStyles((theme) => ({ menuButton: { textTransform: "none !important", fontStyle: "normal", color: "#333", textAlign: "center", fontSize: "16px !important", fontWeight: "500 !important", display: "flex", alignItems: "center", '&:hover': { backgroundColor: "transparent", }, }, dropdownMenu: { borderRadius: "12px !important", zIndex: 10, "& .MuiPaper-root": { border: "1px solid #f85a3e", boxShadow: "0 4px 6px rgba(0, 0, 0, 0.1)", borderRadius: "12px !important", top: -10, overflow: "visible", background: "#1A1A1A", "&::before": { content: '""', display: "block", position: "absolute", top: -10, left: "82%", borderLeft: "10px solid transparent", borderRight: "10px solid transparent", borderBottom: "10px solid #f85a3e", }, }, }, dropdownMenuItem: { fontSize: "16px", fontWeight: 400, color: "#fff", background: "#1A1A1A", borderRadius: 16, // Ensure the border radius matches the container transition: "background-color 0.3s, color 0.3s", '&:hover': { color: "#1A73E8", background: "#3c3c3c", }, }, menuList: { display: "flex", flexDirection: "row", alignItems: "center", padding: 0, margin: 0, listStyle: "none", textTransform: "none", }, cssStcg3yMenuList: { borderRadius: "12px !important", }, divider: { width: "80%", border: "0.5px solid #494949", backgroundColor: "#fff", alignItems: "center", marginLeft: 17 }, })); const Header = (props) => { const { globalUrl, isLoaded, isLoggedIn, removeCookie, homePage, userdata, isMobile, serverside, billingInfo, notifications, } = props; const [isHeader, setIsHeader] = React.useState(false); const [modalOpen, setModalOpen] = useState(false); const [tooltipOpen, setTooltipOpen] = useState(false); const [anchorEl, setAnchorEl] = React.useState(null); const [anchorElAvatar, setAnchorElAvatar] = React.useState(null); const [subAnchorEl, setSubAnchorEl] = React.useState(null); const [upgradeHovered, setUpgradeHovered] = React.useState(false); const [showTopbar, setShowTopbar] = useState(false) // Set to true to show top bar const [selectedOrganization, setSelectedOrganization] = useState({}); const stripeKey = typeof window === 'undefined' || window.location === undefined ? "" : window.location.origin === "https://shuffler.io" ? "pk_live_51PXYYMEJjT17t98N20qEqItyt1fLQjrnn41lPeG2PjnSlZHTDNKHuisAbW00s4KAn86nGuqB9uSVU4ds8MutbnMU00DPXpZ8ZD" : "pk_test_51PXYYMEJjT17t98NbDkojZ3DRvsFUQBs35LGMx3i436BXwEBVFKB9nCvHt0Q3M4MG3dz4mHheuWvfoYvpaL3GmsG00k1Rb2ksO" let navigate = useNavigate(); const classes = useStyles(); const handleClick = (event) => { setAnchorEl(event.currentTarget); }; const handleMenuOpen = (event) => { setAnchorEl(event.currentTarget); }; const handleMenuClose = () => { setAnchorEl(null); }; const handleMenuItemClick = (path) => { navigate(path); handleMenuClose(); }; const handleTooltipClose = () => { setTooltipOpen(false); }; const handleTooltipOpen = () => { setTooltipOpen(true); }; 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 hoverColor = "#f85a3e"; const hoverOutColor = "#e8eaf6"; const handleHover = (event) => { event.target.style.color = hoverColor; }; const handleHoverOut = (event) => { event.target.style.color = hoverOutColor; }; const handleClose = () => { setAnchorEl(null); setAnchorElAvatar(null); }; // Should be based on some path const logoCheck = !homePage ? null : null const hrefStyle = { color: hoverOutColor, textDecoration: "none", textTransform: "none", fontStyle: "normal", width: "100%", fontSize: "16px", }; const menuText = { textTransform: "none", color: "#FFF", textAlign: "center", fontSize: 16, fontStyle: "normal", fontWeight: 400, lineHeight: "normal", } const isCloud = serverside === true || typeof window === "undefined" ? true : window.location.host === "localhost:3002" || window.location.host === "shuffler.io" || window.location.host === "localhost:5002"; const curpath = (typeof window !== "undefined" && window.location && typeof window.location.pathname === "string") ? window.location.pathname : ""; 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); }); }; useEffect(() => { if (isLoggedIn && userdata?.active_org?.id?.length > 0) { handleGetOrg(userdata.active_org.id); } }, [isLoggedIn]); // DEBUG HERE const handleClickLogout = () => { console.log("SHOULD LOG 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_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 notificationWidth = 335 const imagesize = 22; const boxColor = "#86c142"; const handleClickChangeOrg = (orgId) => { // Don't really care about the logout //name: org.name, //orgId = "asd" const data = { org_id: orgId, }; localStorage.setItem("globalUrl", ""); localStorage.setItem("getting_started_sidebar", "open"); 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) { console.log("In here?"); 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(() => { toast.info( "Redirecting to SSO login page as SSO is required for this organization." ); window.location.href = responseJson["url"]; return; }, 2000); } else { toast("Successfully changed active organization - refreshing!"); setTimeout(() => { window.location.reload(); }, 2000); } } else { 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); //removeCookie("session_token", {path: "/"}) }); }; const supportMenu = ( { }} > {/*#f865f2*/} ); // Should be based on some path const parsedAvatar = userdata.avatar !== undefined && userdata.avatar !== null && userdata.avatar.length > 0 ? userdata.avatar : "" const avatarMenu = ( { setAnchorElAvatar(event.currentTarget); }} > { handleClose(); }} > { handleClose(); }} > Organization { handleClose(); }} > Account { handleClose(); }} > Notifications ({ notifications === undefined || notifications === null ? 0 : notifications?.filter((notification) => notification.read === false).length }) { handleClose(); }} > Use Cases { handleClose(); }} > About { handleClickLogout(); event.preventDefault(); handleClose(); }} >  Logout Version: 1.4.5 ); const listItemStyle = { textAlign: "center", marginTop: "auto", marginBottom: "auto", // marginRight: 10, }; const modalView = { setModalOpen(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: "header", action: "close_Upgread_popup", label: "", }) }; setModalOpen(false); }} style={{ marginLeft: "auto", position: "absolute", top: 20, right: 20, }} >
// Handle top bar or something const defaultTop = -2 const loginTextBrowser = !isLoggedIn ? (
{ if (isCloud) { ReactGA.event({ category: "header", action: "home_click", label: "", }); } }} > shuffle logo {isCloud && ( handleMenuItemClick('/pricing')}> Pricing )}
handleMenuItemClick('/professional-services')}> Professional Services
handleMenuItemClick('/training')}> Training Courses
handleMenuItemClick('/partners')}> Partner Program
{/* */}
) : (
logo
{/* */} Workflows
{/* */} Apps
{/*
Dashboard
*/}
{/* */} Docs
{/*
Pricing & Services
*/}
{avatarMenu} {supportMenu} {logoCheck} {userdata === undefined || userdata.orgs === undefined || userdata.orgs === null || userdata.orgs.length <= 0 ? null : ( )} {/* Show on cloud, if not suborg and if not customer/pov/internal */} { userdata.licensed !== undefined && userdata.licensed !== null && userdata.licensed === false ? : null} {userdata === undefined || userdata.app_execution_limit === undefined || userdata.app_execution_usage === undefined || userdata.app_execution_usage < 1000 ? null : ( App Runs used: {userdata.app_execution_usage} / {userdata.app_execution_limit}. When the limit is reached, you can still use Shuffle normally, but your Workflow triggers will stop workflows from starting. Reach out to support@shuffler.io to extend this limit. Customer workflows are NOT stopped this way. } >
= 0.9 ? "2px solid #f86a3e" : null, }} onClick={() => { console.log( userdata.appe_execution_usage / userdata.app_execution_limit ); if (window.drift !== undefined) { window.drift.api.startInteraction({ interactionId: 326905, }); navigate("/pricing"); } else { console.log( "Couldn't find drift in window.drift and not .drift-open-chat with querySelector: ", window.drift ); } }} > {( (userdata.app_execution_usage / userdata.app_execution_limit) * 100 ).toFixed(0)} %
)}
); const loginTextMobile = !isLoggedIn ? (
logo
About
) : (
Logout
{logoCheck}
); // // /* !isLoggedIn ?
{loginTextBrowser}
: */ 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 return !isMobile ? (
{topbar}
{loginTextBrowser}
{modalView}
) : ( {loginTextMobile} ); }; export default Header;