Done with the revamp of apps2 page : New look
This commit is contained in:
+261
-141
@@ -15,6 +15,7 @@ import {
|
|||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import { Context } from "../context/ContextApi.jsx";
|
import { Context } from "../context/ContextApi.jsx";
|
||||||
import Add from '@mui/icons-material/Add';
|
import Add from '@mui/icons-material/Add';
|
||||||
|
import EditIcon from '@mui/icons-material/Edit';
|
||||||
import InputAdornment from '@mui/material/InputAdornment';
|
import InputAdornment from '@mui/material/InputAdornment';
|
||||||
import Search from '@mui/icons-material/Search';
|
import Search from '@mui/icons-material/Search';
|
||||||
import ClearIcon from '@mui/icons-material/Clear';
|
import ClearIcon from '@mui/icons-material/Clear';
|
||||||
@@ -34,20 +35,23 @@ const searchClient = algoliasearch(
|
|||||||
);
|
);
|
||||||
|
|
||||||
// AppCard Component
|
// 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 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}`;
|
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 = {
|
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)",
|
color: "rgba(241, 241, 241, 1)",
|
||||||
cursor: "pointer",
|
cursor: "pointer",
|
||||||
position: "relative",
|
fontFamily: "Inter",
|
||||||
width: 365,
|
// position: "relative",
|
||||||
|
width: "100%",
|
||||||
height: 96,
|
height: 96,
|
||||||
borderRadius: 8,
|
borderRadius: 8,
|
||||||
boxShadow: "0px 0px 10px 0px rgba(0, 0, 0, 0.1)",
|
boxShadow: "0px 0px 10px 0px rgba(0, 0, 0, 0.1)",
|
||||||
marginBottom: 20,
|
marginBottom: 20,
|
||||||
|
transition: "width 0.3s ease",
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -63,7 +67,7 @@ const AppCard = ({ data, index, mouseHoverIndex, setMouseHoverIndex, globalUrl,
|
|||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
display: "flex",
|
display: "flex",
|
||||||
alignItems: "flex-start",
|
fontFamily: "Inter",
|
||||||
width: '100%',
|
width: '100%',
|
||||||
backgroundColor: mouseHoverIndex === index ? "#2F2F2F" : "#212121"
|
backgroundColor: mouseHoverIndex === index ? "#2F2F2F" : "#212121"
|
||||||
}}
|
}}
|
||||||
@@ -92,13 +96,14 @@ const AppCard = ({ data, index, mouseHoverIndex, setMouseHoverIndex, globalUrl,
|
|||||||
fontWeight: '400',
|
fontWeight: '400',
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
margin: "12px 0",
|
margin: "12px 0",
|
||||||
fontFamily: "var(--zds-typography-base,Inter,Helvetica,arial,sans-serif)"
|
fontFamily: "Inter"
|
||||||
}}>
|
}}>
|
||||||
<div style={{
|
<div style={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
textOverflow: "ellipsis",
|
textOverflow: "ellipsis",
|
||||||
|
fontWeight: 600,
|
||||||
whiteSpace: "nowrap",
|
whiteSpace: "nowrap",
|
||||||
marginLeft: 8,
|
marginLeft: 8,
|
||||||
gap: 8
|
gap: 8
|
||||||
@@ -118,13 +123,14 @@ const AppCard = ({ data, index, mouseHoverIndex, setMouseHoverIndex, globalUrl,
|
|||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
textOverflow: "ellipsis",
|
textOverflow: "ellipsis",
|
||||||
whiteSpace: "nowrap",
|
whiteSpace: "nowrap",
|
||||||
width: 230,
|
width: "100%",
|
||||||
textAlign: 'start',
|
|
||||||
marginLeft: 8,
|
marginLeft: 8,
|
||||||
color: "rgba(158, 158, 158, 1)",
|
color: "rgba(158, 158, 158, 1)",
|
||||||
display: "flex"
|
display: "flex",
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
paddingRight: 15,
|
||||||
}}>
|
}}>
|
||||||
<div style={{ minWidth: 120, overflow: "hidden" }}>
|
<div style={{ overflow: "hidden", textAlign: 'start' }}>
|
||||||
{data.generated !== true && data.tags && data.tags.slice(0, 2).map((tag, tagIndex) => (
|
{data.generated !== true && data.tags && data.tags.slice(0, 2).map((tag, tagIndex) => (
|
||||||
<span key={tagIndex}>
|
<span key={tagIndex}>
|
||||||
{tag}
|
{tag}
|
||||||
@@ -134,16 +140,28 @@ const AppCard = ({ data, index, mouseHoverIndex, setMouseHoverIndex, globalUrl,
|
|||||||
</div>
|
</div>
|
||||||
{/* Deactivate button */}
|
{/* Deactivate button */}
|
||||||
{currTab === 0 && !deactivatedIndexes.includes(index) && mouseHoverIndex === index && data.generated === true && (
|
{currTab === 0 && !deactivatedIndexes.includes(index) && mouseHoverIndex === index && data.generated === true && (
|
||||||
|
<div style={{
|
||||||
|
display: "flex",
|
||||||
|
gap: 8
|
||||||
|
}}>
|
||||||
|
{
|
||||||
|
canEditApp && (
|
||||||
|
<button style={{ backgroundColor: "rgba(73, 73, 73, 1)", border: "none", cursor: "pointer", color: "white", borderRadius: 6, display: "flex", alignItems: "center", justifyContent: "center" }}>
|
||||||
|
<EditIcon />
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
}
|
||||||
<Button
|
<Button
|
||||||
className="deactivate-button"
|
className="deactivate-button"
|
||||||
style={{
|
style={{
|
||||||
marginLeft: 15,
|
// marginLeft: 15,
|
||||||
width: 102,
|
width: 102,
|
||||||
height: 35,
|
height: 35,
|
||||||
borderRadius: 200,
|
borderRadius: 6,
|
||||||
backgroundColor: "rgba(73, 73, 73, 1)",
|
backgroundColor: "rgba(73, 73, 73, 1)",
|
||||||
color: "rgba(241, 241, 241, 1)",
|
color: "rgba(241, 241, 241, 1)",
|
||||||
textTransform: "none",
|
textTransform: "none",
|
||||||
|
fontFamily: "Inter"
|
||||||
}}
|
}}
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
@@ -172,6 +190,7 @@ const AppCard = ({ data, index, mouseHoverIndex, setMouseHoverIndex, globalUrl,
|
|||||||
>
|
>
|
||||||
Deactivate
|
Deactivate
|
||||||
</Button>
|
</Button>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -192,6 +211,7 @@ const Hits = ({
|
|||||||
globalUrl,
|
globalUrl,
|
||||||
isLoading,
|
isLoading,
|
||||||
isLoggedIn,
|
isLoggedIn,
|
||||||
|
leftSideBarOpenByClick
|
||||||
}) => {
|
}) => {
|
||||||
const [hoverEffect, setHoverEffect] = useState(-1);
|
const [hoverEffect, setHoverEffect] = useState(-1);
|
||||||
const [allActivatedAppIds, setAllActivatedAppIds] = useState(userdata?.active_apps);
|
const [allActivatedAppIds, setAllActivatedAppIds] = useState(userdata?.active_apps);
|
||||||
@@ -330,7 +350,7 @@ const Hits = ({
|
|||||||
color: "rgba(241, 241, 241, 1)",
|
color: "rgba(241, 241, 241, 1)",
|
||||||
cursor: "pointer",
|
cursor: "pointer",
|
||||||
position: "relative",
|
position: "relative",
|
||||||
width: 365,
|
width: leftSideBarOpenByClick ? 325 : 365,
|
||||||
height: 96,
|
height: 96,
|
||||||
borderRadius: 8,
|
borderRadius: 8,
|
||||||
boxShadow: "0px 0px 10px 0px rgba(0, 0, 0, 0.1)",
|
boxShadow: "0px 0px 10px 0px rgba(0, 0, 0, 0.1)",
|
||||||
@@ -374,7 +394,6 @@ const Hits = ({
|
|||||||
fontWeight: '400',
|
fontWeight: '400',
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
margin: "12px 0",
|
margin: "12px 0",
|
||||||
fontFamily: "var(--zds-typography-base,Inter,Helvetica,arial,sans-serif)"
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@@ -398,7 +417,7 @@ const Hits = ({
|
|||||||
textOverflow: "ellipsis",
|
textOverflow: "ellipsis",
|
||||||
whiteSpace: "nowrap",
|
whiteSpace: "nowrap",
|
||||||
color: "rgba(158, 158, 158, 1)",
|
color: "rgba(158, 158, 158, 1)",
|
||||||
marginTop: 5
|
marginTop: 5,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{data.categories !== null
|
{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 (
|
|
||||||
<Select
|
|
||||||
fullWidth
|
|
||||||
variant="outlined"
|
|
||||||
value={currentRefinement}
|
|
||||||
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',
|
|
||||||
}}
|
|
||||||
renderValue={(selected) => selected.length ? selected.join(', ') : 'All Categories'}
|
|
||||||
>
|
|
||||||
<MenuItem disabled value="">
|
|
||||||
All Categories
|
|
||||||
</MenuItem>
|
|
||||||
{items.map(item => (
|
|
||||||
<MenuItem key={item.label} value={item.label}>
|
|
||||||
<Checkbox checked={currentRefinement.includes(item.label)} />
|
|
||||||
{item.label} ({item.count})
|
|
||||||
</MenuItem>
|
|
||||||
))}
|
|
||||||
</Select>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const CustomCategoryDropdown = connectRefinementList(CategoryDropdown);
|
|
||||||
|
|
||||||
// Custom SearchBox Component
|
// Custom SearchBox Component
|
||||||
const SearchBox = ({ refine, searchQuery, setSearchQuery }) => {
|
const SearchBox = ({ refine, searchQuery, setSearchQuery }) => {
|
||||||
@@ -608,10 +588,11 @@ const SearchBox = ({ refine, searchQuery, setSearchQuery }) => {
|
|||||||
event.preventDefault();
|
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={{
|
InputProps={{
|
||||||
style: {
|
style: {
|
||||||
borderRadius: 8,
|
borderRadius: 8,
|
||||||
|
height: 45
|
||||||
},
|
},
|
||||||
endAdornment: (
|
endAdornment: (
|
||||||
<InputAdornment position="end">
|
<InputAdornment position="end">
|
||||||
@@ -637,6 +618,38 @@ const SearchBox = ({ refine, searchQuery, setSearchQuery }) => {
|
|||||||
const CustomSearchBox = connectSearchBox(SearchBox);
|
const CustomSearchBox = connectSearchBox(SearchBox);
|
||||||
const CustomHits = connectHits(Hits);
|
const CustomHits = connectHits(Hits);
|
||||||
|
|
||||||
|
// Custom Category Dropdown Component
|
||||||
|
const CategoryDropdown = ({ items, currentRefinement, refine }) => {
|
||||||
|
const handleChange = (event) => {
|
||||||
|
const value = event.target.value;
|
||||||
|
refine(value);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Select
|
||||||
|
fullWidth
|
||||||
|
variant="outlined"
|
||||||
|
value={currentRefinement}
|
||||||
|
onChange={handleChange}
|
||||||
|
displayEmpty
|
||||||
|
multiple
|
||||||
|
style={{ borderRadius: 8, height: 45, fontFamily: "Inter", flex: 1 }}
|
||||||
|
renderValue={(selected) => selected.length ? selected.join(', ') : 'All Categories'}
|
||||||
|
>
|
||||||
|
<MenuItem disabled value="" style={{ fontFamily: "Inter" }}>
|
||||||
|
All Categories
|
||||||
|
</MenuItem>
|
||||||
|
{items.map(item => (
|
||||||
|
<MenuItem key={item.label} value={item.label} style={{ fontFamily: "Inter" }}>
|
||||||
|
<Checkbox checked={currentRefinement.includes(item.label)} />
|
||||||
|
{item.label} ({item.count})
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
const CustomCategoryDropdown = connectRefinementList(CategoryDropdown);
|
||||||
|
|
||||||
// Custom Label Dropdown Component
|
// Custom Label Dropdown Component
|
||||||
const LabelDropdown = ({ items, currentRefinement, refine }) => {
|
const LabelDropdown = ({ items, currentRefinement, refine }) => {
|
||||||
const handleChange = (event) => {
|
const handleChange = (event) => {
|
||||||
@@ -652,15 +665,7 @@ const LabelDropdown = ({ items, currentRefinement, refine }) => {
|
|||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
displayEmpty
|
displayEmpty
|
||||||
multiple
|
multiple
|
||||||
style={{
|
style={{ borderRadius: 8, height: 45, fontFamily: "Inter", flex: 1 }}
|
||||||
width: '100%',
|
|
||||||
maxWidth: '300px',
|
|
||||||
borderRadius: '7px',
|
|
||||||
fontFamily: "var(--zds-typography-base,Inter,Helvetica,arial,sans-serif)",
|
|
||||||
overflow: 'hidden',
|
|
||||||
textOverflow: 'ellipsis',
|
|
||||||
whiteSpace: 'nowrap',
|
|
||||||
}}
|
|
||||||
renderValue={(selected) => selected.length ? selected.join(', ') : 'All Labels'}
|
renderValue={(selected) => selected.length ? selected.join(', ') : 'All Labels'}
|
||||||
>
|
>
|
||||||
<MenuItem disabled value="">
|
<MenuItem disabled value="">
|
||||||
@@ -675,9 +680,44 @@ const LabelDropdown = ({ items, currentRefinement, refine }) => {
|
|||||||
</Select>
|
</Select>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const CustomLabelDropdown = connectRefinementList(LabelDropdown);
|
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
|
// Main Apps Component
|
||||||
const Apps2 = (props) => {
|
const Apps2 = (props) => {
|
||||||
const { globalUrl, isLoaded, serverside, userdata, isLoggedIn, checkLogin } = props;
|
const { globalUrl, isLoaded, serverside, userdata, isLoggedIn, checkLogin } = props;
|
||||||
@@ -803,14 +843,16 @@ const Apps2 = (props) => {
|
|||||||
}
|
}
|
||||||
}, [currTab, globalUrl, userdata?.id]); // Remove location.search dependency
|
}, [currTab, globalUrl, userdata?.id]); // Remove location.search dependency
|
||||||
|
|
||||||
useEffect(() => {
|
// useEffect(() => {
|
||||||
setSearchQuery("");
|
// // setSearchQuery("");
|
||||||
}, [currTab])
|
// setSelectedCategory([]);
|
||||||
|
// setSelectedLabel([]);
|
||||||
|
// }, [currTab])
|
||||||
|
|
||||||
|
|
||||||
// Find top categories and tags based on the current tab
|
// Find top categories and tags based on the current tab
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (currTab === 0) {
|
if (currTab === 0 || currTab === 1) {
|
||||||
setCategories(findTopCategories());
|
setCategories(findTopCategories());
|
||||||
setLabels(findTopTags());
|
setLabels(findTopTags());
|
||||||
}
|
}
|
||||||
@@ -881,76 +923,81 @@ const Apps2 = (props) => {
|
|||||||
|
|
||||||
const handleCreateApp = (e) => {
|
const handleCreateApp = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
setOpenModal(true);
|
// setOpenModal(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const apps = currTab === 1 ? userApps : orgApps;
|
const apps = currTab === 1 ? userApps : orgApps;
|
||||||
// Search app based on app name, category, and tag
|
const filteredUserAppdata = filterApps(apps, searchQuery, selectedCategory, selectedLabel);
|
||||||
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;
|
|
||||||
}) : [];
|
|
||||||
|
|
||||||
setAppsToShow(filteredUserAppdata);
|
setAppsToShow(filteredUserAppdata);
|
||||||
}, [searchQuery, selectedCategory, selectedLabel]);
|
}, [searchQuery, selectedCategory, selectedLabel, currTab]);
|
||||||
|
|
||||||
|
|
||||||
const handleTabChange = (newTab) => {
|
const handleTabChange = (newTab) => {
|
||||||
setCurrTab(newTab);
|
setCurrTab(newTab);
|
||||||
|
// Apply filters immediately when changing tabs
|
||||||
if (newTab === 0) {
|
if (newTab === 0) {
|
||||||
setAppsToShow(orgApps)
|
const filteredOrgApps = filterApps(orgApps, searchQuery, selectedCategory, selectedLabel);
|
||||||
const categories = findTopCategories();
|
setAppsToShow(filteredOrgApps);
|
||||||
const labels = findTopTags();
|
} else if (newTab === 1) {
|
||||||
setCategories(categories);
|
const filteredUserApps = filterApps(userApps, searchQuery, selectedCategory, selectedLabel);
|
||||||
setLabels(labels);
|
setAppsToShow(filteredUserApps);
|
||||||
}
|
|
||||||
if (newTab === 1) {
|
|
||||||
setAppsToShow(userApps)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update URL query params
|
||||||
const newQueryParam = newTab === 0 ? 'org_apps' : newTab === 1 ? 'my_apps' : 'all_apps';
|
const newQueryParam = newTab === 0 ? 'org_apps' : newTab === 1 ? 'my_apps' : 'all_apps';
|
||||||
const queryParams = new URLSearchParams(location.search);
|
const queryParams = new URLSearchParams(location.search);
|
||||||
queryParams.set('tab', newQueryParam);
|
queryParams.set('tab', newQueryParam);
|
||||||
|
// Only remove 'q' param if search is empty
|
||||||
|
if (!searchQuery) {
|
||||||
queryParams.delete('q');
|
queryParams.delete('q');
|
||||||
|
}
|
||||||
window.history.replaceState({}, '', `${location.pathname}?${queryParams.toString()}`);
|
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 = {
|
const boxStyle = {
|
||||||
color: "white",
|
color: "white",
|
||||||
display: "flex",
|
display: "flex",
|
||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
|
height: "100%",
|
||||||
width: "100%",
|
width: "100%",
|
||||||
margin: "auto",
|
margin: "auto",
|
||||||
maxWidth: "60%",
|
maxWidth: "70%",
|
||||||
|
fontFamily: "Inter",
|
||||||
// padding: '20px 380px',
|
// padding: '20px 380px',
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -975,6 +1022,7 @@ const Apps2 = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<div style={{ paddingTop: 70, minHeight: 1000, paddingLeft: leftSideBarOpenByClick ? 200 : 0, transition: "padding-left 0.3s ease", backgroundColor: "#1A1A1A" }}>
|
||||||
<InstantSearch searchClient={searchClient} indexName="appsearch">
|
<InstantSearch searchClient={searchClient} indexName="appsearch">
|
||||||
<AppModal
|
<AppModal
|
||||||
open={openModal}
|
open={openModal}
|
||||||
@@ -984,7 +1032,7 @@ const Apps2 = (props) => {
|
|||||||
globalUrl={globalUrl}
|
globalUrl={globalUrl}
|
||||||
/>
|
/>
|
||||||
<div style={boxStyle}>
|
<div style={boxStyle}>
|
||||||
<Typography variant="h4" style={{ marginBottom: 20, paddingLeft: 15, textTransform: 'none' }}>
|
<Typography variant="h4" style={{ marginBottom: 20, paddingLeft: 15, textTransform: 'none', fontFamily: "Inter" }}>
|
||||||
Apps
|
Apps
|
||||||
</Typography>
|
</Typography>
|
||||||
<div style={{ borderBottom: '1px solid gray', marginBottom: 30, marginRight: 10 }}>
|
<div style={{ borderBottom: '1px solid gray', marginBottom: 30, marginRight: 10 }}>
|
||||||
@@ -992,14 +1040,15 @@ const Apps2 = (props) => {
|
|||||||
value={currTab}
|
value={currTab}
|
||||||
onChange={(event, newTab) => handleTabChange(newTab)}
|
onChange={(event, newTab) => handleTabChange(newTab)}
|
||||||
TabIndicatorProps={{ style: { height: '3px', borderRadius: 10 } }}
|
TabIndicatorProps={{ style: { height: '3px', borderRadius: 10 } }}
|
||||||
|
style={{ fontFamily: "Inter" }}
|
||||||
>
|
>
|
||||||
<Tab label="Organization Apps" style={{ textTransform: 'none', marginRight: 20 }} />
|
<Tab label="Organization Apps" style={{ textTransform: 'none', marginRight: 20, fontFamily: "Inter" }} />
|
||||||
<Tab label="My Apps" style={{ textTransform: 'none', marginRight: 20 }} />
|
<Tab label="My Apps" style={{ textTransform: 'none', marginRight: 20, fontFamily: "Inter" }} />
|
||||||
<Tab label="Discover Apps" style={{ textTransform: 'none' }} />
|
<Tab label="Discover Apps" style={{ textTransform: 'none', fontFamily: "Inter" }} />
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ display: "flex", justifyContent: "space-between", marginBottom: 20 }}>
|
<div style={{ display: "flex", justifyContent: "space-between", gap: 10, marginBottom: 20, height: 45 }}>
|
||||||
<div style={{ flex: 1, marginRight: 10 }}>
|
<div style={{ flex: 1, width: '100%', borderRadius: '7px' }}>
|
||||||
{
|
{
|
||||||
(currTab === 0 || currTab === 1) &&
|
(currTab === 0 || currTab === 1) &&
|
||||||
<TextField
|
<TextField
|
||||||
@@ -1008,25 +1057,30 @@ const Apps2 = (props) => {
|
|||||||
placeholder="Search for apps"
|
placeholder="Search for apps"
|
||||||
value={searchQuery}
|
value={searchQuery}
|
||||||
id="shuffle_search_field"
|
id="shuffle_search_field"
|
||||||
onChange={(event) => {
|
onChange={handleSearchChange}
|
||||||
setSearchQuery(event.target.value);
|
|
||||||
}}
|
|
||||||
onKeyDown={(event) => {
|
onKeyDown={(event) => {
|
||||||
if (event.key === "Enter") {
|
if (event.key === "Enter") {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
limit={5}
|
limit={5}
|
||||||
style={{ width: '100%', borderRadius: '7px', fontFamily: "var(--zds-typography-base,Inter,Helvetica,arial,sans-serif)" }}
|
|
||||||
InputProps={{
|
InputProps={{
|
||||||
style: {
|
style: {
|
||||||
borderRadius: 8,
|
borderRadius: 8,
|
||||||
|
height: 45
|
||||||
},
|
},
|
||||||
endAdornment: (
|
endAdornment: (
|
||||||
<InputAdornment position="end">
|
<InputAdornment position="end">
|
||||||
{
|
{searchQuery.length === 0 ? (
|
||||||
searchQuery.length === 0 ? <Search /> : <ClearIcon />
|
<Search />
|
||||||
}
|
) : (
|
||||||
|
<ClearIcon
|
||||||
|
style={{ cursor: "pointer" }}
|
||||||
|
onClick={() => {
|
||||||
|
setSearchQuery("");
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</InputAdornment>
|
</InputAdornment>
|
||||||
),
|
),
|
||||||
}}
|
}}
|
||||||
@@ -1037,10 +1091,11 @@ const Apps2 = (props) => {
|
|||||||
<CustomSearchBox searchQuery={searchQuery} setSearchQuery={setSearchQuery} />
|
<CustomSearchBox searchQuery={searchQuery} setSearchQuery={setSearchQuery} />
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<div style={{ flex: 1, marginRight: 10 }}>
|
<div style={{ flex: 1, width: '100%', borderRadius: '7px', position: 'relative' }}>
|
||||||
{currTab === 2 ? (
|
{currTab === 2 ? (
|
||||||
<CustomCategoryDropdown attribute="categories" />
|
<CustomCategoryDropdown attribute="categories" />
|
||||||
) : (
|
) : (
|
||||||
|
<>
|
||||||
<Select
|
<Select
|
||||||
fullWidth
|
fullWidth
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
@@ -1048,25 +1103,42 @@ const Apps2 = (props) => {
|
|||||||
onChange={handleCategoryChange}
|
onChange={handleCategoryChange}
|
||||||
displayEmpty
|
displayEmpty
|
||||||
multiple
|
multiple
|
||||||
style={{ width: '100%', borderRadius: '7px', fontFamily: "var(--zds-typography-base,Inter,Helvetica,arial,sans-serif)", maxWidth: "300px" }}
|
style={{ borderRadius: 8, height: 45, fontFamily: "Inter" }}
|
||||||
renderValue={(selected) => selected.length ? selected.join(', ') : 'All Categories'}
|
renderValue={(selected) => selected.length ? selected.join(', ') : 'All Categories'}
|
||||||
>
|
>
|
||||||
<MenuItem disabled value="">
|
<MenuItem disabled value="" style={{ fontFamily: "Inter" }}>
|
||||||
All Categories
|
All Categories
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
{categories?.map((category) => (
|
{categories?.map((category) => (
|
||||||
<MenuItem key={category.category} value={category.category}>
|
<MenuItem key={category.category} value={category.category} style={{ fontFamily: "Inter" }}>
|
||||||
<Checkbox checked={selectedCategory.includes(category.category)} />
|
<Checkbox checked={selectedCategory.includes(category.category)} />
|
||||||
{category.category}
|
{category.category}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
|
{selectedCategory.length > 0 && (
|
||||||
|
<ClearIcon
|
||||||
|
style={{
|
||||||
|
position: 'absolute',
|
||||||
|
right: 35,
|
||||||
|
top: '50%',
|
||||||
|
transform: 'translateY(-50%)',
|
||||||
|
cursor: 'pointer',
|
||||||
|
color: 'white',
|
||||||
|
fontSize: 20,
|
||||||
|
zIndex: 1000
|
||||||
|
}}
|
||||||
|
onClick={() => setSelectedCategory([])}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div style={{ flex: 1, marginRight: 10 }}>
|
<div style={{ flex: 1, width: '100%', borderRadius: '7px', position: 'relative' }}>
|
||||||
{currTab === 2 ? (
|
{currTab === 2 ? (
|
||||||
<CustomLabelDropdown attribute="action_labels" />
|
<CustomLabelDropdown attribute="action_labels" />
|
||||||
) : (
|
) : (
|
||||||
|
<>
|
||||||
<Select
|
<Select
|
||||||
fullWidth
|
fullWidth
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
@@ -1074,29 +1146,45 @@ const Apps2 = (props) => {
|
|||||||
onChange={handleLabelChange}
|
onChange={handleLabelChange}
|
||||||
displayEmpty
|
displayEmpty
|
||||||
multiple
|
multiple
|
||||||
style={{ width: '100%', borderRadius: '7px', fontFamily: "var(--zds-typography-base,Inter,Helvetica,arial,sans-serif)", maxWidth: "300px" }}
|
style={{ borderRadius: 8, height: 45, fontFamily: "Inter" }}
|
||||||
renderValue={(selected) => selected.length ? selected.join(', ') : 'All Labels'}
|
renderValue={(selected) => selected.length ? selected.join(', ') : 'All Labels'}
|
||||||
>
|
>
|
||||||
<MenuItem disabled value="">
|
<MenuItem disabled value="" style={{ fontFamily: "Inter" }}>
|
||||||
All Labels
|
All Labels
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
{labels?.map((tag) => (
|
{labels?.map((tag) => (
|
||||||
<MenuItem key={tag.tag} value={tag.tag}>
|
<MenuItem key={tag.tag} value={tag.tag} style={{ fontFamily: "Inter" }}>
|
||||||
<Checkbox checked={selectedLabel.includes(tag.tag)} />
|
<Checkbox checked={selectedLabel.includes(tag.tag)} />
|
||||||
{tag.tag}
|
{tag.tag}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
|
{selectedLabel.length > 0 && (
|
||||||
|
<ClearIcon
|
||||||
|
style={{
|
||||||
|
position: 'absolute',
|
||||||
|
right: 35,
|
||||||
|
top: '50%',
|
||||||
|
transform: 'translateY(-50%)',
|
||||||
|
cursor: 'pointer',
|
||||||
|
color: 'white',
|
||||||
|
fontSize: 20,
|
||||||
|
zIndex: 1000
|
||||||
|
}}
|
||||||
|
onClick={() => setSelectedLabel([])}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div style={{ flex: 1, marginRight: 10 }}>
|
<div style={{ flex: 1 }}>
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
color="primary"
|
color="primary"
|
||||||
onClick={handleCreateApp}
|
onClick={handleCreateApp}
|
||||||
style={{ height: "100%", width: '100%', borderRadius: '7px', textTransform: 'none', fontFamily: "var(--zds-typography-base,Inter,Helvetica,arial,sans-serif)" }}
|
style={{ height: "100%", width: '100%', borderRadius: '7px', textTransform: 'none', backgroundColor: "#FF8544", color: "#1A1A1A", fontFamily: "Inter" }}
|
||||||
>
|
>
|
||||||
<Add style={{ marginRight: 10 }} />
|
<Add style={{ marginRight: 10, color: "#1A1A1A", fontSize: 20 }} />
|
||||||
Create an App
|
Create an App
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
@@ -1105,7 +1193,7 @@ const Apps2 = (props) => {
|
|||||||
|
|
||||||
{
|
{
|
||||||
currTab === 0 && (
|
currTab === 0 && (
|
||||||
<div style={{ minHeight: 570, overflowY: "auto", overflowX: "hidden" }}>
|
<div style={{ minHeight: 570 }}>
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<div style={{ width: "100%", textAlign: "center", display: "flex", justifyContent: "center", alignItems: "center" }}>
|
<div style={{ width: "100%", textAlign: "center", display: "flex", justifyContent: "center", alignItems: "center" }}>
|
||||||
<CircularProgress />
|
<CircularProgress />
|
||||||
@@ -1113,9 +1201,30 @@ const Apps2 = (props) => {
|
|||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
{appsToShow?.length > 0 && appsToShow !== undefined && !isLoading ? (
|
{appsToShow?.length > 0 && appsToShow !== undefined && !isLoading ? (
|
||||||
<div style={{ rowGap: 16, columnGap: 16, marginTop: 16, display: "flex", flexWrap: "wrap", justifyContent: "flex-start", maxHeight: 570, scrollbarWidth: "thin", scrollbarColor: "#494949 #2f2f2f" }}>
|
<div style={{
|
||||||
|
marginTop: 16,
|
||||||
|
width: "100%",
|
||||||
|
display: "grid",
|
||||||
|
gridTemplateColumns: "repeat(auto-fill, minmax(365px, 1fr))",
|
||||||
|
gap: "20px",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
alignItems: "start",
|
||||||
|
padding: "0 10px"
|
||||||
|
}}>
|
||||||
{appsToShow.map((data, index) => (
|
{appsToShow.map((data, index) => (
|
||||||
<AppCard key={index} data={data} index={index} mouseHoverIndex={mouseHoverIndex} setMouseHoverIndex={setMouseHoverIndex} globalUrl={globalUrl} deactivatedIndexes={deactivatedIndexes} currTab={currTab} handleAppClick={handleAppClick} />
|
<AppCard
|
||||||
|
key={index}
|
||||||
|
data={data}
|
||||||
|
index={index}
|
||||||
|
mouseHoverIndex={mouseHoverIndex}
|
||||||
|
setMouseHoverIndex={setMouseHoverIndex}
|
||||||
|
globalUrl={globalUrl}
|
||||||
|
deactivatedIndexes={deactivatedIndexes}
|
||||||
|
currTab={currTab}
|
||||||
|
handleAppClick={handleAppClick}
|
||||||
|
leftSideBarOpenByClick={leftSideBarOpenByClick}
|
||||||
|
userdata={userdata}
|
||||||
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
@@ -1147,10 +1256,19 @@ const Apps2 = (props) => {
|
|||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
{appsToShow?.length > 0 && appsToShow !== undefined ? (
|
{appsToShow?.length > 0 && appsToShow !== undefined ? (
|
||||||
<div style={{ rowGap: 16, columnGap: 16, marginTop: 16, display: "flex", flexWrap: "wrap", justifyContent: "flex-start", maxHeight: 570, scrollbarWidth: "thin", scrollbarColor: "#494949 #2f2f2f" }}>
|
<div style={{
|
||||||
|
marginTop: 16,
|
||||||
|
width: "100%",
|
||||||
|
display: "grid",
|
||||||
|
gridTemplateColumns: "repeat(auto-fill, minmax(365px, 1fr))",
|
||||||
|
gap: "20px",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
alignItems: "start",
|
||||||
|
padding: "0 10px"
|
||||||
|
}}>
|
||||||
{appsToShow.map((data, index) => (
|
{appsToShow.map((data, index) => (
|
||||||
<AppCard key={index} data={data} index={index} mouseHoverIndex={mouseHoverIndex} setMouseHoverIndex={setMouseHoverIndex} globalUrl={globalUrl} deactivatedIndexes={deactivatedIndexes} currTab={currTab}
|
<AppCard key={index} data={data} index={index} mouseHoverIndex={mouseHoverIndex} setMouseHoverIndex={setMouseHoverIndex} globalUrl={globalUrl} deactivatedIndexes={deactivatedIndexes} currTab={currTab} userdata={userdata}
|
||||||
handleAppClick={handleAppClick}
|
handleAppClick={handleAppClick} leftSideBarOpenByClick={leftSideBarOpenByClick}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@@ -1177,12 +1295,14 @@ const Apps2 = (props) => {
|
|||||||
searchQuery={searchQuery}
|
searchQuery={searchQuery}
|
||||||
mouseHoverIndex={mouseHoverIndex}
|
mouseHoverIndex={mouseHoverIndex}
|
||||||
setMouseHoverIndex={setMouseHoverIndex}
|
setMouseHoverIndex={setMouseHoverIndex}
|
||||||
|
leftSideBarOpenByClick={leftSideBarOpenByClick}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div >
|
</div >
|
||||||
<Configure clickAnalytics />
|
<Configure clickAnalytics />
|
||||||
</InstantSearch>
|
</InstantSearch>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user