done with orgApps section
This commit is contained in:
+233
-68
@@ -29,6 +29,7 @@ const searchClient = algoliasearch(
|
||||
"db08e40265e2941b9a7d8f644b6e5240"
|
||||
);
|
||||
|
||||
// AppCard Component
|
||||
const AppCard = ({ data, index, mouseHoverIndex, setMouseHoverIndex, globalUrl, deactivatedIndexes }) => {
|
||||
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}`;
|
||||
@@ -42,7 +43,7 @@ const AppCard = ({ data, index, mouseHoverIndex, setMouseHoverIndex, globalUrl,
|
||||
height: 96,
|
||||
borderRadius: 8,
|
||||
boxShadow: "0px 0px 10px 0px rgba(0, 0, 0, 0.1)",
|
||||
// marginBottom: 20,
|
||||
marginBottom: 20,
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -169,13 +170,13 @@ const AppCard = ({ data, index, mouseHoverIndex, setMouseHoverIndex, globalUrl,
|
||||
|
||||
|
||||
// Component to fetch all public app from the algolia.
|
||||
const Hits = memo(({
|
||||
const Hits = ({
|
||||
userdata,
|
||||
hits,
|
||||
algoliaSelectedCategories,
|
||||
setIsAnyAppActivated,
|
||||
searchQuery,
|
||||
globalUrl,
|
||||
setIsLoggedIn,
|
||||
isLoading,
|
||||
isLoggedIn,
|
||||
}) => {
|
||||
@@ -193,6 +194,16 @@ const Hits = memo(({
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
console.log("searchQuery", searchQuery)
|
||||
console.log("hits", 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 () => {
|
||||
// try {
|
||||
@@ -281,33 +292,37 @@ const Hits = memo(({
|
||||
return () => clearTimeout(timer);
|
||||
}, []);
|
||||
|
||||
const memoizedHits = useMemo(() => hits, [hits]);
|
||||
|
||||
|
||||
return (
|
||||
<div>
|
||||
{!isLoading ? (
|
||||
<div>
|
||||
{memoizedHits?.length === 0 && searchQuery.length >= 0 && showNoAppFound ? (
|
||||
{filteredHits?.length === 0 && searchQuery.length >= 0 && showNoAppFound ? (
|
||||
<Typography variant="body1" style={{ marginTop: '30%' }}>No Apps Found</Typography>
|
||||
) : (
|
||||
<Grid item spacing={2} justifyContent="flex-start">
|
||||
<div
|
||||
style={{
|
||||
gap: 16,
|
||||
minHeight: 570,
|
||||
overflowY: "auto",
|
||||
overflowX: "hidden",
|
||||
}}>
|
||||
<div
|
||||
style={{
|
||||
rowGap: 16,
|
||||
columnGap: 16,
|
||||
marginTop: 16,
|
||||
display: "flex",
|
||||
flexWrap: "wrap",
|
||||
justifyContent: "flex-start",
|
||||
marginLeft: 24,
|
||||
overflowY: "auto",
|
||||
overflowX: "hidden",
|
||||
// marginLeft: 24,
|
||||
maxHeight: 570,
|
||||
scrollbarWidth: "thin",
|
||||
scrollbarColor: "#494949 #2f2f2f",
|
||||
}}
|
||||
>
|
||||
{memoizedHits.map((data, index) => {
|
||||
{filteredHits?.map((data, index) => {
|
||||
const appUrl =
|
||||
isCloud
|
||||
? `/apps/${data.objectID}?queryID=${data.__queryID}`
|
||||
@@ -513,6 +528,7 @@ const Hits = memo(({
|
||||
})
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</Grid >
|
||||
)}
|
||||
</div>
|
||||
@@ -521,8 +537,9 @@ const Hits = memo(({
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// Main Apps Component
|
||||
const Apps2 = (props) => {
|
||||
const { globalUrl, isLoaded, serverside, userdata, isLoggedIn } = props;
|
||||
let navigate = useNavigate();
|
||||
@@ -530,11 +547,13 @@ const Apps2 = (props) => {
|
||||
const location = useLocation();
|
||||
const [searchQuery, setSearchQuery] = useState("");
|
||||
const [selectedCategory, setSelectedCategory] = useState("");
|
||||
const [algoliaSelectedCategories, setAlgoliaSelectedCategories] = useState([]);
|
||||
const [selectedLabel, setSelectedLabel] = useState("");
|
||||
const [algoliaSelectedLabels, setAlgoliaSelectedLabels] = useState([]);
|
||||
const [currTab, setCurrTab] = useState(0);
|
||||
const [categories, setCategories] = useState([]);
|
||||
const [labels, setLabels] = useState([]);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [userApps, setUserApps] = useState([]);
|
||||
const [orgApps, setOrgApps] = useState([]);
|
||||
const [selectedCategoryForUsersAndOgsApps, setselectedCategoryForUsersAndOgsApps] = useState([]);
|
||||
@@ -542,13 +561,12 @@ const Apps2 = (props) => {
|
||||
const [appsToShow, setAppsToShow] = useState([]);
|
||||
const [deactivatedIndexes, setDeactivatedIndexes] = React.useState([]);
|
||||
const [IsAnyAppActivated, setIsAnyAppActivated] = useState(false);
|
||||
|
||||
const [mouseHoverIndex, setMouseHoverIndex] = useState(-1);
|
||||
var counted = 0;
|
||||
const [showNoAppFound, setShowNoAppFound] = useState(false);
|
||||
|
||||
const CustomHits = connectHits(Hits)
|
||||
|
||||
// Set the current tab based on the query parameter
|
||||
useEffect(() => {
|
||||
const queryParams = new URLSearchParams(location.search);
|
||||
const tabParam = queryParams.get('tab');
|
||||
@@ -560,10 +578,13 @@ const Apps2 = (props) => {
|
||||
} else {
|
||||
setCurrTab(2);
|
||||
}
|
||||
} else {
|
||||
setCurrTab(0);
|
||||
}
|
||||
}, [location.search]);
|
||||
|
||||
|
||||
// Fetch apps based on the current tab : 0 -> org_apps, 1 -> my_apps, 2 -> all_apps
|
||||
useEffect(() => {
|
||||
const fetchApps = async () => {
|
||||
const baseUrl = globalUrl;
|
||||
@@ -589,9 +610,12 @@ const Apps2 = (props) => {
|
||||
const data = await response.json();
|
||||
if (currTab === 1) {
|
||||
console.log("data from userApps", data)
|
||||
setAppsToShow(data);
|
||||
setUserApps(data);
|
||||
setIsLoading(false);
|
||||
} else if (currTab === 0) {
|
||||
console.log("data from orgApps", data)
|
||||
setAppsToShow(data);
|
||||
setOrgApps(data);
|
||||
setIsLoading(false);
|
||||
}
|
||||
@@ -601,9 +625,20 @@ const Apps2 = (props) => {
|
||||
};
|
||||
|
||||
fetchApps();
|
||||
}, [currTab, globalUrl]); // Added globalUrl to dependencies to avoid stale closures
|
||||
}, [currTab, globalUrl, location.search]); // Added globalUrl to dependencies to avoid stale closures
|
||||
|
||||
useEffect(() => {
|
||||
setSearchQuery("");
|
||||
}, [currTab])
|
||||
|
||||
|
||||
// Find top categories and tags based on the current tab
|
||||
useEffect(() => {
|
||||
if (currTab === 0) {
|
||||
setCategories(findTopCategories());
|
||||
setLabels(findTopTags());
|
||||
}
|
||||
}, [currTab, appsToShow])
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
@@ -615,10 +650,10 @@ const Apps2 = (props) => {
|
||||
|
||||
const findTopCategories = () => {
|
||||
const categoryCountMap = {};
|
||||
|
||||
const apps = currTab === 1 ? userApps : orgApps;
|
||||
// Check if userAndOrgsApp is an array before iterating over it and Find top 10 Category from the apps
|
||||
if (Array.isArray(appsToShow)) {
|
||||
appsToShow.forEach((app) => {
|
||||
if (Array.isArray(apps)) {
|
||||
apps.forEach((app) => {
|
||||
const categories = app.categories;
|
||||
|
||||
if (categories && categories.length > 0) {
|
||||
@@ -643,9 +678,10 @@ const Apps2 = (props) => {
|
||||
|
||||
const findTopTags = () => {
|
||||
const tagCountMap = {};
|
||||
const apps = currTab === 1 ? userApps : orgApps;
|
||||
|
||||
if (Array.isArray(appsToShow)) {
|
||||
appsToShow.forEach((app) => {
|
||||
if (Array.isArray(apps)) {
|
||||
apps.forEach((app) => {
|
||||
const tags = app.tags;
|
||||
if (tags && tags.length > 0) {
|
||||
tags.forEach((tag) => {
|
||||
@@ -672,10 +708,13 @@ const Apps2 = (props) => {
|
||||
};
|
||||
|
||||
|
||||
//Search app base on app name, category and tag
|
||||
const filteredUserAppdata = Array.isArray(appsToShow) ? appsToShow.filter((app) => {
|
||||
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 === "" ||
|
||||
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())
|
||||
@@ -686,23 +725,25 @@ const Apps2 = (props) => {
|
||||
);
|
||||
|
||||
const matchesSelectedCategories = (
|
||||
selectedCategoryForUsersAndOgsApps.length === 0 ||
|
||||
selectedCategory === "" || // If no category is selected, match all apps
|
||||
(app.categories && app.categories.some(category =>
|
||||
selectedCategoryForUsersAndOgsApps.includes(category)
|
||||
selectedCategory.includes(category)
|
||||
))
|
||||
);
|
||||
|
||||
const matchesSelectedTags = (
|
||||
selectedTagsForUserAndOrgApps.length === 0 ||
|
||||
(app.tags && selectedTagsForUserAndOrgApps.some(tag =>
|
||||
app.tags.includes(tag)
|
||||
selectedLabel === "" || // If no label is selected, match all apps
|
||||
(app.tags && app.tags.some(tag =>
|
||||
tag.toLowerCase().includes(selectedLabel.toLowerCase())
|
||||
))
|
||||
);
|
||||
|
||||
|
||||
return matchesSearchQuery && matchesSelectedCategories && matchesSelectedTags;
|
||||
}) : [];
|
||||
|
||||
setAppsToShow(filteredUserAppdata);
|
||||
}, [searchQuery, selectedCategory, selectedLabel]);
|
||||
|
||||
|
||||
const handleTabChange = (newTab) => {
|
||||
console.log("Current Tab", newTab)
|
||||
@@ -746,6 +787,104 @@ const Apps2 = (props) => {
|
||||
|
||||
|
||||
|
||||
const SearchBox = ({ refine, searchQuery, setSearchQuery }) => {
|
||||
const inputRef = React.useRef(null); // Create a ref for the input field
|
||||
|
||||
// Check for query in URL and set it
|
||||
React.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);
|
||||
setSearchQuery(foundQuery); // Use setSearchQuery to update state
|
||||
}
|
||||
}
|
||||
}, [refine, setSearchQuery]); // Add dependencies
|
||||
|
||||
// Use useEffect to focus the input when it mounts or when searchQuery changes
|
||||
React.useEffect(() => {
|
||||
if (inputRef.current) {
|
||||
inputRef.current.focus();
|
||||
}
|
||||
}, [searchQuery]); // Focus whenever searchQuery changes
|
||||
|
||||
console.log("searchQuery", searchQuery);
|
||||
|
||||
return (
|
||||
<TextField
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
placeholder="Search for apps"
|
||||
value={searchQuery}
|
||||
id="shuffle_search_field"
|
||||
inputRef={inputRef} // Attach the ref to the input field
|
||||
onChange={(event) => {
|
||||
setSearchQuery(event.target.value); // Update the search query
|
||||
removeQuery("q");
|
||||
refine(event.target.value); // Refine the search
|
||||
}}
|
||||
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: (
|
||||
<InputAdornment position="end">
|
||||
{searchQuery?.length === 0 ? <Search /> : (
|
||||
<ClearIcon
|
||||
style={{
|
||||
cursor: "pointer",
|
||||
marginRight: 10
|
||||
}}
|
||||
onClick={() => {
|
||||
setSearchQuery(''); // Clear the search query
|
||||
removeQuery("q");
|
||||
refine(''); // Clear the refinement
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const CustomSearchBox = connectSearchBox(SearchBox);
|
||||
const CustomHits = connectHits(Hits)
|
||||
|
||||
|
||||
const handleCategoryChange = (selectedValue) => {
|
||||
setAlgoliaSelectedCategories(prev => {
|
||||
if (prev.includes(selectedValue)) {
|
||||
// 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(() => {
|
||||
console.log("algoliaSelectedCategories", algoliaSelectedCategories)
|
||||
}, [algoliaSelectedCategories])
|
||||
|
||||
|
||||
return (
|
||||
<InstantSearch searchClient={searchClient} indexName="appsearch">
|
||||
<div style={boxStyle}>
|
||||
@@ -765,6 +904,8 @@ const Apps2 = (props) => {
|
||||
</div>
|
||||
<div style={{ display: "flex", justifyContent: "space-between", marginBottom: 20 }}>
|
||||
<div style={{ flex: 1, marginRight: 10 }}>
|
||||
{
|
||||
(currTab === 0 || currTab === 1) &&
|
||||
<TextField
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
@@ -772,9 +913,7 @@ const Apps2 = (props) => {
|
||||
value={searchQuery}
|
||||
id="shuffle_search_field"
|
||||
onChange={(event) => {
|
||||
setSearchQuery(event.currentTarget.value);
|
||||
removeQuery("q");
|
||||
// refine(event.currentTarget.value);
|
||||
setSearchQuery(event.target.value);
|
||||
}}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === "Enter") {
|
||||
@@ -796,7 +935,11 @@ const Apps2 = (props) => {
|
||||
),
|
||||
}}
|
||||
/>
|
||||
{/* <CustomSearchBox searchQuery={searchQuery} setSearchQuery={setSearchQuery} /> */}
|
||||
}
|
||||
{
|
||||
currTab === 2 &&
|
||||
<CustomSearchBox searchQuery={searchQuery} setSearchQuery={setSearchQuery} />
|
||||
}
|
||||
</div>
|
||||
<div style={{ flex: 1, marginRight: 10 }}>
|
||||
<Select
|
||||
@@ -807,14 +950,14 @@ const Apps2 = (props) => {
|
||||
displayEmpty
|
||||
style={{ width: '100%', borderRadius: '7px', fontFamily: "var(--zds-typography-base,Inter,Helvetica,arial,sans-serif)" }}
|
||||
>
|
||||
<MenuItem value="" >
|
||||
<MenuItem value="">
|
||||
All Categories
|
||||
</MenuItem>
|
||||
{
|
||||
currTab === 0 &&
|
||||
(
|
||||
categories?.map((category) => (
|
||||
<MenuItem value={category.category}>
|
||||
<MenuItem key={category.category} value={category.category}>
|
||||
{category.category}
|
||||
</MenuItem>
|
||||
))
|
||||
@@ -824,11 +967,20 @@ const Apps2 = (props) => {
|
||||
currTab === 2 &&
|
||||
(
|
||||
<div style={{ padding: "5px 10px" }}>
|
||||
<RefinementList attribute="categories" />
|
||||
<RefinementList
|
||||
attribute="categories"
|
||||
defaultRefinement={algoliaSelectedCategories}
|
||||
onChange={(selectedItems) => {
|
||||
handleCategoryChange(selectedItems);
|
||||
}}
|
||||
transformItems={(items) => {
|
||||
console.log("items", items)
|
||||
return items;
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
</Select>
|
||||
</div>
|
||||
<div style={{ flex: 1, marginRight: 10 }}>
|
||||
@@ -878,42 +1030,50 @@ const Apps2 = (props) => {
|
||||
<div>
|
||||
|
||||
{
|
||||
currTab === 0 &&
|
||||
(orgApps.length > 0 ? (
|
||||
<div style={{ rowGap: 16, columnGap: 16, marginTop: 16, display: "flex", flexWrap: "wrap", justifyContent: "flex-start", overflowY: "auto", overflowX: "hidden", maxHeight: 570, scrollbarWidth: "thin", scrollbarColor: "#494949 #2f2f2f", maxHeight: 570, minHeight: 570 }}>
|
||||
{
|
||||
isLoading ? <div
|
||||
style={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
}}
|
||||
> <CircularProgress /></div>
|
||||
:
|
||||
(
|
||||
filteredUserAppdata?.map((data, index) => (
|
||||
<AppCard key={index} data={data} index={index} mouseHoverIndex={mouseHoverIndex} setMouseHoverIndex={setMouseHoverIndex} globalUrl={globalUrl} deactivatedIndexes={deactivatedIndexes} />
|
||||
))
|
||||
)
|
||||
}
|
||||
currTab === 0 && (
|
||||
<div style={{ minHeight: 570, overflowY: "auto", overflowX: "hidden" }}>
|
||||
{isLoading ? (
|
||||
<div style={{ width: "100%", height: "100%", display: "flex", justifyContent: "center", alignItems: "center" }}>
|
||||
<CircularProgress />
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
{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" }}>
|
||||
{appsToShow.map((data, index) => (
|
||||
<AppCard key={index} data={data} index={index} mouseHoverIndex={mouseHoverIndex} setMouseHoverIndex={setMouseHoverIndex} globalUrl={globalUrl} deactivatedIndexes={deactivatedIndexes} />
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div style={{ marginTop: 100, fontSize: 20, fontWeight: 500, width: "100%", textAlign: "center" }}>
|
||||
No apps found
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
) : <div
|
||||
style={{
|
||||
marginTop: 100,
|
||||
fontSize: 20,
|
||||
fontWeight: 500,
|
||||
width: "100%",
|
||||
textAlign: "center",
|
||||
}}
|
||||
>No apps found</div>
|
||||
)
|
||||
}
|
||||
{
|
||||
currTab === 1 &&
|
||||
(userApps.length > 0 ? (
|
||||
<div style={{ rowGap: 16, columnGap: 16, marginTop: 16, display: "flex", flexWrap: "wrap", justifyContent: "flex-start", overflowY: "auto", overflowX: "hidden", maxHeight: 570, scrollbarWidth: "thin", scrollbarColor: "#494949 #2f2f2f", maxHeight: 570 }}>
|
||||
<div style={{
|
||||
minHeight: 570,
|
||||
overflowY: "auto",
|
||||
overflowX: "hidden",
|
||||
}}>
|
||||
<div style={{
|
||||
rowGap: 16,
|
||||
columnGap: 16,
|
||||
marginTop: 16,
|
||||
display: "flex",
|
||||
flexWrap: "wrap",
|
||||
justifyContent: "flex-start",
|
||||
maxHeight: 570,
|
||||
scrollbarWidth: "thin",
|
||||
scrollbarColor: "#494949 #2f2f2f",
|
||||
// minHeight: 570
|
||||
}}>
|
||||
{
|
||||
isLoading ? <div
|
||||
style={{
|
||||
@@ -932,7 +1092,9 @@ const Apps2 = (props) => {
|
||||
)
|
||||
}
|
||||
</div>
|
||||
) : <div
|
||||
</div>
|
||||
) : !isLoading && (
|
||||
<div
|
||||
style={{
|
||||
marginTop: 100,
|
||||
fontSize: 20,
|
||||
@@ -942,10 +1104,12 @@ const Apps2 = (props) => {
|
||||
}}
|
||||
>No apps found</div>
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
{
|
||||
currTab === 2 &&
|
||||
|
||||
<CustomHits
|
||||
isLoggedIn={isLoggedIn}
|
||||
userdata={userdata}
|
||||
@@ -953,6 +1117,7 @@ const Apps2 = (props) => {
|
||||
hitsPerPage={5}
|
||||
globalUrl={globalUrl}
|
||||
searchQuery={searchQuery}
|
||||
algoliaSelectedCategories={algoliaSelectedCategories}
|
||||
mouseHoverIndex={mouseHoverIndex}
|
||||
setMouseHoverIndex={setMouseHoverIndex}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user