Done with categories and labels in both app and org apps
This commit is contained in:
+102
-92
@@ -11,6 +11,7 @@ import {
|
|||||||
Tooltip,
|
Tooltip,
|
||||||
Box,
|
Box,
|
||||||
CircularProgress,
|
CircularProgress,
|
||||||
|
Checkbox,
|
||||||
} 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';
|
||||||
@@ -18,7 +19,7 @@ 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';
|
||||||
|
|
||||||
import { ClearRefinements, connectHits, connectSearchBox, connectStateResults, InstantSearch, RefinementList } from "react-instantsearch-dom";
|
import { ClearRefinements, connectHits, connectSearchBox, connectStateResults, InstantSearch, RefinementList, connectRefinementList } from "react-instantsearch-dom";
|
||||||
import { removeQuery } from "../components/ScrollToTop.jsx";
|
import { removeQuery } from "../components/ScrollToTop.jsx";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
import algoliasearch from "algoliasearch/lite";
|
import algoliasearch from "algoliasearch/lite";
|
||||||
@@ -173,7 +174,6 @@ const AppCard = ({ data, index, mouseHoverIndex, setMouseHoverIndex, globalUrl,
|
|||||||
const Hits = ({
|
const Hits = ({
|
||||||
userdata,
|
userdata,
|
||||||
hits,
|
hits,
|
||||||
algoliaSelectedCategories,
|
|
||||||
setIsAnyAppActivated,
|
setIsAnyAppActivated,
|
||||||
searchQuery,
|
searchQuery,
|
||||||
globalUrl,
|
globalUrl,
|
||||||
@@ -200,10 +200,6 @@ const Hits = ({
|
|||||||
}, [searchQuery, hits])
|
}, [searchQuery, hits])
|
||||||
|
|
||||||
|
|
||||||
const filteredHits = hits?.filter(hit => {
|
|
||||||
if (algoliaSelectedCategories?.length === 0) return true; // If no categories are selected, show all hits
|
|
||||||
return hit.categories?.some(category => algoliaSelectedCategories.includes(category));
|
|
||||||
});
|
|
||||||
|
|
||||||
// const fetchUserData = useCallback(async () => {
|
// const fetchUserData = useCallback(async () => {
|
||||||
// try {
|
// try {
|
||||||
@@ -298,7 +294,7 @@ const Hits = ({
|
|||||||
<div>
|
<div>
|
||||||
{!isLoading ? (
|
{!isLoading ? (
|
||||||
<div>
|
<div>
|
||||||
{filteredHits?.length === 0 && searchQuery.length >= 0 && showNoAppFound ? (
|
{hits?.length === 0 && searchQuery.length >= 0 && showNoAppFound ? (
|
||||||
<Typography variant="body1" style={{ marginTop: '30%' }}>No Apps Found</Typography>
|
<Typography variant="body1" style={{ marginTop: '30%' }}>No Apps Found</Typography>
|
||||||
) : (
|
) : (
|
||||||
<Grid item spacing={2} justifyContent="flex-start">
|
<Grid item spacing={2} justifyContent="flex-start">
|
||||||
@@ -322,7 +318,7 @@ const Hits = ({
|
|||||||
scrollbarColor: "#494949 #2f2f2f",
|
scrollbarColor: "#494949 #2f2f2f",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{filteredHits?.map((data, index) => {
|
{hits?.map((data, index) => {
|
||||||
const appUrl =
|
const appUrl =
|
||||||
isCloud
|
isCloud
|
||||||
? `/apps/${data.objectID}?queryID=${data.__queryID}`
|
? `/apps/${data.objectID}?queryID=${data.__queryID}`
|
||||||
@@ -539,6 +535,47 @@ 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);
|
||||||
|
|
||||||
// Main Apps Component
|
// Main Apps Component
|
||||||
const Apps2 = (props) => {
|
const Apps2 = (props) => {
|
||||||
const { globalUrl, isLoaded, serverside, userdata, isLoggedIn } = props;
|
const { globalUrl, isLoaded, serverside, userdata, isLoggedIn } = props;
|
||||||
@@ -546,9 +583,8 @@ const Apps2 = (props) => {
|
|||||||
const { leftSideBarOpenByClick } = useContext(Context);
|
const { leftSideBarOpenByClick } = useContext(Context);
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const [searchQuery, setSearchQuery] = useState("");
|
const [searchQuery, setSearchQuery] = useState("");
|
||||||
const [selectedCategory, setSelectedCategory] = useState("");
|
const [selectedCategory, setSelectedCategory] = useState([]);
|
||||||
const [algoliaSelectedCategories, setAlgoliaSelectedCategories] = useState([]);
|
const [selectedLabel, setSelectedLabel] = useState([]);
|
||||||
const [selectedLabel, setSelectedLabel] = useState("");
|
|
||||||
const [algoliaSelectedLabels, setAlgoliaSelectedLabels] = useState([]);
|
const [algoliaSelectedLabels, setAlgoliaSelectedLabels] = useState([]);
|
||||||
const [currTab, setCurrTab] = useState(0);
|
const [currTab, setCurrTab] = useState(0);
|
||||||
const [categories, setCategories] = useState([]);
|
const [categories, setCategories] = useState([]);
|
||||||
@@ -725,16 +761,16 @@ const Apps2 = (props) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const matchesSelectedCategories = (
|
const matchesSelectedCategories = (
|
||||||
selectedCategory === "" || // If no category is selected, match all apps
|
selectedCategory.length === 0 || // If no category is selected, match all apps
|
||||||
(app.categories && app.categories.some(category =>
|
(app.categories && app.categories.some(category =>
|
||||||
selectedCategory.includes(category)
|
selectedCategory.includes(category)
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
|
||||||
const matchesSelectedTags = (
|
const matchesSelectedTags = (
|
||||||
selectedLabel === "" || // If no label is selected, match all apps
|
selectedLabel.length === 0 || // If no label is selected, match all apps
|
||||||
(app.tags && app.tags.some(tag =>
|
(app.tags && app.tags.some(tag =>
|
||||||
tag.toLowerCase().includes(selectedLabel.toLowerCase())
|
selectedLabel.includes(tag)
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -779,13 +815,6 @@ const Apps2 = (props) => {
|
|||||||
// padding: '20px 380px',
|
// padding: '20px 380px',
|
||||||
};
|
};
|
||||||
|
|
||||||
const CustomClearRefinements = connectStateResults(({ searchResults, ...rest }) => {
|
|
||||||
const hasFilters = searchResults && searchResults.nbHits !== searchResults.nbSortedHits;
|
|
||||||
return <ClearRefinements translations={{ reset: <span style={{ textDecoration: 'underline' }}>Clear All</span> }} {...rest} disabled={!hasFilters} />;
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const SearchBox = ({ refine, searchQuery, setSearchQuery }) => {
|
const SearchBox = ({ refine, searchQuery, setSearchQuery }) => {
|
||||||
const inputRef = React.useRef(null); // Create a ref for the input field
|
const inputRef = React.useRef(null); // Create a ref for the input field
|
||||||
@@ -868,21 +897,15 @@ const Apps2 = (props) => {
|
|||||||
const CustomHits = connectHits(Hits)
|
const CustomHits = connectHits(Hits)
|
||||||
|
|
||||||
|
|
||||||
const handleCategoryChange = (selectedValue) => {
|
const handleCategoryChange = (event) => {
|
||||||
setAlgoliaSelectedCategories(prev => {
|
const value = event.target.value;
|
||||||
if (prev.includes(selectedValue)) {
|
setSelectedCategory(value);
|
||||||
// If the category is already selected, remove it
|
|
||||||
return prev.filter(category => category !== selectedValue);
|
|
||||||
} else {
|
|
||||||
// Otherwise, add it to the selected categories
|
|
||||||
return [...prev, selectedValue];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
const handleLabelChange = (event) => {
|
||||||
console.log("algoliaSelectedCategories", algoliaSelectedCategories)
|
const value = event.target.value;
|
||||||
}, [algoliaSelectedCategories])
|
setSelectedLabel(value);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -942,75 +965,63 @@ const Apps2 = (props) => {
|
|||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<div style={{ flex: 1, marginRight: 10 }}>
|
<div style={{ flex: 1, marginRight: 10 }}>
|
||||||
<Select
|
{currTab === 2 ? (
|
||||||
fullWidth
|
<CustomCategoryDropdown attribute="categories" />
|
||||||
variant="outlined"
|
) : (
|
||||||
value={selectedCategory}
|
<Select
|
||||||
onChange={(e) => setSelectedCategory(e.target.value)}
|
fullWidth
|
||||||
displayEmpty
|
variant="outlined"
|
||||||
style={{ width: '100%', borderRadius: '7px', fontFamily: "var(--zds-typography-base,Inter,Helvetica,arial,sans-serif)" }}
|
value={selectedCategory}
|
||||||
>
|
onChange={handleCategoryChange}
|
||||||
<MenuItem value="">
|
displayEmpty
|
||||||
All Categories
|
multiple
|
||||||
</MenuItem>
|
style={{ width: '100%', borderRadius: '7px', fontFamily: "var(--zds-typography-base,Inter,Helvetica,arial,sans-serif)", maxWidth: "300px" }}
|
||||||
{
|
renderValue={(selected) => selected.length ? selected.join(', ') : 'All Categories'}
|
||||||
currTab === 0 &&
|
>
|
||||||
(
|
<MenuItem disabled value="">
|
||||||
categories?.map((category) => (
|
All Categories
|
||||||
<MenuItem key={category.category} value={category.category}>
|
</MenuItem>
|
||||||
{category.category}
|
{categories?.map((category) => (
|
||||||
|
<MenuItem key={category.category} value={category.category}>
|
||||||
|
<Checkbox checked={selectedCategory.includes(category.category)} />
|
||||||
|
{category.category}
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
{
|
||||||
|
selectedCategory.length > 0 && (
|
||||||
|
<MenuItem onClick={() => setSelectedCategory([])} style={{ display: 'flex', justifyContent: 'center', padding: '10px', backgroundColor: '#212121', color: '#fff', marginTop: '10px', cursor: 'pointer' }}>
|
||||||
|
<Typography style={{ textAlign: 'center', width: '100%', fontWeight: 'bold' }}>Remove All Categories</Typography>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
))
|
)
|
||||||
)
|
}
|
||||||
}
|
</Select>
|
||||||
{
|
)}
|
||||||
currTab === 2 &&
|
|
||||||
(
|
|
||||||
<div style={{ padding: "5px 10px" }}>
|
|
||||||
<RefinementList
|
|
||||||
attribute="categories"
|
|
||||||
defaultRefinement={algoliaSelectedCategories}
|
|
||||||
onChange={(selectedItems) => {
|
|
||||||
handleCategoryChange(selectedItems);
|
|
||||||
}}
|
|
||||||
transformItems={(items) => {
|
|
||||||
console.log("items", items)
|
|
||||||
return items;
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
</Select>
|
|
||||||
</div>
|
</div>
|
||||||
<div style={{ flex: 1, marginRight: 10 }}>
|
<div style={{ flex: 1, marginRight: 10 }}>
|
||||||
<Select
|
<Select
|
||||||
fullWidth
|
fullWidth
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
value={selectedLabel}
|
value={selectedLabel}
|
||||||
onChange={(e) => setSelectedLabel(e.target.value)}
|
onChange={handleLabelChange}
|
||||||
displayEmpty
|
displayEmpty
|
||||||
style={{ width: '100%', borderRadius: '7px', fontFamily: "var(--zds-typography-base,Inter,Helvetica,arial,sans-serif)" }}
|
multiple
|
||||||
|
style={{ width: '100%', borderRadius: '7px', fontFamily: "var(--zds-typography-base,Inter,Helvetica,arial,sans-serif)", maxWidth: "300px" }}
|
||||||
|
renderValue={(selected) => selected.length ? selected.join(', ') : 'All Labels'}
|
||||||
>
|
>
|
||||||
<MenuItem value="">
|
<MenuItem disabled value="">
|
||||||
All Labels
|
All Labels
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
{labels?.map((tag) => (
|
||||||
|
<MenuItem key={tag.tag} value={tag.tag}>
|
||||||
|
<Checkbox checked={selectedLabel.includes(tag.tag)} />
|
||||||
|
{tag.tag}
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
{
|
{
|
||||||
currTab === 0 &&
|
selectedLabel.length > 0 && (
|
||||||
(
|
<MenuItem onClick={() => setSelectedCategory([])} style={{ display: 'flex', justifyContent: 'center', padding: '10px', backgroundColor: '#212121', color: '#fff', marginTop: '10px', cursor: 'pointer' }}>
|
||||||
labels?.map((tag) => (
|
<Typography style={{ textAlign: 'center', width: '100%', fontWeight: 'bold' }}>Remove All Labels</Typography>
|
||||||
<MenuItem value={tag.tag}>
|
</MenuItem>
|
||||||
{tag.tag}
|
|
||||||
</MenuItem>
|
|
||||||
))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
{
|
|
||||||
currTab === 2 &&
|
|
||||||
(
|
|
||||||
<div style={{ padding: "5px 10px" }}>
|
|
||||||
<RefinementList attribute="action_labels" />
|
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
</Select>
|
</Select>
|
||||||
@@ -1117,7 +1128,6 @@ const Apps2 = (props) => {
|
|||||||
hitsPerPage={5}
|
hitsPerPage={5}
|
||||||
globalUrl={globalUrl}
|
globalUrl={globalUrl}
|
||||||
searchQuery={searchQuery}
|
searchQuery={searchQuery}
|
||||||
algoliaSelectedCategories={algoliaSelectedCategories}
|
|
||||||
mouseHoverIndex={mouseHoverIndex}
|
mouseHoverIndex={mouseHoverIndex}
|
||||||
setMouseHoverIndex={setMouseHoverIndex}
|
setMouseHoverIndex={setMouseHoverIndex}
|
||||||
/>
|
/>
|
||||||
|
|||||||
Reference in New Issue
Block a user