From 452ee87923f4cc63b0986c536aff4e55af053b5e Mon Sep 17 00:00:00 2001 From: Andrey Mikhadyuk Date: Wed, 4 Oct 2023 15:56:46 +0300 Subject: [PATCH 1/9] add lastCommonIdFromFeed to open correct page on Feed tab click --- .../components/LayoutTabs/LayoutTabs.tsx | 40 ++++++++++++++++--- src/store/states/commonLayout/actions.ts | 4 ++ src/store/states/commonLayout/constants.ts | 2 + src/store/states/commonLayout/reducer.ts | 6 +++ src/store/states/commonLayout/selectors.ts | 3 ++ src/store/states/commonLayout/types.ts | 1 + 6 files changed, 51 insertions(+), 5 deletions(-) diff --git a/src/shared/layouts/CommonSidenavLayout/components/LayoutTabs/LayoutTabs.tsx b/src/shared/layouts/CommonSidenavLayout/components/LayoutTabs/LayoutTabs.tsx index c3f386c4fb..589de0ac93 100644 --- a/src/shared/layouts/CommonSidenavLayout/components/LayoutTabs/LayoutTabs.tsx +++ b/src/shared/layouts/CommonSidenavLayout/components/LayoutTabs/LayoutTabs.tsx @@ -1,5 +1,6 @@ -import React, { CSSProperties, FC, ReactNode } from "react"; -import { useSelector } from "react-redux"; +import React, { CSSProperties, FC, ReactNode, useEffect } from "react"; +import { useDispatch, useSelector } from "react-redux"; +import { useParams } from "react-router"; import { useHistory } from "react-router-dom"; import classNames from "classnames"; import { @@ -7,9 +8,12 @@ import { selectUserStreamsWithNotificationsAmount, } from "@/pages/Auth/store/selectors"; import { Tab, Tabs } from "@/shared/components"; +import { ROUTE_PATHS } from "@/shared/constants"; import { useRoutesContext } from "@/shared/contexts"; import { Avatar2Icon, BlocksIcon, InboxIcon } from "@/shared/icons"; -import { openSidenav } from "@/shared/utils"; +import { matchOneOfRoutes, openSidenav } from "@/shared/utils"; +import { selectCommonLayoutLastCommonIdFromFeed } from "@/store/states"; +import { setLastCommonIdFromFeed } from "@/store/states/commonLayout/actions"; import { LayoutTab } from "../../constants"; import { getActiveLayoutTab, getLayoutTabName } from "./utils"; import styles from "./LayoutTabs.module.scss"; @@ -29,7 +33,13 @@ interface TabConfiguration { const LayoutTabs: FC = (props) => { const { className } = props; const history = useHistory(); - const { getInboxPagePath, getProfilePagePath } = useRoutesContext(); + const { id: commonIdFromUrl } = useParams<{ id: string }>(); + const { getCommonPagePath, getInboxPagePath, getProfilePagePath } = + useRoutesContext(); + const dispatch = useDispatch(); + const lastCommonIdFromFeed = useSelector( + selectCommonLayoutLastCommonIdFromFeed, + ); const isAuthenticated = useSelector(authentificated()); const userStreamsWithNotificationsAmount = useSelector( selectUserStreamsWithNotificationsAmount(), @@ -67,6 +77,14 @@ const LayoutTabs: FC = (props) => { "--items-amount": tabs.length, } as CSSProperties; + const handleSpacesClick = () => { + if (lastCommonIdFromFeed) { + history.push(getCommonPagePath(lastCommonIdFromFeed)); + } else { + openSidenav(); + } + }; + const handleTabChange = (value: unknown) => { if (activeTab === value) { return; @@ -74,7 +92,7 @@ const LayoutTabs: FC = (props) => { switch (value) { case LayoutTab.Spaces: - openSidenav(); + handleSpacesClick(); break; case LayoutTab.Inbox: history.push(getInboxPagePath()); @@ -87,6 +105,18 @@ const LayoutTabs: FC = (props) => { } }; + useEffect(() => { + if ( + matchOneOfRoutes( + history.location.pathname, + [ROUTE_PATHS.COMMON, ROUTE_PATHS.V04_COMMON], + { exact: false }, + ) + ) { + dispatch(setLastCommonIdFromFeed(commonIdFromUrl)); + } + }, [commonIdFromUrl]); + return ( (); +export const setLastCommonIdFromFeed = createStandardAction( + CommonLayoutActionType.SET_LAST_COMMON_ID_FROM_FEED, +)(); + export const clearData = createStandardAction( CommonLayoutActionType.CLEAR_DATA, )(); diff --git a/src/store/states/commonLayout/constants.ts b/src/store/states/commonLayout/constants.ts index 38f9c2f751..4f68f889bc 100644 --- a/src/store/states/commonLayout/constants.ts +++ b/src/store/states/commonLayout/constants.ts @@ -13,6 +13,8 @@ export enum CommonLayoutActionType { SET_CURRENT_COMMON_ID = "@COMMON_LAYOUT/SET_CURRENT_COMMON_ID", + SET_LAST_COMMON_ID_FROM_FEED = "@COMMON_LAYOUT/SET_LAST_COMMON_ID_FROM_FEED", + CLEAR_DATA = "@COMMON_LAYOUT/CLEAR_DATA", CLEAR_DATA_EXCEPT_OF_CURRENT = "@COMMON_LAYOUT/CLEAR_DATA_EXCEPT_OF_CURRENT", diff --git a/src/store/states/commonLayout/reducer.ts b/src/store/states/commonLayout/reducer.ts index 6ee068348b..6c50f3b7b6 100644 --- a/src/store/states/commonLayout/reducer.ts +++ b/src/store/states/commonLayout/reducer.ts @@ -9,6 +9,7 @@ type Action = ActionType; const initialState: CommonLayoutState = { currentCommonId: null, + lastCommonIdFromFeed: null, commons: [], areCommonsLoading: false, areCommonsFetched: false, @@ -123,6 +124,11 @@ export const reducer = createReducer(initialState) nextState.currentCommonId = payload; }), ) + .handleAction(actions.setLastCommonIdFromFeed, (state, { payload }) => + produce(state, (nextState) => { + nextState.lastCommonIdFromFeed = payload; + }), + ) .handleAction(actions.clearData, (state) => produce(state, (nextState) => { clearData(nextState); diff --git a/src/store/states/commonLayout/selectors.ts b/src/store/states/commonLayout/selectors.ts index 4450bf213b..14eae9ebea 100644 --- a/src/store/states/commonLayout/selectors.ts +++ b/src/store/states/commonLayout/selectors.ts @@ -6,6 +6,9 @@ const selectCommonLayout = (state: AppState) => state.commonLayout; export const selectCommonLayoutCommonId = (state: AppState) => state.commonLayout.currentCommonId; +export const selectCommonLayoutLastCommonIdFromFeed = (state: AppState) => + state.commonLayout.lastCommonIdFromFeed; + export const selectCommonLayoutCommons = (state: AppState) => state.commonLayout.commons; diff --git a/src/store/states/commonLayout/types.ts b/src/store/states/commonLayout/types.ts index fde59ed117..f473a76ee1 100644 --- a/src/store/states/commonLayout/types.ts +++ b/src/store/states/commonLayout/types.ts @@ -2,6 +2,7 @@ import { ProjectsStateItem } from "../projects"; export interface CommonLayoutState { currentCommonId: string | null; + lastCommonIdFromFeed: string | null; commons: ProjectsStateItem[]; areCommonsLoading: boolean; areCommonsFetched: boolean; From 227331aae080597dc90d8f3a8392b9da0c3af980 Mon Sep 17 00:00:00 2001 From: Andrey Mikhadyuk Date: Thu, 5 Oct 2023 11:05:42 +0300 Subject: [PATCH 2/9] add header and tabs to feed loading state --- src/pages/commonFeed/CommonFeed.tsx | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/pages/commonFeed/CommonFeed.tsx b/src/pages/commonFeed/CommonFeed.tsx index a1ed5b2049..20d72dd7b0 100644 --- a/src/pages/commonFeed/CommonFeed.tsx +++ b/src/pages/commonFeed/CommonFeed.tsx @@ -29,6 +29,7 @@ import { useRoutesContext } from "@/shared/contexts"; import { useAuthorizedModal, useQueryParams } from "@/shared/hooks"; import { useCommonFeedItems, useUserCommonIds } from "@/shared/hooks/useCases"; import { useCommonPinnedFeedItems } from "@/shared/hooks/useCases/useCommonPinnedFeedItems"; +import { useIsTabletView } from "@/shared/hooks/viewport"; import { RightArrowThinIcon } from "@/shared/icons"; import { checkIsFeedItemFollowLayoutItem, @@ -88,6 +89,7 @@ const CommonFeedComponent: FC = (props) => { onActiveItemDataChange, } = props; const { getCommonPagePath, getProfilePagePath } = useRoutesContext(); + const isTabletView = useIsTabletView(); const queryParams = useQueryParams(); const dispatch = useDispatch(); const history = useHistory(); @@ -397,23 +399,20 @@ const CommonFeedComponent: FC = (props) => { } }, [rootCommonMember?.id]); - if (!isDataFetched) { - return ( -
- -
+ if (!isDataFetched || !commonData) { + const content = isDataFetched ? ( + + ) : ( + ); - } - if (!commonData) { + return ( <> } /> -
- -
+
{content}
); From 517937197640ccc2c404d2ef49e115ea2ef8eb1a Mon Sep 17 00:00:00 2001 From: Andrey Mikhadyuk Date: Thu, 5 Oct 2023 11:57:36 +0300 Subject: [PATCH 3/9] move header common content to a separate component --- .../HeaderContent/HeaderContent.module.scss | 103 ----------------- .../HeaderContent/HeaderContent.tsx | 51 +++------ .../HeaderCommonContent.module.scss | 105 ++++++++++++++++++ .../HeaderCommonContent.tsx | 63 +++++++++++ .../components/HeaderCommonContent/index.ts | 1 + .../HeaderContent/components/index.ts | 1 + 6 files changed, 184 insertions(+), 140 deletions(-) create mode 100644 src/pages/commonFeed/components/HeaderContent/components/HeaderCommonContent/HeaderCommonContent.module.scss create mode 100644 src/pages/commonFeed/components/HeaderContent/components/HeaderCommonContent/HeaderCommonContent.tsx create mode 100644 src/pages/commonFeed/components/HeaderContent/components/HeaderCommonContent/index.ts diff --git a/src/pages/commonFeed/components/HeaderContent/HeaderContent.module.scss b/src/pages/commonFeed/components/HeaderContent/HeaderContent.module.scss index 3758bde7a9..1a56974e0d 100644 --- a/src/pages/commonFeed/components/HeaderContent/HeaderContent.module.scss +++ b/src/pages/commonFeed/components/HeaderContent/HeaderContent.module.scss @@ -12,109 +12,6 @@ } } -.openSidenavButton { - display: none; - - @include tablet { - display: flex; - } -} - -.commonContent { - display: flex; - overflow: hidden; -} - -.commonLink { - padding: 0 1.5rem 0 1.375rem; - display: flex; - align-items: center; - text-decoration: none; - overflow: hidden; - box-sizing: border-box; - - &:hover { - .commonName { - color: $c-pink-primary; - text-decoration: underline; - } - } - - @include tablet { - padding-left: 0; - padding-right: 0.5rem; - } -} - -.openSidenavIcon { - width: 1.5rem; - height: 1.5rem; - margin-right: 0.625rem; - transform: rotate(180deg); - color: $c-neutrals-600; -} - -.image { - width: 2.125rem; - height: 2.125rem; - margin-right: 0.75rem; - object-fit: cover; - box-sizing: border-box; - - @include tablet { - width: 2rem; - height: 2rem; - margin-right: 0.625rem; - } -} -.imageNonRounded { - border-radius: 0.375rem; -} -.imageRounded { - border-radius: 50%; -} - -.commonInfoWrapper { - display: flex; - flex-direction: column; - overflow: hidden; -} - -.commonMainInfoWrapper { - display: flex; - align-items: center; - column-gap: 8px; -} - -.commonName { - margin: 0; - font-family: PoppinsSans, sans-serif; - font-weight: 500; - font-size: $moderate-small; - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; - - @include tablet { - font-size: $moderate-xsmall; - } -} - -.commonMembersAmount { - margin: 0; - font-size: $mobile-title; - letter-spacing: 0.02em; - color: $c-gray-40; - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; - - @include tablet { - font-family: PoppinsSans, sans-serif; - font-size: $xxsmall-2; - } -} - .actionButtonsWrapper { display: flex; align-items: center; diff --git a/src/pages/commonFeed/components/HeaderContent/HeaderContent.tsx b/src/pages/commonFeed/components/HeaderContent/HeaderContent.tsx index 1636649037..981dd5077d 100644 --- a/src/pages/commonFeed/components/HeaderContent/HeaderContent.tsx +++ b/src/pages/commonFeed/components/HeaderContent/HeaderContent.tsx @@ -1,19 +1,19 @@ import React, { FC } from "react"; -import { NavLink } from "react-router-dom"; import classNames from "classnames"; -import { useRoutesContext } from "@/shared/contexts"; import { useCommonFollow } from "@/shared/hooks/useCases"; import { useIsTabletView } from "@/shared/hooks/viewport"; -import { RightArrowThinIcon, StarIcon } from "@/shared/icons"; import { CirclesPermissions, Common, CommonMember, Governance, } from "@/shared/models"; -import { CommonAvatar, TopNavigationOpenSidenavButton } from "@/shared/ui-kit"; -import { checkIsProject, getPluralEnding } from "@/shared/utils"; -import { ActionsButton, NewStreamButton } from "./components"; +import { checkIsProject } from "@/shared/utils"; +import { + ActionsButton, + HeaderCommonContent, + NewStreamButton, +} from "./components"; import styles from "./HeaderContent.module.scss"; interface HeaderContentProps { @@ -25,45 +25,22 @@ interface HeaderContentProps { const HeaderContent: FC = (props) => { const { className, common, commonMember, governance } = props; - const { getCommonPageAboutTabPath } = useRoutesContext(); const isMobileVersion = useIsTabletView(); const commonFollow = useCommonFollow(common.id, commonMember); - const isProject = checkIsProject(common); const showFollowIcon = commonFollow.isFollowInProgress ? !commonMember?.isFollowing : commonMember?.isFollowing; return (
-
- } - /> - - - -
-
-

{common.name}

- {showFollowIcon && } -
-

- {common.memberCount} member{getPluralEnding(common.memberCount)} -

-
-
-
+
= (props) => { + const { + commonId, + commonName, + commonImage, + isProject, + memberCount, + showFollowIcon = false, + } = props; + const { getCommonPageAboutTabPath } = useRoutesContext(); + + return ( +
+ } + /> + + + +
+
+

{commonName}

+ {showFollowIcon && } +
+

+ {memberCount} member{getPluralEnding(memberCount)} +

+
+
+
+ ); +}; + +export default HeaderCommonContent; diff --git a/src/pages/commonFeed/components/HeaderContent/components/HeaderCommonContent/index.ts b/src/pages/commonFeed/components/HeaderContent/components/HeaderCommonContent/index.ts new file mode 100644 index 0000000000..c704d1dde3 --- /dev/null +++ b/src/pages/commonFeed/components/HeaderContent/components/HeaderCommonContent/index.ts @@ -0,0 +1 @@ +export { default as HeaderCommonContent } from "./HeaderCommonContent"; diff --git a/src/pages/commonFeed/components/HeaderContent/components/index.ts b/src/pages/commonFeed/components/HeaderContent/components/index.ts index 0f8782fc2a..4711e9ed50 100644 --- a/src/pages/commonFeed/components/HeaderContent/components/index.ts +++ b/src/pages/commonFeed/components/HeaderContent/components/index.ts @@ -1,3 +1,4 @@ +export * from "./HeaderCommonContent"; export * from "./NewStreamButton"; export * from "./ShareButton"; export * from "./ActionsButton"; From b1d221d56a2686a4864bbd675f7468977861f64b Mon Sep 17 00:00:00 2001 From: Andrey Mikhadyuk Date: Thu, 5 Oct 2023 12:10:42 +0300 Subject: [PATCH 4/9] extend last common from feed type --- .../components/LayoutTabs/LayoutTabs.tsx | 29 ++++--------------- src/store/states/commonLayout/actions.ts | 8 ++--- src/store/states/commonLayout/constants.ts | 2 +- src/store/states/commonLayout/reducer.ts | 6 ++-- src/store/states/commonLayout/selectors.ts | 4 +-- src/store/states/commonLayout/types.ts | 10 ++++++- 6 files changed, 25 insertions(+), 34 deletions(-) diff --git a/src/shared/layouts/CommonSidenavLayout/components/LayoutTabs/LayoutTabs.tsx b/src/shared/layouts/CommonSidenavLayout/components/LayoutTabs/LayoutTabs.tsx index 589de0ac93..581b04d66f 100644 --- a/src/shared/layouts/CommonSidenavLayout/components/LayoutTabs/LayoutTabs.tsx +++ b/src/shared/layouts/CommonSidenavLayout/components/LayoutTabs/LayoutTabs.tsx @@ -1,6 +1,5 @@ -import React, { CSSProperties, FC, ReactNode, useEffect } from "react"; -import { useDispatch, useSelector } from "react-redux"; -import { useParams } from "react-router"; +import React, { CSSProperties, FC, ReactNode } from "react"; +import { useSelector } from "react-redux"; import { useHistory } from "react-router-dom"; import classNames from "classnames"; import { @@ -8,12 +7,10 @@ import { selectUserStreamsWithNotificationsAmount, } from "@/pages/Auth/store/selectors"; import { Tab, Tabs } from "@/shared/components"; -import { ROUTE_PATHS } from "@/shared/constants"; import { useRoutesContext } from "@/shared/contexts"; import { Avatar2Icon, BlocksIcon, InboxIcon } from "@/shared/icons"; -import { matchOneOfRoutes, openSidenav } from "@/shared/utils"; -import { selectCommonLayoutLastCommonIdFromFeed } from "@/store/states"; -import { setLastCommonIdFromFeed } from "@/store/states/commonLayout/actions"; +import { openSidenav } from "@/shared/utils"; +import { selectCommonLayoutLastCommonFromFeed } from "@/store/states"; import { LayoutTab } from "../../constants"; import { getActiveLayoutTab, getLayoutTabName } from "./utils"; import styles from "./LayoutTabs.module.scss"; @@ -33,12 +30,10 @@ interface TabConfiguration { const LayoutTabs: FC = (props) => { const { className } = props; const history = useHistory(); - const { id: commonIdFromUrl } = useParams<{ id: string }>(); const { getCommonPagePath, getInboxPagePath, getProfilePagePath } = useRoutesContext(); - const dispatch = useDispatch(); const lastCommonIdFromFeed = useSelector( - selectCommonLayoutLastCommonIdFromFeed, + selectCommonLayoutLastCommonFromFeed, ); const isAuthenticated = useSelector(authentificated()); const userStreamsWithNotificationsAmount = useSelector( @@ -79,7 +74,7 @@ const LayoutTabs: FC = (props) => { const handleSpacesClick = () => { if (lastCommonIdFromFeed) { - history.push(getCommonPagePath(lastCommonIdFromFeed)); + history.push(getCommonPagePath(lastCommonIdFromFeed.id)); } else { openSidenav(); } @@ -105,18 +100,6 @@ const LayoutTabs: FC = (props) => { } }; - useEffect(() => { - if ( - matchOneOfRoutes( - history.location.pathname, - [ROUTE_PATHS.COMMON, ROUTE_PATHS.V04_COMMON], - { exact: false }, - ) - ) { - dispatch(setLastCommonIdFromFeed(commonIdFromUrl)); - } - }, [commonIdFromUrl]); - return ( (); -export const setLastCommonIdFromFeed = createStandardAction( - CommonLayoutActionType.SET_LAST_COMMON_ID_FROM_FEED, -)(); +export const setLastCommonFromFeed = createStandardAction( + CommonLayoutActionType.SET_LAST_COMMON_FROM_FEED, +)(); export const clearData = createStandardAction( CommonLayoutActionType.CLEAR_DATA, diff --git a/src/store/states/commonLayout/constants.ts b/src/store/states/commonLayout/constants.ts index 4f68f889bc..5ac407dafb 100644 --- a/src/store/states/commonLayout/constants.ts +++ b/src/store/states/commonLayout/constants.ts @@ -13,7 +13,7 @@ export enum CommonLayoutActionType { SET_CURRENT_COMMON_ID = "@COMMON_LAYOUT/SET_CURRENT_COMMON_ID", - SET_LAST_COMMON_ID_FROM_FEED = "@COMMON_LAYOUT/SET_LAST_COMMON_ID_FROM_FEED", + SET_LAST_COMMON_FROM_FEED = "@COMMON_LAYOUT/SET_LAST_COMMON_FROM_FEED", CLEAR_DATA = "@COMMON_LAYOUT/CLEAR_DATA", diff --git a/src/store/states/commonLayout/reducer.ts b/src/store/states/commonLayout/reducer.ts index 6c50f3b7b6..5b718e6a84 100644 --- a/src/store/states/commonLayout/reducer.ts +++ b/src/store/states/commonLayout/reducer.ts @@ -9,7 +9,7 @@ type Action = ActionType; const initialState: CommonLayoutState = { currentCommonId: null, - lastCommonIdFromFeed: null, + lastCommonFromFeed: null, commons: [], areCommonsLoading: false, areCommonsFetched: false, @@ -124,9 +124,9 @@ export const reducer = createReducer(initialState) nextState.currentCommonId = payload; }), ) - .handleAction(actions.setLastCommonIdFromFeed, (state, { payload }) => + .handleAction(actions.setLastCommonFromFeed, (state, { payload }) => produce(state, (nextState) => { - nextState.lastCommonIdFromFeed = payload; + nextState.lastCommonFromFeed = payload; }), ) .handleAction(actions.clearData, (state) => diff --git a/src/store/states/commonLayout/selectors.ts b/src/store/states/commonLayout/selectors.ts index 14eae9ebea..3906927769 100644 --- a/src/store/states/commonLayout/selectors.ts +++ b/src/store/states/commonLayout/selectors.ts @@ -6,8 +6,8 @@ const selectCommonLayout = (state: AppState) => state.commonLayout; export const selectCommonLayoutCommonId = (state: AppState) => state.commonLayout.currentCommonId; -export const selectCommonLayoutLastCommonIdFromFeed = (state: AppState) => - state.commonLayout.lastCommonIdFromFeed; +export const selectCommonLayoutLastCommonFromFeed = (state: AppState) => + state.commonLayout.lastCommonFromFeed; export const selectCommonLayoutCommons = (state: AppState) => state.commonLayout.commons; diff --git a/src/store/states/commonLayout/types.ts b/src/store/states/commonLayout/types.ts index f473a76ee1..64af0fd0a8 100644 --- a/src/store/states/commonLayout/types.ts +++ b/src/store/states/commonLayout/types.ts @@ -2,7 +2,15 @@ import { ProjectsStateItem } from "../projects"; export interface CommonLayoutState { currentCommonId: string | null; - lastCommonIdFromFeed: string | null; + lastCommonFromFeed: { + id: string; + data: { + name: string; + image: string; + isProject: boolean; + memberCount: number; + } | null; + } | null; commons: ProjectsStateItem[]; areCommonsLoading: boolean; areCommonsFetched: boolean; From b09c542581e9d2b52a13d1e7d4dadd75bf419416 Mon Sep 17 00:00:00 2001 From: Andrey Mikhadyuk Date: Thu, 5 Oct 2023 12:36:42 +0300 Subject: [PATCH 5/9] add last common from feed saving --- src/pages/commonFeed/CommonFeed.tsx | 45 ++++++++++++++++--- .../commonFeed/hooks/useCommonData/index.ts | 6 ++- 2 files changed, 44 insertions(+), 7 deletions(-) diff --git a/src/pages/commonFeed/CommonFeed.tsx b/src/pages/commonFeed/CommonFeed.tsx index 20d72dd7b0..3e4e6a9ca2 100644 --- a/src/pages/commonFeed/CommonFeed.tsx +++ b/src/pages/commonFeed/CommonFeed.tsx @@ -47,6 +47,7 @@ import { } from "@/shared/utils"; import { commonActions, + commonLayoutActions, selectCommonAction, selectRecentStreamId, selectSharedFeedItem, @@ -108,6 +109,7 @@ const CommonFeedComponent: FC = (props) => { const commonAction = useSelector(selectCommonAction); const { data: commonData, + stateRef, fetched: isCommonDataFetched, fetchCommonData, } = useCommonData(userId); @@ -399,20 +401,51 @@ const CommonFeedComponent: FC = (props) => { } }, [rootCommonMember?.id]); - if (!isDataFetched || !commonData) { - const content = isDataFetched ? ( - - ) : ( - + useEffect(() => { + return () => { + const common = stateRef.current?.data?.common; + + dispatch( + commonLayoutActions.setLastCommonFromFeed({ + id: commonId, + data: common + ? { + name: common.name, + image: common.image, + isProject: checkIsProject(common), + memberCount: common.memberCount, + } + : null, + }), + ); + }; + }, [commonId]); + + if (!isDataFetched) { + return ( + <> + } + /> +
+ +
+ + ); + } + if (!commonData) { return ( <> } /> -
{content}
+
+ +
); diff --git a/src/pages/commonFeed/hooks/useCommonData/index.ts b/src/pages/commonFeed/hooks/useCommonData/index.ts index ca3086e5f5..c2a84ee823 100644 --- a/src/pages/commonFeed/hooks/useCommonData/index.ts +++ b/src/pages/commonFeed/hooks/useCommonData/index.ts @@ -1,4 +1,4 @@ -import { useCallback, useState } from "react"; +import { RefObject, useCallback, useRef, useState } from "react"; import { last } from "lodash"; import { CommonFeedService, @@ -16,6 +16,7 @@ interface FetchCommonDataOptions { } interface Return extends CombinedState { + stateRef: RefObject; fetchCommonData: (options: FetchCommonDataOptions) => void; resetCommonData: () => void; } @@ -26,6 +27,8 @@ export const useCommonData = (userId?: string): Return => { fetched: false, data: null, }); + const stateRef = useRef(state); + stateRef.current = state; const isLoading = state.loading; const isFetched = state.fetched; const currentCommonId = state.data?.common.id; @@ -115,6 +118,7 @@ export const useCommonData = (userId?: string): Return => { loading: isLoading, fetched: isFetched, data: state.data, + stateRef, fetchCommonData, resetCommonData, }; From 52813bbab906d883af9a09fff15f64585d5b1e1a Mon Sep 17 00:00:00 2001 From: Andrey Mikhadyuk Date: Thu, 5 Oct 2023 12:50:56 +0300 Subject: [PATCH 6/9] create component for wrapper of header component --- .../HeaderContent/HeaderContent.module.scss | 11 ----------- .../components/HeaderContent/HeaderContent.tsx | 6 +++--- .../HeaderContentWrapper.module.scss | 12 ++++++++++++ .../HeaderContentWrapper.tsx | 17 +++++++++++++++++ .../components/HeaderContentWrapper/index.ts | 1 + .../HeaderContent/components/index.ts | 1 + .../components/HeaderContent/index.ts | 1 + 7 files changed, 35 insertions(+), 14 deletions(-) create mode 100644 src/pages/commonFeed/components/HeaderContent/components/HeaderContentWrapper/HeaderContentWrapper.module.scss create mode 100644 src/pages/commonFeed/components/HeaderContent/components/HeaderContentWrapper/HeaderContentWrapper.tsx create mode 100644 src/pages/commonFeed/components/HeaderContent/components/HeaderContentWrapper/index.ts diff --git a/src/pages/commonFeed/components/HeaderContent/HeaderContent.module.scss b/src/pages/commonFeed/components/HeaderContent/HeaderContent.module.scss index 1a56974e0d..9b9b12866c 100644 --- a/src/pages/commonFeed/components/HeaderContent/HeaderContent.module.scss +++ b/src/pages/commonFeed/components/HeaderContent/HeaderContent.module.scss @@ -1,17 +1,6 @@ @import "../../../../constants"; @import "../../../../styles/sizes"; -.container { - padding-right: 1.5rem; - display: flex; - justify-content: space-between; - - @include tablet { - padding-left: 1rem; - padding-right: 1.375rem; - } -} - .actionButtonsWrapper { display: flex; align-items: center; diff --git a/src/pages/commonFeed/components/HeaderContent/HeaderContent.tsx b/src/pages/commonFeed/components/HeaderContent/HeaderContent.tsx index 981dd5077d..58064d5c9b 100644 --- a/src/pages/commonFeed/components/HeaderContent/HeaderContent.tsx +++ b/src/pages/commonFeed/components/HeaderContent/HeaderContent.tsx @@ -1,5 +1,4 @@ import React, { FC } from "react"; -import classNames from "classnames"; import { useCommonFollow } from "@/shared/hooks/useCases"; import { useIsTabletView } from "@/shared/hooks/viewport"; import { @@ -12,6 +11,7 @@ import { checkIsProject } from "@/shared/utils"; import { ActionsButton, HeaderCommonContent, + HeaderContentWrapper, NewStreamButton, } from "./components"; import styles from "./HeaderContent.module.scss"; @@ -32,7 +32,7 @@ const HeaderContent: FC = (props) => { : commonMember?.isFollowing; return ( -
+ = (props) => { isMobileVersion={isMobileVersion} />
-
+ ); }; diff --git a/src/pages/commonFeed/components/HeaderContent/components/HeaderContentWrapper/HeaderContentWrapper.module.scss b/src/pages/commonFeed/components/HeaderContent/components/HeaderContentWrapper/HeaderContentWrapper.module.scss new file mode 100644 index 0000000000..9611291e12 --- /dev/null +++ b/src/pages/commonFeed/components/HeaderContent/components/HeaderContentWrapper/HeaderContentWrapper.module.scss @@ -0,0 +1,12 @@ +@import "../../../../../../styles/sizes"; + +.container { + padding-right: 1.5rem; + display: flex; + justify-content: space-between; + + @include tablet { + padding-left: 1rem; + padding-right: 1.375rem; + } +} diff --git a/src/pages/commonFeed/components/HeaderContent/components/HeaderContentWrapper/HeaderContentWrapper.tsx b/src/pages/commonFeed/components/HeaderContent/components/HeaderContentWrapper/HeaderContentWrapper.tsx new file mode 100644 index 0000000000..74ece9cfdd --- /dev/null +++ b/src/pages/commonFeed/components/HeaderContent/components/HeaderContentWrapper/HeaderContentWrapper.tsx @@ -0,0 +1,17 @@ +import React, { FC } from "react"; +import classNames from "classnames"; +import styles from "./HeaderContentWrapper.module.scss"; + +interface HeaderContentWrapperProps { + className?: string; +} + +const HeaderContentWrapper: FC = (props) => { + const { className, children } = props; + + return ( +
{children}
+ ); +}; + +export default HeaderContentWrapper; diff --git a/src/pages/commonFeed/components/HeaderContent/components/HeaderContentWrapper/index.ts b/src/pages/commonFeed/components/HeaderContent/components/HeaderContentWrapper/index.ts new file mode 100644 index 0000000000..8e86f656d4 --- /dev/null +++ b/src/pages/commonFeed/components/HeaderContent/components/HeaderContentWrapper/index.ts @@ -0,0 +1 @@ +export { default as HeaderContentWrapper } from "./HeaderContentWrapper"; diff --git a/src/pages/commonFeed/components/HeaderContent/components/index.ts b/src/pages/commonFeed/components/HeaderContent/components/index.ts index 4711e9ed50..335a9be924 100644 --- a/src/pages/commonFeed/components/HeaderContent/components/index.ts +++ b/src/pages/commonFeed/components/HeaderContent/components/index.ts @@ -1,4 +1,5 @@ export * from "./HeaderCommonContent"; +export * from "./HeaderContentWrapper"; export * from "./NewStreamButton"; export * from "./ShareButton"; export * from "./ActionsButton"; diff --git a/src/pages/commonFeed/components/HeaderContent/index.ts b/src/pages/commonFeed/components/HeaderContent/index.ts index c67e178f9f..7902f0b924 100644 --- a/src/pages/commonFeed/components/HeaderContent/index.ts +++ b/src/pages/commonFeed/components/HeaderContent/index.ts @@ -1 +1,2 @@ export { default as HeaderContent } from "./HeaderContent"; +export { HeaderCommonContent, HeaderContentWrapper } from "./components"; From 1ad73fd665d5f6e880804952733d59466c56c981 Mon Sep 17 00:00:00 2001 From: Andrey Mikhadyuk Date: Thu, 5 Oct 2023 12:59:17 +0300 Subject: [PATCH 7/9] display header with last common from feed content --- src/pages/commonFeed/BaseCommonFeedPage.tsx | 1 + src/pages/commonFeed/CommonFeed.tsx | 16 +++++++++++---- .../commonFeed/CommonFeedPage.module.scss | 12 +++++++++++ src/pages/commonFeed/CommonFeedPage.tsx | 20 +++++++++++++++++++ 4 files changed, 45 insertions(+), 4 deletions(-) diff --git a/src/pages/commonFeed/BaseCommonFeedPage.tsx b/src/pages/commonFeed/BaseCommonFeedPage.tsx index 4ef9d95c7c..cdda4fcfc7 100644 --- a/src/pages/commonFeed/BaseCommonFeedPage.tsx +++ b/src/pages/commonFeed/BaseCommonFeedPage.tsx @@ -10,6 +10,7 @@ const BaseCommonFeedPage: FC< Pick< CommonFeedProps, | "renderContentWrapper" + | "renderLoadingHeader" | "onActiveItemDataChange" | "feedLayoutOuterStyles" | "feedLayoutSettings" diff --git a/src/pages/commonFeed/CommonFeed.tsx b/src/pages/commonFeed/CommonFeed.tsx index 3e4e6a9ca2..0da50b96fa 100644 --- a/src/pages/commonFeed/CommonFeed.tsx +++ b/src/pages/commonFeed/CommonFeed.tsx @@ -76,6 +76,7 @@ export type RenderCommonFeedContentWrapper = (data: { export interface CommonFeedProps { commonId: string; renderContentWrapper: RenderCommonFeedContentWrapper; + renderLoadingHeader?: (() => ReactNode) | null; feedLayoutOuterStyles?: FeedLayoutOuterStyles; feedLayoutSettings?: FeedLayoutSettings; onActiveItemDataChange?: (data: FeedLayoutItemChangeDataWithType) => void; @@ -85,6 +86,7 @@ const CommonFeedComponent: FC = (props) => { const { commonId, renderContentWrapper: outerContentWrapperRenderer, + renderLoadingHeader, feedLayoutOuterStyles, feedLayoutSettings, onActiveItemDataChange, @@ -422,12 +424,18 @@ const CommonFeedComponent: FC = (props) => { }, [commonId]); if (!isDataFetched) { + const headerEl = renderLoadingHeader ? ( + renderLoadingHeader() + ) : ( + } + /> + ); + return ( <> - } - /> + {headerEl}
diff --git a/src/pages/commonFeed/CommonFeedPage.module.scss b/src/pages/commonFeed/CommonFeedPage.module.scss index ce5a42e8f7..16a73085bc 100644 --- a/src/pages/commonFeed/CommonFeedPage.module.scss +++ b/src/pages/commonFeed/CommonFeedPage.module.scss @@ -11,3 +11,15 @@ .desktopRightPane { top: var(--split-view-top); } + +.headerContentWrapper { + display: none; + + @include tablet { + height: 3.25rem; + padding: 0 1rem; + display: flex; + align-items: center; + overflow: hidden; + } +} diff --git a/src/pages/commonFeed/CommonFeedPage.tsx b/src/pages/commonFeed/CommonFeedPage.tsx index baaf8f513f..e5feeb8e05 100644 --- a/src/pages/commonFeed/CommonFeedPage.tsx +++ b/src/pages/commonFeed/CommonFeedPage.tsx @@ -6,6 +6,7 @@ import { MainRoutesProvider } from "@/shared/contexts"; import { MultipleSpacesLayoutPageContent } from "@/shared/layouts"; import { multipleSpacesLayoutActions, + selectCommonLayoutLastCommonFromFeed, selectMultipleSpacesLayoutMainWidth, } from "@/store/states"; import BaseCommonFeedPage, { @@ -16,6 +17,8 @@ import { FeedLayoutOuterStyles, FeedLayoutSettings, HeaderContent, + HeaderCommonContent, + HeaderContentWrapper, } from "./components"; import { useActiveItemDataChange } from "./hooks"; import { generateSplitViewMaxSizeGetter } from "./utils"; @@ -56,6 +59,7 @@ const CommonFeedPage: FC = () => { const { id: commonId } = useParams(); const dispatch = useDispatch(); const layoutMainWidth = useSelector(selectMultipleSpacesLayoutMainWidth); + const lastCommonFromFeed = useSelector(selectCommonLayoutLastCommonFromFeed); const onActiveItemDataChange = useActiveItemDataChange(); const feedLayoutSettings = useMemo( () => ({ @@ -64,6 +68,21 @@ const CommonFeedPage: FC = () => { }), [layoutMainWidth], ); + const lastCommonFromFeedData = lastCommonFromFeed?.data; + + const renderLoadingHeader = lastCommonFromFeedData + ? () => ( + + + + ) + : null; useEffect(() => { dispatch( @@ -84,6 +103,7 @@ const CommonFeedPage: FC = () => { Date: Thu, 5 Oct 2023 13:10:02 +0300 Subject: [PATCH 8/9] keep old data for same common --- src/store/states/commonLayout/reducer.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/store/states/commonLayout/reducer.ts b/src/store/states/commonLayout/reducer.ts index 5b718e6a84..6a40e72967 100644 --- a/src/store/states/commonLayout/reducer.ts +++ b/src/store/states/commonLayout/reducer.ts @@ -126,7 +126,13 @@ export const reducer = createReducer(initialState) ) .handleAction(actions.setLastCommonFromFeed, (state, { payload }) => produce(state, (nextState) => { - nextState.lastCommonFromFeed = payload; + nextState.lastCommonFromFeed = payload && { + ...payload, + data: + nextState.lastCommonFromFeed?.id === payload.id && !payload.data + ? nextState.lastCommonFromFeed?.data + : payload.data, + }; }), ) .handleAction(actions.clearData, (state) => From 6c75baf14e10f1f8c2f794118b587d3a726dbe98 Mon Sep 17 00:00:00 2001 From: Andrey Mikhadyuk Date: Thu, 5 Oct 2023 15:03:46 +0300 Subject: [PATCH 9/9] add border to the loading feed header --- src/pages/commonFeed/CommonFeedPage.module.scss | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pages/commonFeed/CommonFeedPage.module.scss b/src/pages/commonFeed/CommonFeedPage.module.scss index 16a73085bc..24441d5776 100644 --- a/src/pages/commonFeed/CommonFeedPage.module.scss +++ b/src/pages/commonFeed/CommonFeedPage.module.scss @@ -20,6 +20,8 @@ padding: 0 1rem; display: flex; align-items: center; + border-bottom: 0.0625rem solid $c-light-gray; overflow: hidden; + box-sizing: border-box; } }