-
-
Notifications
You must be signed in to change notification settings - Fork 168
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add filter to commmunity search results page
- Loading branch information
Showing
7 changed files
with
208 additions
and
88 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
import type { IonActionSheetCustomEvent } from "@ionic/core"; | ||
import { | ||
ActionSheetButton, | ||
IonActionSheet, | ||
IonButton, | ||
IonIcon, | ||
} from "@ionic/react"; | ||
import { OverlayEventDetail } from "@ionic/react/dist/types/components/react-component-lib/interfaces"; | ||
import { | ||
earthOutline, | ||
homeOutline, | ||
peopleOutline, | ||
shieldCheckmarkOutline, | ||
} from "ionicons/icons"; | ||
import { useContext, useState } from "react"; | ||
import { startCase } from "lodash"; | ||
import { ListingType } from "lemmy-js-client"; | ||
import { scrollUpIfNeeded } from "../../helpers/scrollUpIfNeeded"; | ||
import { AppContext } from "../auth/AppContext"; | ||
|
||
export const LISTING_TYPES = [ | ||
"All", | ||
"Local", | ||
"Subscribed", | ||
"ModeratorView", | ||
] as const; | ||
|
||
const BUTTONS: ActionSheetButton<ListingType>[] = LISTING_TYPES.map( | ||
(listingType) => ({ | ||
text: startCase(listingType), | ||
data: listingType, | ||
icon: getListingTypeIcon(listingType), | ||
}), | ||
); | ||
|
||
interface CommentSortProps { | ||
listingType: ListingType | undefined; | ||
setListingType: (listingType: ListingType) => void; | ||
} | ||
|
||
export default function ListingTypeFilter({ | ||
listingType, | ||
setListingType, | ||
}: CommentSortProps) { | ||
const [open, setOpen] = useState(false); | ||
const { activePageRef } = useContext(AppContext); | ||
|
||
if (!listingType) return; | ||
|
||
return ( | ||
<> | ||
<IonButton onClick={() => setOpen(true)}> | ||
<IonIcon icon={getListingTypeIcon(listingType)} slot="icon-only" /> | ||
</IonButton> | ||
<IonActionSheet | ||
cssClass="left-align-buttons" | ||
isOpen={open} | ||
onDidDismiss={() => setOpen(false)} | ||
onWillDismiss={( | ||
e: IonActionSheetCustomEvent<OverlayEventDetail<ListingType>>, | ||
) => { | ||
if (!e.detail.data) return; | ||
|
||
setListingType(e.detail.data); | ||
scrollUpIfNeeded(activePageRef?.current, 1, "auto"); | ||
}} | ||
header="Filter by..." | ||
buttons={BUTTONS.map((b) => ({ | ||
...b, | ||
role: listingType === b.data ? "selected" : undefined, | ||
}))} | ||
/> | ||
</> | ||
); | ||
} | ||
|
||
export function getListingTypeIcon(listingType: ListingType): string { | ||
switch (listingType) { | ||
case "All": | ||
return earthOutline; | ||
case "Local": | ||
return peopleOutline; | ||
case "Subscribed": | ||
return homeOutline; | ||
case "ModeratorView": | ||
return shieldCheckmarkOutline; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,11 @@ | ||
import RandomCommunity from "./RandomCommunity"; | ||
import SpecialSearchMenu from "./SpecialSearchMenu"; | ||
import TrendingCommunities from "./TrendingCommunities"; | ||
|
||
export default function EmptySearch() { | ||
return ( | ||
<> | ||
<TrendingCommunities /> | ||
<RandomCommunity /> | ||
<SpecialSearchMenu /> | ||
</> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
import { | ||
IonBackButton, | ||
IonButtons, | ||
IonContent, | ||
IonPage, | ||
IonTitle, | ||
IonToolbar, | ||
} from "@ionic/react"; | ||
import { useBuildGeneralBrowseLink } from "../../../helpers/routes"; | ||
import { useCallback, useState } from "react"; | ||
import { FetchFn, isFirstPage } from "../../../features/feed/Feed"; | ||
import useClient from "../../../helpers/useClient"; | ||
import { LIMIT } from "../../../services/lemmy"; | ||
import PostSort from "../../../features/feed/PostSort"; | ||
import { CommunityView, LemmyHttp, ListingType } from "lemmy-js-client"; | ||
import CommunityFeed from "../../../features/feed/CommunityFeed"; | ||
import { isLemmyError } from "../../../helpers/lemmyErrors"; | ||
import useFeedSort from "../../../features/feed/sort/useFeedSort"; | ||
import { compact } from "lodash"; | ||
import AppHeader from "../../../features/shared/AppHeader"; | ||
import ListingTypeFilter from "../../../features/feed/ListingType"; | ||
|
||
interface CommunitiesResultsPageProps { | ||
search?: string; | ||
} | ||
|
||
export default function CommunitiesResultsPage({ | ||
search, | ||
}: CommunitiesResultsPageProps) { | ||
const buildGeneralBrowseLink = useBuildGeneralBrowseLink(); | ||
const client = useClient(); | ||
const [sort, setSort] = useFeedSort("posts"); | ||
const [listingType, setListingType] = useState<ListingType>("All"); | ||
|
||
const fetchFn: FetchFn<CommunityView> = useCallback( | ||
async (pageData) => { | ||
if (isFirstPage(pageData) && search?.includes("@")) { | ||
return compact([await findExactCommunity(search, client)]); | ||
} | ||
|
||
const response = await (search | ||
? client.search({ | ||
limit: LIMIT, | ||
q: search, | ||
type_: "Communities", | ||
listing_type: listingType, | ||
...pageData, | ||
sort, | ||
}) | ||
: client.listCommunities({ | ||
limit: LIMIT, | ||
type_: listingType, | ||
...pageData, | ||
sort, | ||
})); | ||
|
||
return response.communities; | ||
}, | ||
[client, search, sort, listingType], | ||
); | ||
|
||
return ( | ||
<IonPage> | ||
<AppHeader> | ||
<IonToolbar> | ||
<IonButtons slot="start"> | ||
<IonBackButton | ||
text="Search" | ||
defaultHref={buildGeneralBrowseLink("")} | ||
/> | ||
</IonButtons> | ||
|
||
<IonTitle>{search ? <>“{search}”</> : "Communities"}</IonTitle> | ||
|
||
<IonButtons slot="end"> | ||
<ListingTypeFilter | ||
listingType={listingType} | ||
setListingType={setListingType} | ||
/> | ||
<PostSort sort={sort} setSort={setSort} /> | ||
</IonButtons> | ||
</IonToolbar> | ||
</AppHeader> | ||
<IonContent> | ||
<CommunityFeed fetchFn={fetchFn} /> | ||
</IonContent> | ||
</IonPage> | ||
); | ||
} | ||
|
||
async function findExactCommunity( | ||
name: string, | ||
client: LemmyHttp, | ||
): Promise<CommunityView | undefined> { | ||
const sanitizedName = name.startsWith("!") ? name.slice(1) : name; | ||
|
||
try { | ||
return (await client.getCommunity({ name: sanitizedName })).community_view; | ||
} catch (error) { | ||
if (isLemmyError(error, "couldnt_find_community")) return; | ||
|
||
throw error; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,89 +1,9 @@ | ||
import { | ||
IonBackButton, | ||
IonButtons, | ||
IonContent, | ||
IonPage, | ||
IonTitle, | ||
IonToolbar, | ||
} from "@ionic/react"; | ||
import { useBuildGeneralBrowseLink } from "../../../../helpers/routes"; | ||
import { useCallback } from "react"; | ||
import { FetchFn, isFirstPage } from "../../../../features/feed/Feed"; | ||
import useClient from "../../../../helpers/useClient"; | ||
import { LIMIT } from "../../../../services/lemmy"; | ||
import { useParams } from "react-router"; | ||
import PostSort from "../../../../features/feed/PostSort"; | ||
import { CommunityView, LemmyHttp } from "lemmy-js-client"; | ||
import CommunityFeed from "../../../../features/feed/CommunityFeed"; | ||
import { isLemmyError } from "../../../../helpers/lemmyErrors"; | ||
import useFeedSort from "../../../../features/feed/sort/useFeedSort"; | ||
import { compact } from "lodash"; | ||
import AppHeader from "../../../../features/shared/AppHeader"; | ||
import CommunitiesResultsPage from "../CommunitiesResultsPage"; | ||
|
||
export default function SearchCommunitiesPage() { | ||
const { search: _encodedSearch } = useParams<{ search: string }>(); | ||
const buildGeneralBrowseLink = useBuildGeneralBrowseLink(); | ||
const client = useClient(); | ||
const [sort, setSort] = useFeedSort("posts"); | ||
|
||
const search = decodeURIComponent(_encodedSearch); | ||
|
||
const fetchFn: FetchFn<CommunityView> = useCallback( | ||
async (pageData) => { | ||
if (isFirstPage(pageData) && search.includes("@")) { | ||
return compact([await findExactCommunity(search, client)]); | ||
} | ||
|
||
const response = await client.search({ | ||
limit: LIMIT, | ||
q: search, | ||
type_: "Communities", | ||
listing_type: "All", | ||
...pageData, | ||
sort, | ||
}); | ||
|
||
return response.communities; | ||
}, | ||
[client, search, sort], | ||
); | ||
|
||
return ( | ||
<IonPage> | ||
<AppHeader> | ||
<IonToolbar> | ||
<IonButtons slot="start"> | ||
<IonBackButton | ||
text="Search" | ||
defaultHref={buildGeneralBrowseLink("")} | ||
/> | ||
</IonButtons> | ||
|
||
<IonTitle>“{search}”</IonTitle> | ||
|
||
<IonButtons slot="end"> | ||
<PostSort sort={sort} setSort={setSort} /> | ||
</IonButtons> | ||
</IonToolbar> | ||
</AppHeader> | ||
<IonContent> | ||
<CommunityFeed fetchFn={fetchFn} /> | ||
</IonContent> | ||
</IonPage> | ||
); | ||
} | ||
|
||
async function findExactCommunity( | ||
name: string, | ||
client: LemmyHttp, | ||
): Promise<CommunityView | undefined> { | ||
const sanitizedName = name.startsWith("!") ? name.slice(1) : name; | ||
|
||
try { | ||
return (await client.getCommunity({ name: sanitizedName })).community_view; | ||
} catch (error) { | ||
if (isLemmyError(error, "couldnt_find_community")) return; | ||
|
||
throw error; | ||
} | ||
return <CommunitiesResultsPage search={search} />; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters