From e652d0039c84fe6dd73272ac7bce54adab3915ec Mon Sep 17 00:00:00 2001 From: monilprajapati Date: Sun, 1 Dec 2024 19:12:28 +0530 Subject: [PATCH] Done with the revamp of apps2 page : New look --- frontend/src/views/Apps2.jsx | 816 ++++++++++++++++++++--------------- 1 file changed, 468 insertions(+), 348 deletions(-) diff --git a/frontend/src/views/Apps2.jsx b/frontend/src/views/Apps2.jsx index 7011be79..0f395471 100644 --- a/frontend/src/views/Apps2.jsx +++ b/frontend/src/views/Apps2.jsx @@ -15,6 +15,7 @@ import { } from "@mui/material"; import { Context } from "../context/ContextApi.jsx"; import Add from '@mui/icons-material/Add'; +import EditIcon from '@mui/icons-material/Edit'; import InputAdornment from '@mui/material/InputAdornment'; import Search from '@mui/icons-material/Search'; import ClearIcon from '@mui/icons-material/Clear'; @@ -34,20 +35,23 @@ const searchClient = algoliasearch( ); // AppCard Component -const AppCard = ({ data, index, mouseHoverIndex, setMouseHoverIndex, globalUrl, deactivatedIndexes, currTab, handleAppClick }) => { +const AppCard = ({ data, index, mouseHoverIndex, setMouseHoverIndex, globalUrl, deactivatedIndexes, currTab, handleAppClick, leftSideBarOpenByClick, userdata }) => { const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io" || window.location.host === "localhost:3000"; const appUrl = isCloud ? `/apps/${data.id}` : `https://shuffler.io/apps/${data.id}`; + var canEditApp = userdata.admin === "true" || userdata.id === data?.owner || data?.owner === "" || (userdata.admin === "true" && userdata.active_org.id === data?.reference_org) || !data?.generated const paperStyle = { - backgroundColor: mouseHoverIndex === index ? "rgba(26, 26, 26, 1)" : "#1A1A1A", + backgroundColor: mouseHoverIndex === index ? "rgba(26, 26, 26, 1)" : "#212121", color: "rgba(241, 241, 241, 1)", cursor: "pointer", - position: "relative", - width: 365, + fontFamily: "Inter", + // position: "relative", + width: "100%", height: 96, borderRadius: 8, boxShadow: "0px 0px 10px 0px rgba(0, 0, 0, 0.1)", marginBottom: 20, + transition: "width 0.3s ease", }; return ( @@ -63,7 +67,7 @@ const AppCard = ({ data, index, mouseHoverIndex, setMouseHoverIndex, globalUrl, fontSize: 16, overflow: "hidden", display: "flex", - alignItems: "flex-start", + fontFamily: "Inter", width: '100%', backgroundColor: mouseHoverIndex === index ? "#2F2F2F" : "#212121" }} @@ -92,13 +96,14 @@ const AppCard = ({ data, index, mouseHoverIndex, setMouseHoverIndex, globalUrl, fontWeight: '400', overflow: "hidden", margin: "12px 0", - fontFamily: "var(--zds-typography-base,Inter,Helvetica,arial,sans-serif)" + fontFamily: "Inter" }}>
-
+
{data.generated !== true && data.tags && data.tags.slice(0, 2).map((tag, tagIndex) => ( {tag} @@ -134,44 +140,57 @@ const AppCard = ({ data, index, mouseHoverIndex, setMouseHoverIndex, globalUrl,
{/* Deactivate button */} {currTab === 0 && !deactivatedIndexes.includes(index) && mouseHoverIndex === index && data.generated === true && ( - + ) + } + + .then((response) => response.json()) + .then((responseJson) => { + if (responseJson.success === false) { + toast.error(responseJson.reason); + } else { + toast.success("App Deactivated Successfully. Reload UI to see updated changes."); + } + }) + .catch(error => { + console.log("app error: ", error.toString()); + }); + }} + > + Deactivate + +
)}
@@ -192,6 +211,7 @@ const Hits = ({ globalUrl, isLoading, isLoggedIn, + leftSideBarOpenByClick }) => { const [hoverEffect, setHoverEffect] = useState(-1); const [allActivatedAppIds, setAllActivatedAppIds] = useState(userdata?.active_apps); @@ -330,7 +350,7 @@ const Hits = ({ color: "rgba(241, 241, 241, 1)", cursor: "pointer", position: "relative", - width: 365, + width: leftSideBarOpenByClick ? 325 : 365, height: 96, borderRadius: 8, boxShadow: "0px 0px 10px 0px rgba(0, 0, 0, 0.1)", @@ -374,7 +394,6 @@ const Hits = ({ fontWeight: '400', overflow: "hidden", margin: "12px 0", - fontFamily: "var(--zds-typography-base,Inter,Helvetica,arial,sans-serif)" }} >
{data.categories !== null @@ -514,46 +533,7 @@ const Hits = ({ ); } -// Custom Category Dropdown Component -const CategoryDropdown = ({ items, currentRefinement, refine }) => { - const handleChange = (event) => { - const value = event.target.value; - refine(value); - }; - return ( - - ); -}; - -const CustomCategoryDropdown = connectRefinementList(CategoryDropdown); // Custom SearchBox Component const SearchBox = ({ refine, searchQuery, setSearchQuery }) => { @@ -608,10 +588,11 @@ const SearchBox = ({ refine, searchQuery, setSearchQuery }) => { event.preventDefault(); } }} - style={{ width: '100%', borderRadius: '7px', fontFamily: "var(--zds-typography-base,Inter,Helvetica,arial,sans-serif)" }} + style={{ borderRadius: 8, height: 45, fontFamily: "Inter", flex: 1 }} InputProps={{ style: { borderRadius: 8, + height: 45 }, endAdornment: ( @@ -637,6 +618,38 @@ const SearchBox = ({ refine, searchQuery, setSearchQuery }) => { const CustomSearchBox = connectSearchBox(SearchBox); const CustomHits = connectHits(Hits); +// Custom Category Dropdown Component +const CategoryDropdown = ({ items, currentRefinement, refine }) => { + const handleChange = (event) => { + const value = event.target.value; + refine(value); + }; + + return ( + + ); +}; +const CustomCategoryDropdown = connectRefinementList(CategoryDropdown); + // Custom Label Dropdown Component const LabelDropdown = ({ items, currentRefinement, refine }) => { const handleChange = (event) => { @@ -652,15 +665,7 @@ const LabelDropdown = ({ items, currentRefinement, refine }) => { onChange={handleChange} displayEmpty multiple - style={{ - width: '100%', - maxWidth: '300px', - borderRadius: '7px', - fontFamily: "var(--zds-typography-base,Inter,Helvetica,arial,sans-serif)", - overflow: 'hidden', - textOverflow: 'ellipsis', - whiteSpace: 'nowrap', - }} + style={{ borderRadius: 8, height: 45, fontFamily: "Inter", flex: 1 }} renderValue={(selected) => selected.length ? selected.join(', ') : 'All Labels'} > @@ -675,9 +680,44 @@ const LabelDropdown = ({ items, currentRefinement, refine }) => { ); }; - const CustomLabelDropdown = connectRefinementList(LabelDropdown); + + +// New filter function +const filterApps = (apps, searchQuery, selectedCategory, selectedLabel) => { + if (!Array.isArray(apps)) return []; + + return apps.filter((app) => { + const matchesSearchQuery = ( + searchQuery === "" || // If searchQuery is empty, match all apps + 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 = ( + selectedCategory.length === 0 || // If no category is selected, match all apps + (app.categories && app.categories.some(category => + selectedCategory.includes(category) + )) + ); + + const matchesSelectedTags = ( + selectedLabel.length === 0 || // If no label is selected, match all apps + (app.tags && app.tags.some(tag => + selectedLabel.includes(tag) + )) + ); + + return matchesSearchQuery && matchesSelectedCategories && matchesSelectedTags; + }); +}; + // Main Apps Component const Apps2 = (props) => { const { globalUrl, isLoaded, serverside, userdata, isLoggedIn, checkLogin } = props; @@ -803,14 +843,16 @@ const Apps2 = (props) => { } }, [currTab, globalUrl, userdata?.id]); // Remove location.search dependency - useEffect(() => { - setSearchQuery(""); - }, [currTab]) + // useEffect(() => { + // // setSearchQuery(""); + // setSelectedCategory([]); + // setSelectedLabel([]); + // }, [currTab]) // Find top categories and tags based on the current tab useEffect(() => { - if (currTab === 0) { + if (currTab === 0 || currTab === 1) { setCategories(findTopCategories()); setLabels(findTopTags()); } @@ -881,76 +923,81 @@ const Apps2 = (props) => { const handleCreateApp = (e) => { e.preventDefault(); - setOpenModal(true); + // setOpenModal(true); }; useEffect(() => { const apps = currTab === 1 ? userApps : orgApps; - // Search app based on app name, category, and tag - const filteredUserAppdata = Array.isArray(apps) ? apps.filter((app) => { - - const matchesSearchQuery = ( - searchQuery === "" || // If searchQuery is empty, match all apps - 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 = ( - selectedCategory.length === 0 || // If no category is selected, match all apps - (app.categories && app.categories.some(category => - selectedCategory.includes(category) - )) - ); - - const matchesSelectedTags = ( - selectedLabel.length === 0 || // If no label is selected, match all apps - (app.tags && app.tags.some(tag => - selectedLabel.includes(tag) - )) - ); - - return matchesSearchQuery && matchesSelectedCategories && matchesSelectedTags; - }) : []; - + const filteredUserAppdata = filterApps(apps, searchQuery, selectedCategory, selectedLabel); setAppsToShow(filteredUserAppdata); - }, [searchQuery, selectedCategory, selectedLabel]); + }, [searchQuery, selectedCategory, selectedLabel, currTab]); const handleTabChange = (newTab) => { setCurrTab(newTab); + // Apply filters immediately when changing tabs if (newTab === 0) { - setAppsToShow(orgApps) - const categories = findTopCategories(); - const labels = findTopTags(); - setCategories(categories); - setLabels(labels); - } - if (newTab === 1) { - setAppsToShow(userApps) + const filteredOrgApps = filterApps(orgApps, searchQuery, selectedCategory, selectedLabel); + setAppsToShow(filteredOrgApps); + } else if (newTab === 1) { + const filteredUserApps = filterApps(userApps, searchQuery, selectedCategory, selectedLabel); + setAppsToShow(filteredUserApps); } + + // Update URL query params const newQueryParam = newTab === 0 ? 'org_apps' : newTab === 1 ? 'my_apps' : 'all_apps'; const queryParams = new URLSearchParams(location.search); queryParams.set('tab', newQueryParam); - queryParams.delete('q'); + // Only remove 'q' param if search is empty + if (!searchQuery) { + queryParams.delete('q'); + } window.history.replaceState({}, '', `${location.pathname}?${queryParams.toString()}`); }; + // Update useEffect to handle initial load and URL search params + useEffect(() => { + const queryParams = new URLSearchParams(location.search); + const searchParam = queryParams.get('q'); + if (searchParam) { + setSearchQuery(searchParam); + } + }, []); + // Update useEffect for filtering to handle both tabs + useEffect(() => { + if (currTab === 2) return; // Skip for "Discover Apps" tab as it uses Algolia + const apps = currTab === 1 ? userApps : orgApps; + const filteredApps = filterApps(apps, searchQuery, selectedCategory, selectedLabel); + setAppsToShow(filteredApps); + + // Update URL with search query + const queryParams = new URLSearchParams(location.search); + if (searchQuery) { + queryParams.set('q', searchQuery); + } else { + queryParams.delete('q'); + } + window.history.replaceState({}, '', `${location.pathname}?${queryParams.toString()}`); + }, [searchQuery, selectedCategory, selectedLabel, currTab, userApps, orgApps]); + + // Update search input handler to maintain state across tabs + const handleSearchChange = (event) => { + const newSearchQuery = event.target.value; + setSearchQuery(newSearchQuery); + }; const boxStyle = { color: "white", display: "flex", flexDirection: "column", + height: "100%", width: "100%", margin: "auto", - maxWidth: "60%", + maxWidth: "70%", + fontFamily: "Inter", // padding: '20px 380px', }; @@ -975,214 +1022,287 @@ const Apps2 = (props) => { } return ( - - -
- - Apps - -
- handleTabChange(newTab)} - TabIndicatorProps={{ style: { height: '3px', borderRadius: 10 } }} - > - - - - -
-
-
+
+ + +
+ + Apps + +
+ handleTabChange(newTab)} + TabIndicatorProps={{ style: { height: '3px', borderRadius: 10 } }} + style={{ fontFamily: "Inter" }} + > + + + + +
+
+
+ { + (currTab === 0 || currTab === 1) && + { + if (event.key === "Enter") { + event.preventDefault(); + } + }} + limit={5} + InputProps={{ + style: { + borderRadius: 8, + height: 45 + }, + endAdornment: ( + + {searchQuery.length === 0 ? ( + + ) : ( + { + setSearchQuery(""); + }} + /> + )} + + ), + }} + /> + } + { + currTab === 2 && + + } +
+
+ {currTab === 2 ? ( + + ) : ( + <> + + {selectedCategory.length > 0 && ( + setSelectedCategory([])} + /> + )} + + )} +
+
+ {currTab === 2 ? ( + + ) : ( + <> + + {selectedLabel.length > 0 && ( + setSelectedLabel([])} + /> + )} + + )} +
+
+ +
+
+
+ { - (currTab === 0 || currTab === 1) && - { - setSearchQuery(event.target.value); - }} - onKeyDown={(event) => { - if (event.key === "Enter") { - event.preventDefault(); - } - }} - limit={5} - style={{ width: '100%', borderRadius: '7px', fontFamily: "var(--zds-typography-base,Inter,Helvetica,arial,sans-serif)" }} - InputProps={{ - style: { - borderRadius: 8, - }, - endAdornment: ( - - { - searchQuery.length === 0 ? : - } - - ), - }} - /> + currTab === 0 && ( +
+ {isLoading ? ( +
+ +
+ ) : ( + <> + {appsToShow?.length > 0 && appsToShow !== undefined && !isLoading ? ( +
+ {appsToShow.map((data, index) => ( + + ))} +
+ ) : ( +
+ +
+ )} + + )} +
+ ) } + { + currTab === 1 && ( +
+ {isLoading ? ( +
+ +
+ ) : ( + <> + {appsToShow?.length > 0 && appsToShow !== undefined ? ( +
+ {appsToShow.map((data, index) => ( + + ))} +
+ ) : ( +
+ No Apps Found +
+ )} + + )} +
+ ) + } + { currTab === 2 && - + }
-
- {currTab === 2 ? ( - - ) : ( - - )} -
-
- {currTab === 2 ? ( - - ) : ( - - )} -
-
- -
-
-
- - { - currTab === 0 && ( -
- {isLoading ? ( -
- -
- ) : ( - <> - {appsToShow?.length > 0 && appsToShow !== undefined && !isLoading ? ( -
- {appsToShow.map((data, index) => ( - - ))} -
- ) : ( -
- -
- )} - - )} -
- ) - } - { - currTab === 1 && ( -
- {isLoading ? ( -
- -
- ) : ( - <> - {appsToShow?.length > 0 && appsToShow !== undefined ? ( -
- {appsToShow.map((data, index) => ( - - ))} -
- ) : ( -
- No Apps Found -
- )} - - )} -
- ) - } - - { - currTab === 2 && - - } -
-
- - +
+ + +
); };