import React, { useState, useEffect, useRef, useContext } from 'react';
import {getTheme} from '../theme.jsx';
import { useNavigate, Link, useParams } from "react-router-dom";
import { toast } from "react-toastify"
import {
Chip,
IconButton,
TextField,
InputAdornment,
List,
Card,
ListItem,
ListItemAvatar,
ListItemText,
Avatar,
Grid,
Typography,
Tooltip,
Divider,
Button,
} from '@mui/material';
import ArticleIcon from '@mui/icons-material/Article';
import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight';
import ManageSearchIcon from '@mui/icons-material/ManageSearch';
import {
VerifiedUser as VerifiedUserIcon,
} from '@mui/icons-material'
import {
AvatarGroup,
} from "@mui/material"
import { Context } from '../context/ContextApi.jsx';
import { Search as SearchIcon, Close as CloseIcon, Folder as FolderIcon, Code as CodeIcon, LibraryBooks as LibraryBooksIcon } from '@mui/icons-material'
import algoliasearch from 'algoliasearch/lite';
import aa from 'search-insights'
import { InstantSearch, Configure, connectSearchBox, connectHits, Index } from 'react-instantsearch-dom';
//import { InstantSearch, SearchBox, Hits, connectSearchBox, connectHits, Index } from 'react-instantsearch-dom';
// https://www.algolia.com/doc/api-reference/widgets/search-box/react/
const chipStyle = {
backgroundColor: "#3d3f43", height: 30, marginRight: 5, paddingLeft: 5, paddingRight: 5, height: 28, cursor: "pointer", borderColor: "#3d3f43", color: "white",
}
const searchClient = algoliasearch("JNSS5CFDZZ", "c8f882473ff42d41158430be09ec2b4e")
const SearchData = props => {
const { serverside, globalUrl, userdata } = props
let navigate = useNavigate();
const { searchBarModalOpen, setSearchBarModalOpen, isDocSearchModalOpen } = useContext(Context);
const borderRadius = 3
const node = useRef()
const [searchOpen, setSearchOpen] = useState(false)
const [oldPath, setOldPath] = useState("")
const [value, setValue] = useState("");
const isDocSearchModal = isDocSearchModalOpen;
const {themeMode, supportEmail} = useContext(Context);
const theme = getTheme(themeMode)
const handleLinkClick = () => {
if (searchBarModalOpen) {
setSearchBarModalOpen(false); // Assuming setModalOpen is defined correctly
} else {
console.log("Condition not met, staying on the same page");
}
};
if (serverside === true) {
return null
}
//if (window !== undefined && window.location !== undefined && window.location.pathname === "/search") {
// return null
//}
const isCloud = (window.location.host === "localhost:3002" || window.location.host === "shuffler.io") ? true : (import.meta.env.VITE_IS_SSR === "true");
// if (window.location.pathname === "/docs" || window.location.pathname === "/apps" || window.location.pathname === "/usecases" ) {
// setModalOpen(false)
// }
// useEffect(() => {
// if (searchOpen) {
// var tarfield = document.getElementById("shuffle_search_field")
// tarfield.focus()
// }
// }, searchOpen)
const SearchBox = ({ currentRefinement, refine, isSearchStalled, }) => {
const [inputValue, setInputValue] = useState(currentRefinement);
const textFieldRef = useRef(null);
const debounceTimeoutRef = useRef(null);
const keyPressHandler = (e) => {
if (e.key === "Enter") {
e.preventDefault();
// navigate(`/search?q=${currentRefinement}`, { state: value, replace: true });
// setModalOpen(false);
const trimmedValue = inputValue.trim();
if (trimmedValue !== '') {
navigate(`/search?q=${trimmedValue}`, { state: trimmedValue, replace: true });
setSearchBarModalOpen(false);
}
}
};
useEffect(() => {
if (searchOpen && textFieldRef.current) {
textFieldRef.current.focus();
}
}, [searchOpen]);
useEffect(() => {
// Clear any existing timeout to prevent multiple executions
if (debounceTimeoutRef.current) {
clearTimeout(debounceTimeoutRef.current);
}
// Set a new timeout that will execute the search after a 200ms delay
debounceTimeoutRef.current = setTimeout(() => {
refine(inputValue);
setSearchOpen(inputValue.trim() !== '');
}, 200);
// Cleanup function that runs when component unmounts or when dependencies change
// This ensures we don't have any hanging timeouts
return () => {
if (debounceTimeoutRef.current) {
clearTimeout(debounceTimeoutRef.current);
}
};
}, [inputValue, refine]); // Effect runs when inputValue or refine function changes
return (
)
}
const WorkflowHits = ({ hits }) => {
const [mouseHoverIndex, setMouseHoverIndex] = useState(0)
var tmp = searchOpen
if (!searchOpen) {
return null
}
const positionInfo = document.activeElement.getBoundingClientRect()
const outerlistitemStyle = {
width: "100%",
overflowX: "hidden",
overflowY: "hidden",
borderBottom: "1px solid rgba(255,255,255,0.4)",
}
if (hits.length > 4) {
hits = hits.slice(0, 4)
}
var type = "workflows"
const baseImage =
return (
Workflows
{hits.length === 0 ?
console.log(hits)}>
:
hits.map((hit, index) => {
const innerlistitemStyle = {
width: positionInfo.width + 35,
overflowX: "hidden",
overflowY: "hidden",
borderBottom: "1px solid rgba(255,255,255,0.4)",
backgroundColor: mouseHoverIndex === index ? theme.palette.hoverColor : "inherit",
cursor: "pointer",
marginLeft: 5,
marginRight: 5,
maxHeight: 75,
minHeight: 75,
maxWidth: 420,
minWidth: "100%",
}
const name = hit.name === undefined ?
hit.filename.charAt(0).toUpperCase() + hit.filename.slice(1).replaceAll("_", " ") + " - " + hit.title :
(hit.name.charAt(0).toUpperCase() + hit.name.slice(1)).replaceAll("_", " ")
const secondaryText = hit.description !== undefined && hit.description !== null && hit.description.length > 3 ? hit.description.slice(0, 40) + "..." : ""
const appGroup = hit.action_references === undefined || hit.action_references === null ? [] : hit.action_references
const avatar = baseImage
var parsedUrl = isCloud ? `/workflows/${hit.objectID}` : `https://shuffler.io/workflows/${hit.objectID}`
parsedUrl += `?queryID=${hit.__queryID}`
const validated = hit.validated !== undefined && hit.validate !== null ? hit.validated : false
//
return (
{
//console.log("CLICK")
setSearchOpen(true)
setSearchBarModalOpen(false)
aa('init', {
appId: searchClient.appId,
apiKey: searchClient.transporter.queryParameters["x-algolia-api-key"]
})
const timestamp = new Date().getTime()
aa('sendEvents', [
{
eventType: 'click',
eventName: 'Workflow Clicked',
index: 'workflows',
objectIDs: [hit.objectID],
timestamp: timestamp,
queryID: hit.__queryID,
positions: [hit.__position],
userToken: userdata === undefined || userdata === null || userdata.id === undefined ? "unauthenticated" : userdata.id,
}
])
if (!isCloud) {
event.preventDefault()
window.open(parsedUrl, '_blank');
}
}}>
{
setMouseHoverIndex(index)
}}>
{validated === true ?
:
{avatar}
}
{appGroup.map((app, index) => {
// Putting all this in secondary of ListItemText looked weird.
return (
{
navigate("/apps/" + app.id)
}}
>
)
})}
{/*
*/}
)
})
}
{/*
See all workflows
*/}
)
}
const activateApp = (name, appid, type) => {
if (globalUrl === undefined || globalUrl === null) {
console.log(`Global URL not set`)
return
}
if (name === undefined || name === null) {
name = ""
}
name = name.replaceAll("_", " ")
if (userdata === undefined || userdata === null || userdata.id === undefined) {
toast(`You need to be logged in to activate the ${name} app. Redirecting`)
setTimeout(() => {
navigate(`/register?message=You need to be logged in to use the ${name} app.`)
}, 500)
return
}
const url = `${globalUrl}/api/v1/apps/${appid}/${type}`
fetch(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
credentials: "include",
})
.then((response) => {
if (response.status !== 200) {
toast(`Failed to ${type} the app for your organization. Please try again or contact ${supportEmail}`)
}
return response.json()
})
.then((responseJson) => {
if (responseJson.success === false) {
toast(`Failed to ${type} the app for your organization. Please try again or contact ${supportEmail} for more info`)
} else {
toast(`App successfully ${type}d. It may now be used in your workflows.`)
}
})
.catch(error => {
//toast(error.toString())
console.log("Activate app error: ", error.toString())
});
}
const AppHits = ({ hits }) => {
const [mouseHoverIndex, setMouseHoverIndex] = useState(0)
var tmp = searchOpen
if (!searchOpen) {
return null
}
const positionInfo = document.activeElement.getBoundingClientRect()
const outerlistitemStyle = {
width: "100%",
overflowX: "hidden",
overflowY: "hidden",
borderBottom: "1px solid rgba(255,255,255,0.4)",
}
if (hits.length > 4) {
hits = hits.slice(0, 4)
}
var type = "app"
const baseImage =
return (
{/* {
setSearchOpen(false)
}}>
*/}
Apps
{hits.length === 0 ?
console.log(hits)}>
:
hits.map((hit, index) => {
const innerlistitemStyle = {
width: positionInfo.width + 35,
overflowX: "hidden",
overflowY: "hidden",
borderBottom: "1px solid rgba(255,255,255,0.4)",
backgroundColor: mouseHoverIndex === index ? theme.palette.hoverColor : "inherit",
cursor: "pointer",
marginLeft: 5,
marginRight: 5,
maxHeight: 75,
minHeight: 75,
maxWidth: 420,
minWidth: "100%",
}
const name = hit.name === undefined ?
hit.filename.charAt(0).toUpperCase() + hit.filename.slice(1).replaceAll("_", " ") + " - " + hit.title :
(hit.name.charAt(0).toUpperCase() + hit.name.slice(1)).replaceAll("_", " ")
var secondaryText = hit.data !== undefined ? hit.data.slice(0, 40) + "..." : ""
const avatar = hit.image_url === undefined ?
baseImage
:
//console.log(hit)
if (hit.categories !== undefined && hit.categories !== null && hit.categories.length > 0) {
secondaryText = hit.categories.slice(0, 3).map((data, index) => {
if (index === 0) {
return data
}
return ", " + data
/*
{
//handleChipClick
}}
variant="outlined"
color="primary"
/>
*/
})
}
var parsedUrl = isCloud ? `/apps/${hit.objectID}` : `/apps/${hit.objectID}`
parsedUrl += `?queryID=${hit.__queryID}`
return (
{
setSearchOpen(true)
setSearchBarModalOpen(false)
aa('init', {
appId: searchClient.appId,
apiKey: searchClient.transporter.queryParameters["x-algolia-api-key"]
})
const timestamp = new Date().getTime()
aa('sendEvents', [
{
eventType: 'click',
eventName: 'App Clicked',
index: 'appsearch',
objectIDs: [hit.objectID],
timestamp: timestamp,
queryID: hit.__queryID,
positions: [hit.__position],
userToken: userdata === undefined || userdata === null || userdata.id === undefined ? "unauthenticated" : userdata.id,
}
])
if (!isCloud) {
event.preventDefault()
window.open(parsedUrl, '_blank');
}
}}>
{
setMouseHoverIndex(index)
}}>
{avatar}
{/*
*/}
)
})
}
{/*
See more
*/}
)
}
const DocHits = ({ hits }) => {
const [mouseHoverIndex, setMouseHoverIndex] = useState(0)
var tmp = searchOpen
if (!searchOpen) {
return null
}
const positionInfo = document.activeElement.getBoundingClientRect()
const outerlistitemStyle = {
width: "100%",
overflowX: "hidden",
overflowY: "hidden",
borderBottom: "1px solid rgba(255,255,255,0.4)",
}
if (hits.length > 4) {
if(!isDocSearchModal) {
hits = hits.slice(0, 4)
} else {
hits = hits.slice(0, 15)
}
}
const type = "documentation"
const baseImage =
//console.log(type, hits.length, hits)
return (
{/* {
setSearchOpen(false)
}}>
*/}
{
!isDocSearchModal && (
Documentation
)
}
{/*
{
setSearchOpen(false)
}}>
*/}
{hits.length === 0 ?
console.log(hits)}>
:
hits.map((hit, index) => {
const innerlistitemStyle = {
width: positionInfo.width + 35,
overflowX: "hidden",
overflowY: "hidden",
borderBottom: "1px solid rgba(255,255,255,0.4)",
backgroundColor: mouseHoverIndex === index ? theme.palette.hoverColor : "inherit",
cursor: "pointer",
marginLeft: 5,
marginRight: 5,
maxHeight: isDocSearchModal ? 100 : 75,
minHeight: isDocSearchModal ? 100 : 75,
maxWidth: 420,
minWidth: "100%",
}
var name = hit.name === undefined ?
hit.filename.charAt(0).toUpperCase() + hit.filename.slice(1).replaceAll("_", " ") + " - " + hit.title
:
(hit.name.charAt(0).toUpperCase() + hit.name.slice(1)).replaceAll("_", " ")
if (name.length > 30) {
if(isDocSearchModal) {
name = name.slice(0, 70) + "..."
} else {
name = name.slice(0, 30) + "..."
}
}
const secondaryText = hit.data !== undefined ? hit.data.slice(0, 80) + "..." : ""
const avatar = hit.image_url === undefined ?
baseImage
:
var parsedUrl = hit.urlpath !== undefined ? hit.urlpath : ""
parsedUrl += `?queryID=${hit.__queryID}`
if (parsedUrl.includes("/apps/")) {
const extraHash = hit.url_hash === undefined ? "" : `#${hit.url_hash}`
parsedUrl = `/apps/${hit.filename}`
parsedUrl += `?tab=docs&queryID=${hit.__queryID}${extraHash}`
}
return (
{
aa('init', {
appId: searchClient.appId,
apiKey: searchClient.transporter.queryParameters["x-algolia-api-key"]
})
const timestamp = new Date().getTime()
aa('sendEvents', [
{
eventType: 'click',
eventName: 'Document Clicked',
index: 'documentation',
objectIDs: [hit.objectID],
timestamp: timestamp,
queryID: hit.__queryID,
positions: [hit.__position],
userToken: userdata === undefined || userdata === null || userdata.id === undefined ? "unauthenticated" : userdata.id,
}
])
console.log("CLICK")
setSearchOpen(true)
setSearchBarModalOpen(false)
}}>
{
setMouseHoverIndex(index)
}}>
{avatar}
{secondaryText}}
/>
{/*
*/}
)
})
}
)
}
const DiscordHits = ({ hits }) => {
const [mouseHoverIndex, setMouseHoverIndex] = useState(0);
var tmp = searchOpen
if (!searchOpen) {
return null
}
const positionInfo = document.activeElement.getBoundingClientRect()
const outerlistitemStyle = {
width: "100%",
overflowX: "hidden",
overflowY: "hidden",
borderBottom: "1px solid rgba(255,255,255,0.4)",
}
if (hits.length > 4) {
hits = hits.slice(0, 4)
}
const type = "Discord Text"
const handleHitClick = (url) => {
const modifiedUrl = url.replace('https://ptb.discord.com/', 'https://discord.com/');
window.open(modifiedUrl, '_blank');
};
return (
Discord Chat
{hits.length === 0 ?
console.log(hits)}>
:
hits.map((chat, index) => (
handleHitClick(chat.url)} key={index} style={{ cursor: "pointer", borderBottom: "1px solid rgba(255,255,255,0.4)" }} onMouseOver={() => setMouseHoverIndex(index)}>
))}
);
};
const gettingStartData = !searchOpen ? (
Getting Started
Popular searches
Create Apps
Find Apps
Workflows
Creator
) : null
const CustomSearchBox = connectSearchBox(SearchBox)
const CustomAppHits = connectHits(AppHits)
const CustomWorkflowHits = connectHits(WorkflowHits)
const CustomDocHits = connectHits(DocHits)
const CustomDiscordHits = connectHits(DiscordHits);
const modalView = (
{
!isDocSearchModal ? (
) : (
)
}
)
return (
{
console.log("CLICKED")
}}>
{modalView}
{!isDocSearchModal && gettingStartData}
)
}
export default SearchData;