Skip to content

Commit

Permalink
implement search in the feed
Browse files Browse the repository at this point in the history
  • Loading branch information
budnik9 committed Dec 11, 2023
1 parent 3ca5e15 commit 9f4c8b6
Show file tree
Hide file tree
Showing 37 changed files with 593 additions and 24 deletions.
2 changes: 2 additions & 0 deletions src/pages/OldCommon/store/selectors.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ export const selectUserProposalList = () =>
createSelector(selectCommons, (state) => state.userProposals);
export const selectCommonActiveTab = () =>
createSelector(selectCommons, (state) => state.activeTab);
export const selectCommonStates = () =>
createSelector(selectCommons, (state) => state.commonStates);
export const selectCommonStateById = (commonId: string) =>
createSelector(
selectCommons,
Expand Down
11 changes: 9 additions & 2 deletions src/pages/commonFeed/CommonFeed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ import {
cacheActions,
commonActions,
selectCommonAction,
selectIsSearchingFeedItems,
selectRecentStreamId,
selectSharedFeedItem,
} from "@/store/states";
Expand Down Expand Up @@ -101,6 +102,7 @@ const CommonFeedComponent: FC<CommonFeedProps> = (props) => {
const user = useSelector(selectUser());
const userId = user?.uid;
const recentStreamId = useSelector(selectRecentStreamId);
const isSearchingFeedItems = useSelector(selectIsSearchingFeedItems);
const [feedLayoutRef, setFeedLayoutRef] = useState<FeedLayoutRef | null>(
null,
);
Expand Down Expand Up @@ -228,7 +230,7 @@ const CommonFeedComponent: FC<CommonFeedProps> = (props) => {
};

const fetchMoreCommonFeedItems = (feedItemId?: string) => {
if (hasMoreCommonFeedItems) {
if (hasMoreCommonFeedItems && !isSearchingFeedItems) {
fetchCommonFeedItems(feedItemId);
}
};
Expand Down Expand Up @@ -527,7 +529,12 @@ const CommonFeedComponent: FC<CommonFeedProps> = (props) => {
commonMember={commonMember}
topFeedItems={topFeedItems}
feedItems={commonFeedItems}
loading={areCommonFeedItemsLoading}
loading={areCommonFeedItemsLoading || isSearchingFeedItems}
emptyText={
hasMoreCommonFeedItems
? ""
: "Looks like there are no matches for your query."
}
batchNumber={batchNumber}
onFetchNext={fetchMoreCommonFeedItems}
renderFeedItemBaseContent={renderFeedItemBaseContent}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
.actionButtonsWrapper {
display: flex;
align-items: center;
justify-content: end;
flex-grow: 1;

& > * {
margin-right: 1rem;
Expand Down
20 changes: 20 additions & 0 deletions src/pages/commonFeed/components/HeaderContent/HeaderContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ import {
CommonMember,
Governance,
} from "@/shared/models";
import { SearchButton, SearchInput } from "@/shared/ui-kit";
import { checkIsProject } from "@/shared/utils";
import {
ActionsButton,
HeaderCommonContent,
HeaderContentWrapper,
NewStreamButton,
} from "./components";
import { useSearchFeedItems } from "./hooks";
import styles from "./HeaderContent.module.scss";

interface HeaderContentProps {
Expand All @@ -27,6 +29,8 @@ const HeaderContent: FC<HeaderContentProps> = (props) => {
const { className, common, commonMember, governance } = props;
const isMobileVersion = useIsTabletView();
const commonFollow = useCommonFollow(common.id, commonMember);
const { searchValue, searchInputToggle, onChangeSearchValue, onCloseSearch } =
useSearchFeedItems();
const showFollowIcon =
!isMobileVersion &&
(commonFollow.isFollowInProgress
Expand All @@ -45,6 +49,22 @@ const HeaderContent: FC<HeaderContentProps> = (props) => {
showFollowIcon={showFollowIcon}
/>
<div className={styles.actionButtonsWrapper}>
{!isMobileVersion && (
<>
{searchInputToggle.isToggledOn && (
<SearchInput
value={searchValue}
placeholder="Search spaces"
onChange={onChangeSearchValue}
onClose={onCloseSearch}
autoFocus
/>
)}
{!searchInputToggle.isToggledOn && (
<SearchButton onClick={searchInputToggle.setToggleOn} />
)}
</>
)}
<NewStreamButton
commonId={common.id}
commonMember={commonMember}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
.container {
display: flex;
overflow: hidden;
max-width: 400px;
}

.openSidenavButton {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./useSearchFeedItems";
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { useCallback, useEffect, useState } from "react";
import { useDispatch } from "react-redux";
import { debounce } from "lodash";
import { ToggleState, useToggle } from "@/shared/hooks";
import { commonActions } from "@/store/states";

interface Return {
searchValue: string;
searchInputToggle: ToggleState;
onChangeSearchValue: (value: string) => void;
onCloseSearch: () => void;
}

export const useSearchFeedItems = (): Return => {
const dispatch = useDispatch();
const [searchValue, setSearchValue] = useState("");
const searchInputToggle = useToggle(false);

const searchFeedItems = debounce((value: string) => {
dispatch(commonActions.searchFeedItems(value));
}, 300);

useEffect(() => {
return () => {
dispatch(commonActions.resetSearchState());
};
}, []);

const onChangeSearchValue = useCallback((value: string) => {
setSearchValue(value);
searchFeedItems(value);
}, []);

const onCloseSearch = useCallback(() => {
searchInputToggle.setToggleOff();
onChangeSearchValue("");
}, []);

return {
searchValue,
searchInputToggle,
onChangeSearchValue,
onCloseSearch,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ import { Modal } from "@/shared/components";
import { KeyboardKeys } from "@/shared/constants";
import { useDMUserChatChannel } from "@/shared/hooks/useCases";
import { DMUser } from "@/shared/interfaces";
import { Loader } from "@/shared/ui-kit";
import { Loader, SearchInput } from "@/shared/ui-kit";
import { emptyFunction } from "@/shared/utils";
import { inboxActions } from "@/store/states";
import { DirectMessageUserItem, SearchInput } from "./components";
import { DirectMessageUserItem } from "./components";
import { useDMUsers } from "./hooks";
import styles from "./DirectMessageModal.module.scss";

Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
export * from "./DirectMessageUserItem";
export * from "./SearchInput";
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
.content {
display: flex;
align-items: center;
margin-right: 50px;
}

.inboxIcon {
Expand All @@ -34,6 +35,8 @@
.actionButtonsWrapper {
display: flex;
align-items: center;
justify-content: end;
flex-grow: 1;

& > * {
margin-right: 1rem;
Expand Down
16 changes: 16 additions & 0 deletions src/pages/inbox/components/HeaderContent/HeaderContent.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import React, { FC } from "react";
import classNames from "classnames";
import { useSearchFeedItems } from "@/pages/commonFeed/components/HeaderContent/hooks";
import { useIsTabletView } from "@/shared/hooks/viewport";
import { InboxIcon } from "@/shared/icons";
import { SearchButton, SearchInput } from "@/shared/ui-kit";
import { DirectMessageButton } from "../DirectMessageButton";
import { HeaderContent_v04 } from "../HeaderContent_v04";
import { InboxFilterButton } from "../InboxFilterButton";
Expand All @@ -16,6 +18,8 @@ interface HeaderContentProps {
const HeaderContent: FC<HeaderContentProps> = (props) => {
const { className, streamsWithNotificationsAmount } = props;
const isMobileVersion = useIsTabletView();
const { searchValue, searchInputToggle, onChangeSearchValue, onCloseSearch } =
useSearchFeedItems();

if (isMobileVersion) {
return (
Expand All @@ -33,7 +37,19 @@ const HeaderContent: FC<HeaderContentProps> = (props) => {
<h1 className={styles.title}>Inbox</h1>
</div>
<div className={styles.actionButtonsWrapper}>
{searchInputToggle.isToggledOn && (
<SearchInput
value={searchValue}
placeholder="Search spaces"
onChange={onChangeSearchValue}
onClose={onCloseSearch}
autoFocus
/>
)}
{/* <InboxFilterButton /> */}
{!searchInputToggle.isToggledOn && (
<SearchButton onClick={searchInputToggle.setToggleOn} />
)}
<DirectMessageButton
isMobileVersion={isMobileVersion}
ButtonComponent={PlusButton}
Expand Down
20 changes: 20 additions & 0 deletions src/services/Discussion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { Collection, Discussion } from "@/shared/models";
import {
convertObjectDatesToFirestoreTimestamps,
firestoreDataConverter,
transformFirebaseDataList,
} from "@/shared/utils";
import firebase, { isFirestoreCacheError } from "@/shared/utils/firebase";
import Api from "./Api";
Expand Down Expand Up @@ -54,6 +55,25 @@ class DiscussionService {
}
};

public getDiscussionsByIds = async (
ids: string[],
): Promise<Array<Discussion | null>> => {
const queries: firebase.firestore.Query[] = [];

// Firebase allows to use at most 10 items per query for `in` option
for (let i = 0; i < ids.length; i += 10) {
queries.push(
this.getDiscussionCollection().where("id", "in", ids.slice(i, i + 10)),
);
}

const results = await Promise.all(queries.map((query) => query.get()));

return results
.map((result) => transformFirebaseDataList<Discussion | null>(result))
.reduce((acc, items) => [...acc, ...items], []);
};

public createDiscussion = async (
payload: CreateDiscussionDto,
): Promise<Discussion> => {
Expand Down
19 changes: 19 additions & 0 deletions src/services/Proposal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,25 @@ class ProposalService {
);
};

public getProposalsByIds = async (
ids: string[],
): Promise<Array<Proposal | null>> => {
const queries: firebase.firestore.Query[] = [];

// Firebase allows to use at most 10 items per query for `in` option
for (let i = 0; i < ids.length; i += 10) {
queries.push(
this.getProposalCollection().where("id", "in", ids.slice(i, i + 10)),
);
}

const results = await Promise.all(queries.map((query) => query.get()));

return results
.map((result) => transformFirebaseDataList<Proposal | null>(result))
.reduce((acc, items) => [...acc, ...items], []);
};

public checkActiveProposalsExistenceInCommon = async (
commonId: string,
): Promise<boolean> => {
Expand Down
1 change: 1 addition & 0 deletions src/shared/hooks/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@ export { useIsMounted } from "./useIsMounted";
export * from "./usePreventReload";
export { default as useImageSizeCheck } from "./useImageSizeCheck";
export { default as useLightThemeOnly } from "./useLightThemeOnly";
export * from "./useToggle";
9 changes: 8 additions & 1 deletion src/shared/hooks/useCases/useCommonFeedItems.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import { useEffect, useRef } from "react";
import { useDispatch, useSelector } from "react-redux";
import { CommonFeedService } from "@/services";
import { commonActions, FeedItems, selectFeedItems } from "@/store/states";
import {
commonActions,
FeedItems,
selectFeedItems,
selectFilteredFeedItems,
} from "@/store/states";

interface Return
extends Pick<FeedItems, "data" | "loading" | "hasMore" | "batchNumber"> {
Expand All @@ -15,6 +20,7 @@ export const useCommonFeedItems = (
): Return => {
const dispatch = useDispatch();
const feedItems = useSelector(selectFeedItems);
const filteredFeedItems = useSelector(selectFilteredFeedItems);
const idsForNotListeningRef = useRef<string[]>(idsForNotListening || []);

const fetch = (feedItemId?: string) => {
Expand Down Expand Up @@ -74,6 +80,7 @@ export const useCommonFeedItems = (

return {
...feedItems,
data: filteredFeedItems || feedItems.data,
fetch,
};
};
3 changes: 3 additions & 0 deletions src/shared/hooks/useCases/useCommonPinnedFeedItems.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { CommonFeedService } from "@/services";
import {
commonActions,
PinnedFeedItems,
selectFilteredPinnedFeedItems,
selectPinnedFeedItems,
} from "@/store/states";

Expand All @@ -19,6 +20,7 @@ export const useCommonPinnedFeedItems = (
): Return => {
const dispatch = useDispatch();
const pinnedFeedItems = useSelector(selectPinnedFeedItems);
const filteredPinnedFeedItems = useSelector(selectFilteredPinnedFeedItems);
const previousIdsForListening = usePreviousDistinct(idsForListening);

const fetch = () => {
Expand Down Expand Up @@ -57,6 +59,7 @@ export const useCommonPinnedFeedItems = (

return {
...pinnedFeedItems,
data: filteredPinnedFeedItems || pinnedFeedItems.data,
fetch,
};
};
24 changes: 24 additions & 0 deletions src/shared/hooks/useToggle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { useCallback, useState } from "react";

export interface ToggleState {
isToggledOn: boolean;
toggle: () => void;
setToggleOn: () => void;
setToggleOff: () => void;
}

export const useToggle = (
initialValue: boolean | (() => boolean) = false,
): ToggleState => {
const [isToggledOn, setToggle] = useState(initialValue);
const toggle = useCallback(() => setToggle((isOn) => !isOn), []);
const setToggleOn = useCallback(() => setToggle(true), []);
const setToggleOff = useCallback(() => setToggle(false), []);

return {
isToggledOn,
toggle,
setToggleOn,
setToggleOff,
};
};
1 change: 1 addition & 0 deletions src/shared/models/CommonFeed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export enum CommonFeedType {

export interface CommonFeed extends BaseEntity, SoftDeleteEntity {
userId: string;
commonId: string;
data: Record<string, unknown> & {
type: CommonFeedType;
id: string;
Expand Down
7 changes: 7 additions & 0 deletions src/shared/ui-kit/SearchButton/SearchButton.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
@import "../../../constants.scss";

.buttonIcon {
&:hover {
background-color: var(--hover-fill);
}
}
Loading

0 comments on commit 9f4c8b6

Please sign in to comment.