diff --git a/frontend/src/components/AppGrid.jsx b/frontend/src/components/AppGrid.jsx
index 5bb08119..c75f2449 100644
--- a/frontend/src/components/AppGrid.jsx
+++ b/frontend/src/components/AppGrid.jsx
@@ -1,289 +1,1912 @@
-import React, {useEffect, useState} from 'react';
+import React, { useEffect, useState, useRef } from "react";
-import theme from '../theme.jsx';
-import ReactGA from 'react-ga4';
-import {Link} from 'react-router-dom';
-import { removeQuery } from '../components/ScrollToTop.jsx';
+import theme from "../theme.jsx";
+import ReactGA from "react-ga4";
+import { Link } from "react-router-dom";
+import { removeQuery } from "../components/ScrollToTop.jsx";
+import { useMemo } from "react";
-import {
- Search as SearchIcon,
- CloudQueue as CloudQueueIcon,
- Code as CodeIcon
-} from '@mui/icons-material';
+import { Tabs, Tab } from "@mui/material";
+import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
+import ExpandLessIcon from "@mui/icons-material/ExpandLess";
+import {
+ Search as SearchIcon,
+ CloudQueue as CloudQueueIcon,
+ Code as CodeIcon,
+} from "@mui/icons-material";
+import { toast } from "react-toastify"
+import ClearIcon from '@mui/icons-material/Clear';
+import Box from '@mui/material/Box';
-import algoliasearch from 'algoliasearch/lite';
-import { InstantSearch, Configure, connectSearchBox, connectHits, connectHitInsights } from 'react-instantsearch-dom';
+import noImage from "../no_image.png"
-import aa from 'search-insights'
+import CircularProgress from '@mui/material/CircularProgress';
-import {
- Zoom,
- Grid,
- Paper,
- TextField,
- ButtonBase,
- InputAdornment,
- Typography,
- Button,
- Tooltip
-} from '@mui/material';
+import algoliasearch from "algoliasearch/lite";
+import {
+ InstantSearch,
+ Configure,
+ connectSearchBox,
+ connectHits,
+ connectHitInsights,
+ RefinementList,
+ ClearRefinements,
+ connectStateResults
+} from "react-instantsearch-dom";
-const searchClient = algoliasearch("JNSS5CFDZZ", "db08e40265e2941b9a7d8f644b6e5240")
+import aa from "search-insights";
+
+import "./FilterCSS.css";
+
+import {
+ Zoom,
+ Grid,
+ Paper,
+ TextField,
+ ButtonBase,
+ InputAdornment,
+ Typography,
+ Button,
+ Tooltip,
+} from "@mui/material";
+
+const searchClient = algoliasearch(
+ "JNSS5CFDZZ",
+ "db08e40265e2941b9a7d8f644b6e5240"
+);
//const searchClient = algoliasearch("L55H18ZINA", "a19be455e7e75ee8f20a93d26b9fc6d6")
-const AppGrid = props => {
- const { maxRows, showName, showSuggestion, isMobile, globalUrl, parsedXs, userdata, isHeader } = props
+
+const AppGrid = (props) => {
+ const {
+ maxRows,
+ showName,
+ showSuggestion,
+ isMobile,
+ globalUrl,
+ parsedXs,
+ isHeader,
+ } = props;
const isCloud =
window.location.host === "localhost:3002" ||
window.location.host === "shuffler.io";
- const rowHandler = maxRows === undefined || maxRows === null ? 50 : maxRows
- const xs = parsedXs === undefined || parsedXs === null ? isMobile ? 6 : 2 : parsedXs
- //const [apps, setApps] = React.useState([]);
- //const [filteredApps, setFilteredApps] = React.useState([]);
- const [formMail, setFormMail] = React.useState("");
- const [message, setMessage] = React.useState("");
- const [formMessage, setFormMessage] = React.useState("");
+ const rowHandler = maxRows === undefined || maxRows === null ? 50 : maxRows;
+ const xs =
+ parsedXs === undefined || parsedXs === null ? (isMobile ? 6 : 3) : parsedXs;
- const buttonStyle = {borderRadius: 30, height: 50, width: 220, margin: isMobile ? "15px auto 15px auto" : 20, fontSize: 18,}
+ const [formMail, setFormMail] = React.useState("");
+ const [message, setMessage] = React.useState("");
+ const [formMessage, setFormMessage] = React.useState("");
- const innerColor = "rgba(255,255,255,0.65)"
- const borderRadius = 3
- window.title = "Shuffle | Apps | Find and integrate any app"
+ const buttonStyle = {
+ borderRadius: 30,
+ height: 50,
+ width: 220,
+ margin: isMobile ? "15px auto 15px auto" : 20,
+ fontSize: 18,
+ };
+ const innerColor = "rgba(255,255,255,0.65)";
+ const borderRadius = 3;
+ window.title = "Shuffle | Apps | Find and integrate any app";
- const submitContact = (email, message) => {
- const data = {
- "firstname": "",
- "lastname": "",
- "title": "",
- "companyname": "",
- "email": email,
- "phone": "",
- "message": message,
- }
-
- const errorMessage = "Something went wrong. Please contact frikky@shuffler.io directly."
- fetch(globalUrl+"/api/v1/contact", {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify(data),
- })
- .then(response => response.json())
- .then(response => {
- if (response.success === true) {
- setFormMessage(response.reason)
- //toast("Thanks for submitting!")
- } else {
- setFormMessage(errorMessage)
- }
+ const submitContact = (email, message) => {
+ const data = {
+ firstname: "",
+ lastname: "",
+ title: "",
+ companyname: "",
+ email: email,
+ phone: "",
+ message: message,
+ };
- setFormMail("")
- setMessage("")
+ const errorMessage =
+ "Something went wrong. Please contact frikky@shuffler.io directly.";
+
+ fetch(globalUrl + "/api/v1/contact", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify(data),
})
- .catch(error => {
- setFormMessage(errorMessage)
- console.log(error)
- });
- }
+ .then((response) => response.json())
+ .then((response) => {
+ if (response.success === true) {
+ setFormMessage(response.reason);
+ //toast("Thanks for submitting!")
+ } else {
+ setFormMessage(errorMessage);
+ }
- const SearchBox = ({currentRefinement, refine, isSearchStalled} ) => {
- var defaultSearch = ""
- //useEffect(() => {
- if (window !== undefined && window.location !== undefined && window.location.search !== undefined && window.location.search !== null) {
- const urlSearchParams = new URLSearchParams(window.location.search)
- const params = Object.fromEntries(urlSearchParams.entries())
- const foundQuery = params["q"]
- if (foundQuery !== null && foundQuery !== undefined) {
- console.log("Got query: ", foundQuery)
- refine(foundQuery)
- defaultSearch = foundQuery
- }
- }
- //}, [])
+ setFormMail("");
+ setMessage("");
+ })
+ .catch((error) => {
+ setFormMessage(errorMessage);
+ console.log(error);
+ });
+ };
- return (
-
- )
- }
+ var [searchQuery, setSearchQuery] = useState("");
- var workflowDelay = -50
- const Hits = ({ hits, insights }) => {
- const [mouseHoverIndex, setMouseHoverIndex] = useState(-1)
- var counted = 0
+ //useEffect(() => {
+ if (
+ window !== undefined &&
+ window.location !== undefined &&
+ window.location.search !== undefined &&
+ window.location.search !== null
+ ) {
+ const urlSearchParams = new URLSearchParams(window.location.search);
+ const params = Object.fromEntries(urlSearchParams.entries());
+ const foundQuery = params["q"];
+ if (foundQuery !== null && foundQuery !== undefined) {
+ console.log("Got query: ", foundQuery);
+ refine(foundQuery);
+ defaultSearch = foundQuery;
+ searchQuery = foundQuery
+ }
+ }
+ //}, [])
- //console.log(hits)
- //var curhits = hits
- //if (hits.length > 0 && defaultApps.length === 0) {
- // setDefaultApps(hits)
- //}
- //const [defaultApps, setDefaultApps] = React.useState([])
- //console.log(hits)
- //if (hits.length > 0 && hits.length !== innerHits.length) {
- // setInnerHits(hits)
- //}
+ const handleSearch = () => {
+ refine(searchQuery.trim());
+ };
- return (
-
- {hits.map((data, index) => {
+ return (
+
+ );
+ };
- const paperStyle = {
- backgroundColor: index === mouseHoverIndex ? "rgba(255,255,255,0.8)" : theme.palette.inputColor,
- color: index === mouseHoverIndex ? theme.palette.inputColor : "rgba(255,255,255,0.8)",
- border: `1px solid ${innerColor}`,
- padding: isHeader ? null : 15,
- cursor: "pointer",
- position: "relative",
- minHeight: 116,
- }
-
- if (counted === 12/xs*rowHandler) {
- return null
- }
+ const [currTab, setCurrTab] = useState(0);
- counted += 1
- var parsedname = ""
- for (var key = 0; key < data.name.length; key++) {
- var character = data.name.charAt(key)
- if (character === character.toUpperCase()) {
- //console.log(data.name[key], data.name[key+1])
- if (data.name.charAt(key+1) !== undefined && data.name.charAt(key+1) === data.name.charAt(key+1).toUpperCase()) {
- } else {
- parsedname += " "
- }
- }
+ const handleTabChange = (event, newValue) => {
+ setCurrTab(newValue);
+ };
- parsedname += character
- }
-
- parsedname = (parsedname.charAt(0).toUpperCase()+parsedname.substring(1)).replaceAll("_", " ")
- const appUrl = isCloud ? `/apps/${data.objectID}?queryID=${data.__queryID}` : `https://shuffler.io/apps/${data.objectID}?queryID=${data.__queryID}`
- return (
-
-
-
- {
- setMouseHoverIndex(index)
- /*
- ReactGA.event({
- category: "app_grid_view",
- action: `search_bar_click`,
- label: "",
- })
- */
- }} onMouseOut={() => {
- setMouseHoverIndex(-1)
- }} onClick={() => {
- if (isCloud) {
- ReactGA.event({
- category: "app_grid_view",
- action: `app_${parsedname}_${data.id}_click`,
- label: "",
- })
- }
+ const [isLoggedIn, setIsLoggedIn] = useState(false);
+ const [userInfo, setUserInfo] = useState([]);
- //const searchClient = algoliasearch("L55H18ZINA", "a19be455e7e75ee8f20a93d26b9fc6d6")
- console.log(searchClient)
- aa('init', {
- appId: searchClient.appId,
- apiKey: searchClient.transporter.queryParameters["x-algolia-api-key"]
- })
+ useEffect(() => {
+ var baseurl = globalUrl;
+ fetch(baseurl + "/api/v1/getinfo", {
+ credentials: "include",
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ })
+ .then(response => response.json())
+ .then(responseJson => {
+ if (responseJson.success) {
+ setIsLoggedIn(true);
+ setUserInfo(responseJson);
+ }
+ })
+ .catch(error => {
+ console.log("Failed login check: ", error);
+ });
+ }, []);
- const timestamp = new Date().getTime()
- aa('sendEvents', [
- {
- eventType: 'click',
- eventName: 'Product Clicked',
- index: 'appsearch',
- objectIDs: [data.objectID],
- timestamp: timestamp,
- queryID: data.__queryID,
- positions: [data.__position],
- userToken: userdata === undefined || userdata === null || userdata.id === undefined ? "unauthenticated" : userdata.id,
- }
- ])
+ //Component to fetch all app from the algolia
+ const Hits = ({
+ hits,
+ insights,
+ setIsAnyAppActivated
+ }) => {
+ const [mouseHoverIndex, setMouseHoverIndex] = useState(-1);
+ var counted = 0;
+ const [hoverEffect, setHoverEffect] = useState(-1);
- }}>
-
-
-
-
- {index === mouseHoverIndex || showName === true ?
- parsedname
- :
- null
- }
- {data.generated ?
-
- {data.invalid ?
-
- :
-
- }
-
- :
-
-
-
- }
-
-
-
-
- )
- })}
-
- )
- }
+ const normalizedString = (name) => {
+ if (typeof name === 'string') {
+ return name.replace(/_/g, ' ');
+ } else {
+ return name;
+ }
+ };
- const CustomSearchBox = connectSearchBox(SearchBox)
- const CustomHits = connectHits(Hits)
- //const CustomHits = connectHitInsights(aa)(Hits)
- const selectButtonStyle = {
- minWidth: 150,
- maxWidth: 150,
- minHeight: 50,
- }
+ const [allActivatedAppIds, setAllActivatedAppIds] = useState(() => {
+ const storedApps = isLoggedIn && localStorage.getItem('allActivatedAppIds');
+ return storedApps ? JSON.parse(storedApps) : userInfo.active_apps;
+ });
+ const [isAppActivated, setIsAppActivated] = useState(false);
+ const [isActivateAppSuccess, setIsActivateAppSuccess] = useState(false);
- return (
-
- {/*
+ //Function for activation and deactivation of app
+ const handleActivateButton = (event, data, type) => {
+ event.preventDefault();
+ if (!isLoggedIn) {
+ toast.error("Please log in to your account to activate the app.")
+ return;
+ }
+ if (type === "activate") {
+ toast.success(`The ${normalizedString(data.name)} app is activating. Please wait...`);
+ }
+ if (type === "deactivate") {
+ toast.success(`The ${normalizedString(data.name)} app is deactivating. Please wait...`);
+ }
+
+ const baseURL = globalUrl;
+ const url = `${baseURL}/api/v1/apps/${data.objectID}/${type}`;
+
+ fetch(url, {
+ method: 'GET',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json',
+ },
+ credentials: "include",
+ })
+ .then((response) => response.json())
+ .then((responseJson) => {
+ if (responseJson.success === false) {
+ toast.error(responseJson.reason);
+ } else {
+ toast.success(`App ${type}d Successfully!`);
+ if (type === 'activate') {
+ setAllActivatedAppIds(prev => [...prev, data.objectID]);
+ setIsAnyAppActivated(true);
+ }
+ if (type === 'deactivate') {
+ const updatedIds = allActivatedAppIds.filter(id => id !== data.objectID);
+ setAllActivatedAppIds(updatedIds);
+ }
+ setIsActivateAppSuccess(prev => !prev);
+ }
+ })
+ .catch(error => {
+ console.log("app error: ", error.toString());
+ });
+ }
+
+ useEffect(() => {
+ isLoggedIn && localStorage.setItem('allActivatedAppIds', JSON.stringify(allActivatedAppIds));
+ }, [allActivatedAppIds]);
+
+
+ const memoizedHits = useMemo(() => {
+ return hits.map((data, index) => {
+ let workflowDelay = 0;
+ const isHeader = true;
+ const paperStyle = {
+ color: "rgba(241, 241, 241, 1)",
+ padding: isHeader ? null : 15,
+ cursor: "pointer",
+ maxWidth: 339,
+ maxHeight: 96,
+ borderRadius: 8,
+ transition: 'background-color 0.3s ease',
+ backgroundColor: "rgba(26, 26, 26, 1)",
+ };
+
+ const appUrl =
+ isCloud
+ ? `/apps/${data.objectID}?queryID=${data.__queryID}`
+ : `https://shuffler.io/apps/${data.objectID}?queryID=${data.__queryID}`;
+
+ //check if appExist in userInfo.active_app or not.
+ return (
+
+
+
+ {
+ setMouseHoverIndex(index);
+ }}
+ onMouseOut={() => {
+ setMouseHoverIndex(-1);
+ }}
+ >
+
+
+
+
+ {(allActivatedAppIds && allActivatedAppIds.includes(data.objectID)) && }
+ {normalizedString(data.name)}
+
+
+
+ {data.categories !== null
+ ? normalizedString(data.categories).join(", ")
+ : "NA"}
+
+
+
+ {mouseHoverIndex === index ? (
+
+ {data.tags && (
+
+
+ {data.tags.slice(0, 1).map((tag, tagIndex) => (
+
+ {normalizedString(tag)}
+ {tagIndex < 1 ? ", " : ""}
+
+ ))}
+
+
+ )}
+
+ ) : (
+
+ {data.tags &&
+ data.tags.map((tag, tagIndex) => (
+
+ {normalizedString(tag)}
+ {tagIndex < data.tags.length - 1 ? ", " : ""}
+
+ ))}
+
+ )}
+
+
+ {mouseHoverIndex === index && (
+
+ {allActivatedAppIds && allActivatedAppIds.includes(data.objectID) ? (
+ {
+ handleActivateButton(event, data, "deactivate");
+ }}>
+ Deactivate
+
+ ) : (
+ {
+ handleActivateButton(event, data, "activate");
+ }}
+ >
+ Activate
+
+ )}
+
+ )}
+
+
+
+
+
+
+
+
+ );
+ });
+ }, [hits, mouseHoverIndex, isActivateAppSuccess, allActivatedAppIds]);
+
+ return (
+
+
+ {memoizedHits}
+
+
+ );
+ };
+
+ var workflowDelay = -50;
+
+ const CustomClearRefinements = connectStateResults(({ searchResults, ...rest }) => {
+ const hasFilters = searchResults && searchResults.nbHits !== searchResults.nbSortedHits;
+ return
Clear All }} {...rest} disabled={!hasFilters} />;
+ });
+
+ //Component to Filter all apps base on category
+ const FilterAllAppsByCategory = () => {
+ const [isRefinementListExpanded, setIsRefinementListExpanded] =
+ useState(true);
+
+ const toggleRefinementList = () => {
+ setIsRefinementListExpanded((prevState) => !prevState);
+ };
+
+ const categoryButtonStyling = {
+ cursor: "pointer",
+ color: "white",
+ border: "none",
+ backgroundColor: "transparent",
+ fontSize: 16,
+ display: "flex",
+ width: "100%",
+ height: 30,
+ flexDirection: "row",
+ textTransform: 'none',
+ fontFamily: "var(--zds-typography-base,Inter,Helvetica,arial,sans-serif)"
+ }
+
+ return (
+
+
+ Category
+ {isRefinementListExpanded ? (
+
+ ) : (
+
+ )}
+
+
+ {isRefinementListExpanded && (
+ <>
+
+
+ >
+ )}
+
+ );
+ };
+
+ //Component to filter all apps base on Action label
+ const FilterByActionLabel = () => {
+ const [isActionLabelExpanded, setIsActionLabelExpanded] = useState(false);
+ useState(false);
+
+ const toogleActionLabel = () => {
+ setIsActionLabelExpanded((prevState) => !prevState);
+ };
+
+ const actionLabelButtonStyling = {
+ cursor: "pointer",
+ color: "white",
+ border: "none",
+ backgroundColor: "transparent",
+ fontSize: 16,
+ display: "flex",
+ flexDirection: "row",
+ width: "100%",
+ height: 30,
+ textTransform: 'none',
+ fontWeight: 400
+ }
+
+
+ return (
+
+
+ Labels
+ {isActionLabelExpanded ? (
+
+ ) : (
+
+ )}
+
+
+ {isActionLabelExpanded && (
+ <>
+
+
+ >
+ )}
+
+ );
+ };
+
+ //component to filter all apps base on the created with like 'App Editor' or 'Python'
+ const FilterByCreatedWith = () => {
+ const [isCreatedWithExpanded, setIsCreatedWithExpanded] = useState(false);
+
+ const toogleCreatedWith = () => {
+ setIsCreatedWithExpanded((prevState) => !prevState);
+ };
+
+ const transformRefinementListItems = items =>
+ items.map(item => ({
+ ...item,
+ label: item.label === 'true' ? 'App Editor' : 'Python',
+ }));
+
+ const createdWithButtonStyling = {
+ cursor: "pointer",
+ color: "white",
+ border: "none",
+ backgroundColor: "transparent",
+ fontSize: 16,
+ display: "flex",
+ flexDirection: "row",
+ alignItems: "center",
+ width: "100%",
+ height: 30,
+ textTransform: 'none',
+ fontWeight: 400
+ }
+
+ return (
+
+
+ Created With
+ {isCreatedWithExpanded ? : }
+
+
+ {isCreatedWithExpanded && (
+ <>
+
+
+ >
+ )}
+
+ );
+ };
+
+ const FilterCreatedBy = () => {
+ const [isCreatedByExpanded, setIscreatedByExpanded] = useState(false);
+ useState(false);
+
+ const toogleCreatedBy = () => {
+ setIscreatedByExpanded((prevState) => !prevState);
+ };
+
+ const createdByButtonStyling = {
+ cursor: "pointer",
+ color: "white",
+ border: "none",
+ backgroundColor: "transparent",
+ fontSize: 16,
+ display: "flex",
+ flexDirection: "row",
+ alignItems: "center",
+ whiteSpace: "nowrap",
+ width: "100%",
+ height: 30,
+ textTransform: 'none',
+ opacity: '0.5'
+ }
+
+ return (
+
+
+ Created By
+ {isCreatedByExpanded ? (
+
+ ) : (
+
+ )}
+
+
+ {isCreatedByExpanded && (
+ <>
+ {/* */}
+
+ {/* */}
+
+ Clear All
+
+ >
+ )}
+
+ );
+ };
+
+ const FilterApps = () => {
+ return (
+
+
+ Filter By
+
+
+
+
+
+
+ );
+ };
+
+
+
+ const boxStyle = {
+ color: "white",
+ flex: "1",
+ marginLeft: isHeader ? null : 10,
+ marginRight: isHeader ? null : 10,
+ paddingLeft: isHeader ? null : 30,
+ paddingRight: isHeader ? null : 30,
+ paddingBottom: isHeader ? null : 30,
+ display: "flex",
+ flexDirection: "column",
+ overflowX: "visible",
+ backgroundColor: "rgba(33, 33, 33, 1)",
+ borderRadius: 16,
+ marginTop: 24,
+ width: 741,
+ height: 741,
+ };
+
+
+ //Component to display all apps.
+ const AllApps = ({ setIsAnyAppActivated }) => {
+
+ return (
+
+
+
+
+ );
+ };
+
+ //Search box for the orgs and users apps
+ const SearchBoxForOrgsAndUsersApp = ({ searchQuery, setSearchQuery }) => {
+
+ return (
+
+ )
+ }
+
+
+
+ const [selectedCategoryForUsersAndOgsApps, setselectedCategoryForUsersAndOgsApps] = useState([]);
+ const [selectedTagsForUserAndOrgApps, setSelectedTagsForUserAndOrgApps] = useState([]);
+ const [isCategoreListExpanded, setIsCategoryListExpanded] = useState(true);
+
+ const toogleCategoryList = () => {
+ setIsCategoryListExpanded((prevState) => !prevState);
+ };
+
+ //Component to display category List for User and Orgs app
+ const FilterUsersAndOrgsAppByCategory = ({ userAndOrgsApp }) => {
+
+ //Display top 9 category from the database
+
+ const findTopCategories = () => {
+ const categoryCountMap = {};
+
+ // Check if userAndOrgsApp is an array before iterating over it and Find top 10 Category from the apps
+ if (Array.isArray(userAndOrgsApp)) {
+ userAndOrgsApp.forEach((app) => {
+ const categories = app.categories;
+
+ if (categories && categories.length > 0) {
+ categories.forEach((category) => {
+ categoryCountMap[category] = (categoryCountMap[category] || 0) + 1;
+ });
+ }
+ });
+
+ const categoryArray = Object.keys(categoryCountMap).map((category) => ({
+ category,
+ count: categoryCountMap[category],
+ }));
+
+ categoryArray.sort((a, b) => b.count - a.count);
+
+ const topCategories = categoryArray.slice(0, 9);
+
+ return topCategories;
+ }
+ };
+
+ const topCategories = findTopCategories();
+
+ const handleCheckboxChange = (category) => {
+ if (selectedCategoryForUsersAndOgsApps.includes(category)) {
+ setselectedCategoryForUsersAndOgsApps(selectedCategoryForUsersAndOgsApps.filter((item) => item !== category));
+ } else {
+ setselectedCategoryForUsersAndOgsApps([...selectedCategoryForUsersAndOgsApps, category]);
+ }
+ };
+
+ const handleClearFilter = () => {
+ setselectedCategoryForUsersAndOgsApps([]);
+ };
+
+ const categorysButtonStyling = {
+ cursor: "pointer",
+ color: "white",
+ border: "none",
+ backgroundColor: "transparent",
+ fontSize: 16,
+ display: "flex",
+ width: "100%",
+ height: 30,
+ flexDirection: "row",
+ textTransform: 'none',
+ fontFamily: "var(--zds-typography-base,Inter,Helvetica,arial,sans-serif)"
+ }
+ return (
+
+
+ Category
+ {isCategoreListExpanded ? (
+
+ ) : (
+
+ )}
+
+ {isCategoreListExpanded && topCategories && topCategories.length > 0 && (
+
+ {topCategories.map((data, index) => (
+ handleCheckboxChange(data.category)}
+ >
+ handleCheckboxChange(data.category)}
+ style={{ marginRight: 5 }}
+ />
+ {data.category}
+
+
+ ))}
+
+
+ Clear All
+
+
+ )}
+
+ );
+ };
+
+ const [isActionLabelExpanded, setIsActionLabelExpanded] = useState(false);
+ const toogleActionLabel = () => {
+ setIsActionLabelExpanded((prevState) => !prevState);
+ };
+
+ const FilterUsersAndOrgsAppByActionLabel = ({ userAndOrgsApp }) => {
+
+ const findTopTags = () => {
+ const tagCountMap = {};
+
+ // Check if userAndOrgsApp is an array before iterating over it and Find top 10 tags from the apps
+ if (Array.isArray(userAndOrgsApp)) {
+ userAndOrgsApp.forEach((app) => {
+ const tags = app.tags;
+
+ if (tags && tags.length > 0) {
+ tags.forEach((tag) => {
+ tagCountMap[tag] = (tagCountMap[tag] || 0) + 1;
+ });
+ }
+ });
+ }
+
+ const tagArray = Object.keys(tagCountMap).map((tag) => ({
+ tag,
+ count: tagCountMap[tag],
+ }));
+
+ tagArray.sort((a, b) => b.count - a.count);
+
+ const topTags = tagArray.slice(0, 9);
+
+ return topTags;
+ };
+
+ const topTags = findTopTags();
+ const [selectedCategories, setSelectedCategories] = useState([]);
+
+ const handleCheckboxChange = (index) => {
+ const category = topTags[index].tag;
+ const updatedCheckboxStates = [...selectedTagsForUserAndOrgApps];
+
+ if (updatedCheckboxStates.includes(category)) {
+ setSelectedTagsForUserAndOrgApps(updatedCheckboxStates.filter((item) => item !== category));
+ } else {
+ setSelectedTagsForUserAndOrgApps([...updatedCheckboxStates, category]);
+ }
+ };
+
+ const handleClearFilter = () => {
+ setSelectedTagsForUserAndOrgApps([]);
+ };
+
+ const actionLabelButtonStyling = {
+ cursor: "pointer",
+ color: "white",
+ border: "none",
+ backgroundColor: "transparent",
+ fontSize: 16,
+ display: "flex",
+ flexDirection: "row",
+ width: "100%",
+ height: 30,
+ textTransform: 'none',
+ marginBottom: isActionLabelExpanded && 16,
+ fontFamily: "var(--zds-typography-base,Inter,Helvetica,arial,sans-serif)"
+ }
+
+ return (
+
+
+ Labels
+ {isActionLabelExpanded ? (
+
+ ) : (
+
+ )}
+
+
+ {isActionLabelExpanded && topTags && topTags.length > 0 && (
+ <>
+ {topTags.map((data, index) => (
+ handleCheckboxChange(index)}
+ >
+ handleCheckboxChange(index)}
+ style={{ marginRight: 5 }}
+ />
+ {data.tag}
+
+
+ ))}
+
+
+ Clear All
+
+ >
+ )}
+
+ );
+ };
+
+ const [selectedOptionOfCreatedWith, setSelectedOptionOfCreatedWith] = useState([]);
+ const [isCreatedWithExpanded, setIsCreatedWithExpanded] = useState(false);
+
+ const toogleCreatedWith = () => {
+ setIsCreatedWithExpanded((prevState) => !prevState);
+ };
+ const FilterUsersAndOrgsAppByCreatedWith = () => {
+
+ const AppCreatedWithOptions = ['App Editor', 'Python']
+
+ const handleCheckboxChange = (index) => {
+ const category = AppCreatedWithOptions[index];
+ const updatedCheckboxStates = [...selectedOptionOfCreatedWith];
+ if (updatedCheckboxStates.includes(category)) {
+ setSelectedOptionOfCreatedWith(updatedCheckboxStates.filter((item) => item !== category));
+ } else {
+ setSelectedOptionOfCreatedWith([...updatedCheckboxStates, category]);
+ }
+ };
+
+
+ const handleClearFilter = () => {
+ setSelectedOptionOfCreatedWith([]);
+ };
+
+ const createdWithButtonStyling = {
+ cursor: "pointer",
+ color: "white",
+ border: "none",
+ backgroundColor: "transparent",
+ fontSize: 16,
+ display: "flex",
+ flexDirection: "row",
+ alignItems: "center",
+ width: "100%",
+ height: 30,
+ textTransform: 'none',
+ marginBottom: isCreatedWithExpanded && 16,
+ fontFamily: "var(--zds-typography-base,Inter,Helvetica,arial,sans-serif)"
+ }
+
+ return (
+
+
+ Created With
+ {isCreatedWithExpanded ? : }
+
+
+ {isCreatedWithExpanded && (
+ <>
+ {AppCreatedWithOptions.map((data, index) => (
+ handleCheckboxChange(index)}
+ >
+ handleCheckboxChange(index)}
+ style={{ marginRight: 5 }}
+ />
+ {data}
+
+
+ ))}
+
+
+ Clear All
+
+ >
+ )}
+
+ );
+ };
+
+ const FilterUsersAndOrgsAppCreatedBy = () => {
+
+ const [isCreatedByExpanded, setIscreatedByExpanded] = useState(false);
+ useState(false);
+
+ const toogleCreatedBy = () => {
+ setIscreatedByExpanded((prevState) => !prevState);
+ };
+ const [isButtonDisable, setIsButtonDisable] = useState(true)
+
+ const createdByButtonStyling = {
+ cursor: "pointer",
+ color: "white",
+ border: "none",
+ backgroundColor: isButtonDisable ? '#3c3c3c. ' : "transparent",
+ fontSize: 16,
+ display: "flex",
+ flexDirection: "row",
+ alignItems: "center",
+ whiteSpace: "nowrap",
+ width: "100%",
+ height: 30,
+ textTransform: 'none',
+ opacity: '0.5'
+ }
+
+ return (
+
+
+ Created By
+ {isCreatedByExpanded ? (
+
+ ) : (
+
+ )}
+
+
+ {isCreatedByExpanded && (
+ <>
+
+
+ Clear All
+
+ >
+ )}
+
+ );
+ };
+
+ const FilterUserAndOrgApps = () => {
+
+ const [userAndOrgsApp, setUserAndOrgsApp] = useState([]);
+
+ useEffect(() => {
+ if (currTab === 2) {
+ const baseUrl = globalUrl;
+ const userAppsUrl = `${baseUrl}/api/v1/users/apps`;
+ fetch(userAppsUrl, {
+ method: "GET",
+ credentials: "include",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ })
+ .then((response) => response.json())
+ .then((data) => {
+ setUserAndOrgsApp(data);
+ })
+ .catch((err) => {
+ console.error("Error fetching user apps:", err);
+ });
+ } else if (currTab === 1) {
+ const baseUrl = globalUrl;
+ const appsUrl = `${baseUrl}/api/v1/apps`;
+ fetch(appsUrl, {
+ method: "GET",
+ credentials: "include",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ })
+ .then((response) => response.json())
+ .then((data) => {
+ setUserAndOrgsApp(data);
+ })
+ .catch((err) => {
+ console.error("Error fetching apps:", err);
+ });
+ }
+ }, [currTab]);
+
+
+ return (
+
+ {isLoggedIn === true && (
+
+
+ Filter By
+
+
+
+
+
+
+ )}
+
+ )
+ }
+ const [isLoading, setIsLoading] = useState(false)
+ useEffect(() => {
+ if (currTab) {
+ setselectedCategoryForUsersAndOgsApps([]);
+ setSelectedTagsForUserAndOrgApps([]);
+ setSelectedOptionOfCreatedWith([]);
+ setIsCategoryListExpanded(true);
+ setIsActionLabelExpanded(false);
+ setIsCreatedWithExpanded(false);
+ }
+ if (currTab === 1 || currTab === 2) {
+ setIsLoading(true);
+ }
+
+ }, [currTab])
+
+ //Component to fetch all apps created by user and Org
+ const UserAndOrgApps = () => {
+
+ const [searchQuery, setSearchQuery] = useState("");
+ const [userAndOrgAppData, setUserAndOrgAppData] = useState([])
+
+ const allActivatedAppIdsString = localStorage.getItem('allActivatedAppIds');
+ const allActivatedAppIds = allActivatedAppIdsString ? JSON.parse(allActivatedAppIdsString) : [];
+ const latestActivatedAppId = allActivatedAppIds.length > 0 ? allActivatedAppIds[allActivatedAppIds.length - 1] : null;
+
+ useEffect(() => {
+ if (currTab === 2 && isLoggedIn != undefined && isLoggedIn != null && isLoggedIn === true) {
+ const baseUrl = globalUrl;
+ const URL = `${baseUrl}/api/v1/users/apps`;
+ fetch(URL, {
+ method: "GET",
+ credentials: "include",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ })
+ .then((response) => {
+ return response.json();
+ })
+ .then((data) => {
+ setUserAndOrgAppData(data)
+ setIsLoading(false)
+ })
+ .catch((err) => {
+ console.error("Error fetching user apps:", err);
+ });
+ }
+ else if (currTab === 1 && isLoggedIn != undefined && isLoggedIn != null && isLoggedIn === true) {
+ const baseUrl = globalUrl;
+ const URL = `${baseUrl}/api/v1/apps`;
+ fetch(URL, {
+ method: "GET",
+ credentials: "include",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ })
+ .then((response) => {
+ return response.json();
+ })
+ .then((data) => {
+ setUserAndOrgAppData(data)
+ setIsLoading(false);
+ })
+ .catch((err) => {
+ console.error("Error fetching user apps:", err);
+ });
+ }
+ }, [])
+
+ //Search app base on app name, category and tag
+ const filteredUserAppdata = Array.isArray(userAndOrgAppData) ? userAndOrgAppData.filter((app) => {
+ const matchesSearchQuery = (
+ searchQuery === "" ||
+ app.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
+ (app.tags && app.tags.some(tag =>
+ tag.toLowerCase().includes(searchQuery.toLowerCase())
+ )) ||
+ (app.categories && app.categories.some((category) =>
+ category.toLowerCase().includes(searchQuery.toLowerCase())
+ ))
+ );
+
+ const matchesSelectedCategories = (
+ selectedCategoryForUsersAndOgsApps.length === 0 ||
+ (app.categories && app.categories.some(category =>
+ selectedCategoryForUsersAndOgsApps.includes(category)
+ ))
+ );
+ const matchesSelectedTags = (
+ selectedTagsForUserAndOrgApps.length === 0 ||
+ (app.tags && selectedTagsForUserAndOrgApps.some(tag =>
+ app.tags.includes(tag)
+ ))
+ );
+
+ const matchesSelectedOption = (
+ selectedOptionOfCreatedWith.length === 0 ||
+ selectedOptionOfCreatedWith.includes('App Editor') && app.generated === true ||
+ selectedOptionOfCreatedWith.includes('Python') && app.generated === false
+ );
+
+ return matchesSearchQuery && matchesSelectedCategories && matchesSelectedTags && matchesSelectedOption;
+ }) : [];
+
+
+ const [mouseHoverIndex, setMouseHoverIndex] = useState(-1);
+ var counted = 0;
+
+ const memoizedHits = useMemo(() => {
+ return filteredUserAppdata.map((data, index) => {
+ const isMouseOverOnCloudIcon = false;
+ const xs = 12;
+ const rowHandler = 12;
+ const searchClient = {};
+ const userdata = {};
+
+ const paperStyle = {
+ backgroundColor: "#1A1A1A",
+ color: "rgba(241, 241, 241, 1)",
+ padding: isHeader ? null : 15,
+ cursor: "pointer",
+ position: "relative",
+ width: 339,
+ height: 96,
+ borderRadius: 8,
+ };
+
+ var parsedname = "";
+ for (var key = 0; key < data.name.length; key++) {
+ var character = data.name.charAt(key);
+ if (character === character.toUpperCase()) {
+ if (
+ data.name.charAt(key + 1) !== undefined &&
+ data.name.charAt(key + 1) ===
+ data.name.charAt(key + 1).toUpperCase()
+ ) {
+ } else {
+ parsedname += " ";
+ }
+ }
+ parsedname += character;
+ }
+
+ parsedname = (
+ parsedname.charAt(0).toUpperCase() + parsedname.substring(1)
+ ).replaceAll("_", " ");
+
+ const normalizedString = (name) => {
+ if (typeof name === 'string') {
+ return name.replace(/_/g, ' ');
+ } else {
+ return name;
+ }
+ };
+
+ const appUrl =
+ isCloud === false
+ ? `/apps/${data.id}`
+ : `https://shuffler.io/apps/${data.id}`;
+
+ return (
+
+
+
+ {
+ setMouseHoverIndex(index);
+ }}
+ onMouseOut={() => {
+ setMouseHoverIndex(-1);
+ }}
+ >
+
+
+
+
+ {normalizedString(data.name)}
+
+
+ {data.categories !== null
+ ? normalizedString(data.categories).join(", ")
+ : "NA"}
+
+
+ {data.tags &&
+ data.tags.map((tag, tagIndex) => (
+
+ {normalizedString(tag)}
+ {tagIndex < data.tags.length - 1 ? ", " : ""}
+
+ ))}
+
+ {/* )} */}
+
+
+
+
+
+
+ );
+ });
+ }, [filteredUserAppdata, latestActivatedAppId]);
+
+
+ return (
+
+ {isLoggedIn ? (
+
+ {isLoading ?
: (
+
+
+
+
+ {memoizedHits}
+
+
+
+ )}
+
+ ) : (
+
+
Please login to your account first to view {`${currTab === 1 ? "Organization" : "My"}`} Apps.
+ Or signup to create a new account.
+
+ )}
+
+ );
+ };
+
+
+ const AppTab = () => {
+
+ const [isAnyAppActivated, setIsAnyAppActivated] = useState(false);
+
+ return (
+
+
+
+
+ {isAnyAppActivated && }Organization Apps
+ sx={{
+ color: currTab === 1 ? "#F86743" : "inherit",
+ border: 'none',
+ height: 44,
+ fontSize: 16,
+ flex: 1,
+ textTransform: 'none',
+ fontWeight: 400,
+ paddingBottom: 3,
+ fontFamily: "var(--zds-typography-base,Inter,Helvetica,arial,sans-serif)",
+ }}
+ >
+
+
+
+ {currTab === 0 ? (
+
+ ) : currTab === 1 || currTab === 2 ? (
+
+ ) : null}
+
+
+ );
+ };
+
+ const CustomSearchBox = connectSearchBox(SearchBox);
+ const CustomHits = connectHits(Hits);
+ return (
+
+ {/*
{
*/}
-
-
-
-
-
-
-
-
- {showSuggestion === true ?
-
-
- Can't find what you're looking for?
-
-
- setFormMail(e.target.value)}
- />
- setMessage(e.target.value)}
- />
-
-
{
- submitContact(formMail, message)
- }}
- >
- Submit
-
-
{formMessage}
-
- : null
- }
-
-
-
- Search by
-
-
-
-
-
-
-
- )
-}
+
+
+
+ {currTab === 0 ?
:
}
+
+
+ {/* */}
+
+
+ {showSuggestion === true ? (
+
+
+ Can't find what you're looking for?
+
+
+ setFormMail(e.target.value)}
+ />
+ setMessage(e.target.value)}
+ />
+
+
{
+ submitContact(formMail, message);
+ }}
+ >
+ Submit
+
+
+ {formMessage}
+
+
+ ) : null}
+
+
+ );
+};
export default AppGrid;
diff --git a/frontend/src/components/Billing.jsx b/frontend/src/components/Billing.jsx
index d3a65927..8602911c 100644
--- a/frontend/src/components/Billing.jsx
+++ b/frontend/src/components/Billing.jsx
@@ -43,7 +43,7 @@ import BillingStats from "../components/BillingStats.jsx";
import { handlePayasyougo } from "../views/HandlePaymentNew.jsx"
const Billing = (props) => {
- const { globalUrl, userdata, serverside, billingInfo, stripeKey, selectedOrganization, handleGetOrg, } = props;
+ const { globalUrl, userdata, serverside, billingInfo, stripeKey, selectedOrganization, handleGetOrg, clickedFromOrgTab } = props;
//const alert = useAlert();
let navigate = useNavigate();
@@ -970,21 +970,29 @@ const Billing = (props) => {
const isChildOrg = userdata.active_org.creator_org !== "" && userdata.active_org.creator_org !== undefined && userdata.active_org.creator_org !== null
return (
-
+
{addDealModal}
+ {clickedFromOrgTab?
+
Billing & Licensing :
Billing & Licensing
-
+ }
+ {clickedFromOrgTab?
+
{isCloud ?
+ "Get more out of Shuffle by adding your credit card, such as no App Run limitations, and priority support from our team. We use Stripe to manage subscriptions and do not store any of your billing information. You can manage your subscription and billing information below."
+ :
+ "Shuffle is an Open Source automation platform, and no license is required. We do however offer a Scale license with HA guarantees, along with support hours. By buying a license on https://shuffler.io, you can get access to the license immediately, and if Cloud Syncronisation is enabled, the UI in your local instance will also update."
+ } :
{isCloud ?
"Get more out of Shuffle by adding your credit card, such as no App Run limitations, and priority support from our team. We use Stripe to manage subscriptions and do not store any of your billing information. You can manage your subscription and billing information below."
:
"Shuffle is an Open Source automation platform, and no license is required. We do however offer a Scale license with HA guarantees, along with support hours. By buying a license on https://shuffler.io, you can get access to the license immediately, and if Cloud Syncronisation is enabled, the UI in your local instance will also update."
}
-
+ }
{userdata.support === true ?
-
+
For sales: Create
New Cloud Contract
diff --git a/frontend/src/components/Branding.jsx b/frontend/src/components/Branding.jsx
index c3c32058..48466476 100644
--- a/frontend/src/components/Branding.jsx
+++ b/frontend/src/components/Branding.jsx
@@ -103,8 +103,8 @@ const Branding = (props) => {
}
return (
-
-
+
+
Branding
diff --git a/frontend/src/components/CacheView.jsx b/frontend/src/components/CacheView.jsx
index 4e4f2fdd..22500fe2 100644
--- a/frontend/src/components/CacheView.jsx
+++ b/frontend/src/components/CacheView.jsx
@@ -115,43 +115,6 @@ const CacheView = (props) => {
});
};
- // const getCacheList = (orgId) => {
- // fetch(`${globalUrl}/api/v1/orgs/${orgId}/get_cache`, {
- // method: "GET",
- // headers: {
- // "Content-Type": "application/json",
- // Accept: "application/json",
- // },
- // credentials: "include",
- // })
- // .then((response) => {
- // if (response.status !== 200) {
- // console.log("Status not 200 for WORKFLOW EXECUTION :O!");
- // }
-
-
- // return response.json();
- // })
- // .then((responseJson) => {
- // if (responseJson.success !== false) {
- // console.log("Found cache: ", responseJson)
- // setListCache(responseJson)
- // } else {
- // console.log("Couldn't find the creator profile (rerun?): ", responseJson)
- // // If the current user is any of the Shuffle Creators
- // // AND the workflow doesn't have an owner: allow editing.
- // // else: Allow suggestions?
- // //console.log("User: ", userdata)
- // //if (rerun !== true) {
- // // getUserProfile(userdata.id, true)
- // //}
- // }
- // })
- // .catch((error) => {
- // console.log("Get userprofile error: ", error);
- // })
- // }
-
const deleteCache = (orgId, key) => {
toast("Attempting to delete Cache");
@@ -403,7 +366,7 @@ const CacheView = (props) => {
{
@@ -416,7 +379,7 @@ const CacheView = (props) => {
Add Cache
listOrgCache(orgId)}
@@ -433,26 +396,27 @@ const CacheView = (props) => {
{listCache === undefined || listCache === null
? null
: listCache.map((data, index) => {
- var bgColor = "#27292d";
+ var bgColor = isSelectedDataStore? "#212121":"#27292d";
if (index % 2 === 0) {
- bgColor = "#1f2023";
+ bgColor = isSelectedDataStore? "#1A1A1A":"#1f2023";
}
const validate = validateJson(data.value);
@@ -460,16 +424,16 @@ const CacheView = (props) => {
{
onClick={() => {
upload.click();
}}
- style={{backgroundColor: isSelectedFiles?'rgba(255, 132, 68, 0.2)':null, color:isSelectedFiles?"#FF8444":null, borderRadius:isSelectedFiles?200:null, width:isSelectedFiles?162:null, height:isSelectedFiles?40:null}}
+ style={{backgroundColor: isSelectedFiles?'rgba(255, 132, 68, 0.2)':null, color:isSelectedFiles?"#FF8444":null, borderRadius:isSelectedFiles?200:null, width:isSelectedFiles?162:null, height:isSelectedFiles?40:null, boxShadow: isSelectedFiles?'none':null,}}
>
Upload files
@@ -679,7 +679,7 @@ const Files = (props) => {
}}
/>
getFiles()}
@@ -814,7 +814,7 @@ const Files = (props) => {
/>
{
return null;
}
- var bgColor = "#27292d";
+ var bgColor = isSelectedFiles ? "#212121":"#27292d";
if (index % 2 === 0) {
- bgColor = "#1f2023";
+ bgColor = isSelectedFiles ? "#1A1A1A":"#1f2023";
}
const filenamesplit = file.filename.split(".")
@@ -855,8 +855,8 @@ const Files = (props) => {
>
{
minWidth: 100,
maxWidth: 100,
overflow: "hidden",
+ textAlign: isSelectedFiles?"center":null
}}
/>
{
minWidth: 75,
maxWidth: 75,
overflow: "hidden",
+ textAlign:isSelectedFiles?"center":null,
marginLeft: 10,
}}
/>
@@ -1064,7 +1068,7 @@ const Files = (props) => {
diff --git a/frontend/src/components/Priorities.jsx b/frontend/src/components/Priorities.jsx
index 1c0b27a2..e73374bd 100644
--- a/frontend/src/components/Priorities.jsx
+++ b/frontend/src/components/Priorities.jsx
@@ -203,7 +203,7 @@ const Priorities = (props) => {
{
}
return (
-
+
Suggestions
Suggestions are tasks identified by Shuffle to help you discover ways to protect your and customers' company. These range from simple configurations in Shuffle to Usecases you may have missed.
diff --git a/frontend/src/components/Priority.jsx b/frontend/src/components/Priority.jsx
index c1ecb4d7..67d56af7 100644
--- a/frontend/src/components/Priority.jsx
+++ b/frontend/src/components/Priority.jsx
@@ -147,7 +147,7 @@ const Priority = (props) => {
}
-
{
+ {
if (isCloud) {
ReactGA.event({
@@ -173,7 +173,7 @@ const Priority = (props) => {
Explore
{priority.active === true ?
- {
+ {
// dismiss -> get envs
changeRecommendation(priority, "dismiss")
}}>
diff --git a/frontend/src/views/Search.jsx b/frontend/src/views/Search.jsx
index b19050c7..687e392f 100644
--- a/frontend/src/views/Search.jsx
+++ b/frontend/src/views/Search.jsx
@@ -1,206 +1,316 @@
-import React, { useState, useEffect } from "react";
+import React, { useState, useEffect, useMemo } from "react";
-import theme from '../theme.jsx';
+import theme from "../theme.jsx";
import { isMobile } from "react-device-detect";
-import AppGrid from "../components/AppGrid.jsx"
-import WorkflowGrid from "../components/WorkflowGrid.jsx"
-import CreatorGrid from "../components/CreatorGrid.jsx"
-import DocsGrid from "../components/DocsGrid.jsx"
-import DiscordChat from "../components/DiscordChat.jsx";
+import AppGrid from "../components/AppGrid.jsx";
+import WorkflowGrid from "../components/WorkflowGrid.jsx";
+import CreatorGrid from "../components/CreatorGrid.jsx";
+import DocsGrid from "../components/DocsGrid.jsx";
import { useNavigate } from "react-router-dom";
+import Typography from "@material-ui/core/Typography";
+import { Tabs, Tab, setRef } from "@mui/material";
+import { styled } from "@mui/material/styles";
+import { makeStyles } from '@mui/styles';
+import DiscordChat from "../components/DiscordChat.jsx";
import {
- Tabs,
- Tab,
-} from "@mui/material";
-
-import {
- Apps as AppsIcon,
- Code as CodeIcon,
- Chat as ChatIcon,
- EmojiObjects as EmojiObjectsIcon,
- Description as DescriptionIcon,
+ Apps as AppsIcon,
+ Code as CodeIcon,
+ EmojiObjects as EmojiObjectsIcon,
+ Chat as ChatIcon,
+ BorderBottom,
} from "@mui/icons-material";
+import PeopleAltOutlinedIcon from '@mui/icons-material/PeopleAltOutlined';
+import DescriptionOutlinedIcon from '@mui/icons-material/DescriptionOutlined';
// Should be different if logged in :|
const Search = (props) => {
- const { globalUrl, isLoaded, serverside, userdata, hidemargins, isHeader } = props;
- let navigate = useNavigate();
+ const { globalUrl, isLoaded, serverside, userdata, hidemargins, isHeader } =
+ props;
+ let navigate = useNavigate();
- const [curTab, setCurTab] = useState(0);
- const iconStyle = { marginRight: isHeader ? null : 10 };
+ const [curTab, setCurTab] = useState(0);
+ const iconStyle = { marginRight: isHeader ? null : 10 };
- useEffect(() => {
- if (serverside !== true && window.location.search !== undefined && window.location.search !== null) {
- const urlSearchParams = new URLSearchParams(window.location.search)
- const params = Object.fromEntries(urlSearchParams.entries())
- const foundTab = params["tab"]
- if (foundTab !== null && foundTab !== undefined) {
- for (var key in Object.keys(views)) {
- const value = views[key]
- console.log(key, value)
- if (value === foundTab) {
- setConfig("", key)
- break
- }
- }
- }
- }
- }, [])
+ useEffect(() => {
+ if (
+ serverside !== true &&
+ window.location.search !== undefined &&
+ window.location.search !== null
+ ) {
+ const urlSearchParams = new URLSearchParams(window.location.search);
+ const params = Object.fromEntries(urlSearchParams.entries());
+ const foundTab = params["tab"];
+ if (foundTab !== null && foundTab !== undefined) {
+ for (var key in Object.keys(views)) {
+ const value = views[key];
+ console.log(key, value);
+ if (value === foundTab) {
+ setConfig("", key);
+ break;
+ }
+ }
+ }
+ }
+ }, []);
- if (serverside === true) {
- return null
- }
+ //Stop unnecessariry re-rendering of the component to improve performace
+ const MemoizedAppGrid = useMemo(() => , [curTab]);
- const bodyDivStyle = {
- margin: "auto",
- maxWidth: 1024,
- scrollX: "hidden",
- overflowX: "hidden",
- justifyContent: isHeader ? "center" : null,
- }
+const MemoizedWorkflowGrid = useMemo(() => , [curTab]);
- const boxStyle = {
- color: "white",
- flex: "1",
- marginLeft: isHeader ? null : 10,
- marginRight: isHeader ? null : 10,
- paddingLeft: isHeader ? null : 30,
- paddingRight: isHeader ? null : 30,
- paddingBottom: isHeader ? null : 30,
- paddingTop: hidemargins === true ? 0 : isHeader ? null : 30,
- display: "flex",
- flexDirection: "column",
- overflowX: "hidden",
- minHeight: 400,
- }
+const MemoizedDocsGrid = useMemo(() => , [curTab]);
- const views = {
- 0: "apps",
- 1: "workflows",
- 2: "docs",
- 3: "creators",
- 4: "discord",
- }
+const MemoizedCreatorGrid = useMemo(() => , [curTab]);
- const setConfig = (event, inputValue) => {
- const newValue = parseInt(inputValue)
+ const MemoizedDiscordChat = useMemo(() => )
- setCurTab(newValue)
- if (newValue === 0) {
- document.title = "Shuffle - search - apps";
- } else if (newValue === 1) {
- document.title = "Shuffle - search - workflows";
- } else if (newValue === 2) {
- document.title = "Shuffle - search - documentation";
- } else if (newValue === 3) {
- document.title = "Shuffle - search - creators";
- } else if (newValue === 4) {
- document.title = "Shuffle - search - Discord Chat";
- }else {
- document.title = "Shuffle - search";
- }
+const useStyles = makeStyles({
+ hideIndicator: {
+ display: 'none',
+ },
+ customTab: {
+ justifyContent: 'center',
+ gap: '46px',
+ }
+});
+const classes = useStyles();
+ if (serverside === true) {
+ return null;
+ }
- const urlSearchParams = new URLSearchParams(window.location.search)
- const params = Object.fromEntries(urlSearchParams.entries())
- const foundQuery = params["q"]
- var extraQ = ""
- if (foundQuery !== null && foundQuery !== undefined) {
- extraQ = "&q=" + foundQuery
- }
+ const bodyDivStyle = {
+ margin: "auto",
+ maxWidth: "100%",
+ scrollX: "hidden",
+ overflowX: "hidden",
+ justifyContent: isHeader ? "center" : null,
+ };
+ const boxStyle = {
+ color: "white",
+ flex: "1",
+ marginLeft: isHeader ? null : 10,
+ marginRight: isHeader ? null : 10,
+ paddingLeft: isHeader ? null : 30,
+ paddingRight: isHeader ? null : 30,
+ paddingBottom: isHeader ? null : 30,
+ paddingTop: hidemargins === true ? 0 : isHeader ? null : 30,
+ display: "flex",
+ flexDirection: "column",
+ overflowX: "hidden",
+ width: "100%",
+ minHeight: 400,
+ };
- if ((serverside === false || serverside === undefined) && window.location.pathname.includes("/search")) {
- navigate(`/search?tab=${views[newValue]}` + extraQ)
- }
- }
+ const views = {
+ 0: "apps",
+ 1: "workflows",
+ 2: "docs",
+ 3: "creators",
+ };
+ const setConfig = (event, inputValue) => {
+ const newValue = parseInt(inputValue);
- if (isLoaded === false) {
- return null
- }
+ setCurTab(newValue);
+ if (newValue === 0) {
+ document.title = "Shuffle - search - apps";
+ } else if (newValue === 1) {
+ document.title = "Shuffle - search - workflows";
+ } else if (newValue === 2) {
+ document.title = "Shuffle - search - documentation";
+ } else if (newValue === 3) {
+ document.title = "Shuffle - search - creators";
+ } else {
+ document.title = "Shuffle - search";
+ }
+ const urlSearchParams = new URLSearchParams(window.location.search);
+ const params = Object.fromEntries(urlSearchParams.entries());
+ const foundQuery = params["q"];
+ var extraQ = "";
+ if (foundQuery !== null && foundQuery !== undefined) {
+ extraQ = "&q=" + foundQuery;
+ }
- // Random names for type & autoComplete. Didn't research :^)
- const landingpageDataBrowser =
-
-
-
-
- Apps
-
- />
-
- Workflows
-
- />
-
- Docs
-
- />
-
- Creators
-
- />
-
- Discord Chat
-
- />
+ if (
+ (serverside === false || serverside === undefined) &&
+ window.location.pathname.includes("/search")
+ ) {
+ navigate(`/search?tab=${views[newValue]}` + extraQ);
+ }
+ };
-
- {curTab === 0 ?
-
- :
- curTab === 1 ?
- window.location.pathname === "/search" ?
-
- :
-
- :
- curTab === 2 ?
-
- :
- curTab === 3 ?
-
- :
- curTab === 4 ?
-
-:
+ if (isLoaded === false) {
+ return null;
+ }
- null}
-
-
- //{/*alternativeView={true} />*/}
+ const StyledTab = styled(Tab)(({ theme }) => ({
+ width: 151,
+ height: 51,
+ padding: "10px 20px",
+ borderRadius: 8,
+ fontWeight: 600,
+ textTransform: "none",
+ border: 'none',
+ "&.Mui-selected": {
+ backgroundColor: theme.palette.primary.main,
+ color: theme.palette.common.white,
+ "& .MuiSvgIcon-root": {
+ color: theme.palette.common.white,
+ },
+ },
+ }));
- const loadedCheck = isLoaded ?
-
-
{landingpageDataBrowser}
-
- :
-
-
+ const tabSpanStyling = {
+ display: 'flex',
+ flexDirection: 'row',
+ alignItems: 'center'
+ }
- // #1f2023?
- return (
-
- {loadedCheck}
-
- )
-}
+ const tabTextStyling = {
+ marginLeft: '5px',
+ color: 'white'
+ }
+
+
+ // Random names for type & autoComplete. Didn't research :^)
+ const landingpageDataBrowser = (
+
+
+
+
+
+ App
+
+ }
+ />
+
+
+ Workflow
+
+ }
+ />
+
+
+ Docs
+
+ }
+ />
+
+
+ Creators
+
+ }
+ />
+
+
+ Discord Chat
+
+ }
+ />
+
+ {curTab === 0 && MemoizedAppGrid}
+ {curTab === 1 && MemoizedWorkflowGrid}
+ {curTab === 2 && MemoizedDocsGrid}
+ {curTab === 3 && MemoizedCreatorGrid}
+ {curTab === 4 && MemoizedDiscordChat}
+
+
+ );
+ //{/*alternativeView={true} />*/}
+
+ const loadedCheck = isLoaded ? (
+
+
{landingpageDataBrowser}
+
+ ) : (
+
+ );
+
+ // #1f2023?
+ return {loadedCheck}
;
+};
export default Search;