diff --git a/src/components/right/Profile.tsx b/src/components/right/Profile.tsx index f2828f228..a16faea0e 100644 --- a/src/components/right/Profile.tsx +++ b/src/components/right/Profile.tsx @@ -131,6 +131,7 @@ type StateProps = { hasPreviewMediaTab?: boolean; hasGiftsTab?: boolean; gifts?: ApiSavedStarGift[]; + giftsTransitionKey: number; areMembersHidden?: boolean; canAddMembers?: boolean; canDeleteMembers?: boolean; @@ -199,6 +200,7 @@ const Profile: FC = ({ hasPreviewMediaTab, hasGiftsTab, gifts, + giftsTransitionKey, botPreviewMedia, areMembersHidden, canAddMembers, @@ -490,7 +492,7 @@ const Profile: FC = ({ }, [hasMembersTab, activeTab, tabs]); const handleResetGiftsFilter = useLastCallback(() => { - resetGiftProfileFilter(); + resetGiftProfileFilter({ peerId: chatId }); }); useEffect(() => { @@ -827,6 +829,20 @@ const Profile: FC = ({ ); } + const shouldUseTransitionForContent = resultType === 'gifts'; + const contentTransitionKey = giftsTransitionKey; + + function renderContentWithTransition() { + return ( + + {renderContent()} + + ); + } + return ( = ({ onStart={applyTransitionFix} onStop={handleTransitionStop} > - {renderContent()} + {shouldUseTransitionForContent ? renderContentWithTransition() : renderContent()} @@ -952,6 +968,7 @@ export default memo(withGlobal( const hasGiftsTab = Boolean(peerFullInfo?.starGiftCount) && !isSavedDialog; const peerGifts = selectTabState(global).savedGifts.giftsByPeerId[chatId]; + const giftsTransitionKey = selectTabState(global).savedGifts.transitionKey || 0; const isNotDefaultGiftFilter = !selectIsGiftProfileFilterDefault(global); @@ -979,6 +996,7 @@ export default memo(withGlobal( storyIds, hasGiftsTab, gifts: peerGifts?.gifts, + giftsTransitionKey, pinnedStoryIds, archiveStoryIds, storyByIds, diff --git a/src/components/right/RightHeader.tsx b/src/components/right/RightHeader.tsx index b35f72d35..249c5a0a8 100644 --- a/src/components/right/RightHeader.tsx +++ b/src/components/right/RightHeader.tsx @@ -509,7 +509,7 @@ const RightHeader: FC = ({ return ( <>

{lang('ProfileTabGifts')}

- {canUseGiftFilter && ( + {canUseGiftFilter && chatId && (
= ({ icon={giftsSortType === 'byDate' ? 'calendar-filter' : 'cash-circle'} // eslint-disable-next-line react/jsx-no-bind onClick={() => updateGiftProfileFilter( - { filter: { sortType: giftsSortType === 'byDate' ? 'byValue' : 'byDate' } }, + { peerId: chatId, filter: { sortType: giftsSortType === 'byDate' ? 'byValue' : 'byDate' } }, )} > {lang(giftsSortType === 'byDate' ? 'GiftSortByDate' : 'GiftSortByValue')} @@ -532,7 +532,7 @@ const RightHeader: FC = ({ icon={shouldIncludeUnlimitedGifts ? 'check' : 'placeholder'} // eslint-disable-next-line react/jsx-no-bind onClick={() => updateGiftProfileFilter( - { filter: { shouldIncludeUnlimited: !shouldIncludeUnlimitedGifts } }, + { peerId: chatId, filter: { shouldIncludeUnlimited: !shouldIncludeUnlimitedGifts } }, )} > {lang('GiftFilterUnlimited')} @@ -542,7 +542,7 @@ const RightHeader: FC = ({ icon={shouldIncludeLimitedGifts ? 'check' : 'placeholder'} // eslint-disable-next-line react/jsx-no-bind onClick={() => updateGiftProfileFilter( - { filter: { shouldIncludeLimited: !shouldIncludeLimitedGifts } }, + { peerId: chatId, filter: { shouldIncludeLimited: !shouldIncludeLimitedGifts } }, )} > {lang('GiftFilterLimited')} @@ -552,7 +552,7 @@ const RightHeader: FC = ({ icon={shouldIncludeUniqueGifts ? 'check' : 'placeholder'} // eslint-disable-next-line react/jsx-no-bind onClick={() => updateGiftProfileFilter( - { filter: { shouldIncludeUnique: !shouldIncludeUniqueGifts } }, + { peerId: chatId, filter: { shouldIncludeUnique: !shouldIncludeUniqueGifts } }, )} > {lang('GiftFilterUnique')} @@ -565,7 +565,7 @@ const RightHeader: FC = ({ icon={shouldIncludeDisplayedGifts ? 'check' : 'placeholder'} // eslint-disable-next-line react/jsx-no-bind onClick={() => updateGiftProfileFilter( - { filter: { shouldIncludeDisplayed: !shouldIncludeDisplayedGifts } }, + { peerId: chatId, filter: { shouldIncludeDisplayed: !shouldIncludeDisplayedGifts } }, )} > {lang('GiftFilterDisplayed')} @@ -575,7 +575,7 @@ const RightHeader: FC = ({ icon={shouldIncludeHiddenGifts ? 'check' : 'placeholder'} // eslint-disable-next-line react/jsx-no-bind onClick={() => updateGiftProfileFilter( - { filter: { shouldIncludeHidden: !shouldIncludeHiddenGifts } }, + { peerId: chatId, filter: { shouldIncludeHidden: !shouldIncludeHiddenGifts } }, )} > {lang('GiftFilterHidden')} diff --git a/src/global/actions/api/stars.ts b/src/global/actions/api/stars.ts index 3259c66ca..4f40e98d7 100644 --- a/src/global/actions/api/stars.ts +++ b/src/global/actions/api/stars.ts @@ -138,7 +138,7 @@ addActionHandler('loadStarGifts', async (global): Promise => { addActionHandler('loadPeerSavedGifts', async (global, actions, payload): Promise => { const { - peerId, shouldRefresh, tabId = getCurrentTabId(), + peerId, shouldRefresh, withTransition, tabId = getCurrentTabId(), } = payload; const peer = selectPeer(global, peerId); @@ -149,20 +149,35 @@ addActionHandler('loadPeerSavedGifts', async (global, actions, payload): Promise if (!shouldRefresh && currentGifts && !localNextOffset) return; // Already loaded all + global = getGlobal(); + const fetchingFilter = selectGiftProfileFilter(global, peerId, tabId); + const result = await callApi('fetchSavedStarGifts', { peer, offset: !shouldRefresh ? localNextOffset : '', - filter: selectGiftProfileFilter(global, peerId, tabId), + filter: fetchingFilter, }); - if (!result) { + global = getGlobal(); + const currentFilter = selectGiftProfileFilter(global, peerId, tabId); + + if (!result || currentFilter !== fetchingFilter) { return; } - global = getGlobal(); - const newGifts = currentGifts && !shouldRefresh ? currentGifts.gifts.concat(result.gifts) : result.gifts; + const tabState = selectTabState(global, tabId); + + if (withTransition) { + global = updateTabState(global, { + savedGifts: { + ...tabState.savedGifts, + transitionKey: (tabState?.savedGifts.transitionKey || 0) + 1, + }, + }, tabId); + } + global = replacePeerSavedGifts(global, peerId, newGifts, result.nextOffset, tabId); setGlobal(global); }); diff --git a/src/global/actions/ui/payments.ts b/src/global/actions/ui/payments.ts index 1de0cd4a0..492df69b8 100644 --- a/src/global/actions/ui/payments.ts +++ b/src/global/actions/ui/payments.ts @@ -2,7 +2,7 @@ import type { ActionReturnType } from '../../types'; import { DEFAULT_GIFT_PROFILE_FILTER_OPTIONS } from '../../../config'; import { getCurrentTabId } from '../../../util/establishMultitabRole'; -import { addActionHandler } from '../../index'; +import { addActionHandler, setGlobal } from '../../index'; import { clearPayment, updatePayment, @@ -68,7 +68,7 @@ addActionHandler('closeGiftCodeModal', (global, actions, payload): ActionReturnT }); addActionHandler('updateGiftProfileFilter', (global, actions, payload): ActionReturnType => { - const { filter, tabId = getCurrentTabId() } = payload || {}; + const { filter, peerId, tabId = getCurrentTabId() } = payload || {}; const tabState = selectTabState(global, tabId); const prevFilter = tabState.savedGifts.filter; @@ -98,23 +98,40 @@ addActionHandler('updateGiftProfileFilter', (global, actions, payload): ActionRe }; } - return updateTabState(global, { + global = updateTabState(global, { savedGifts: { - giftsByPeerId: {}, + ...tabState.savedGifts, + giftsByPeerId: { + [peerId]: tabState.savedGifts.giftsByPeerId[peerId], + }, filter: updatedFilter, }, }, tabId); + setGlobal(global); + + actions.loadPeerSavedGifts({ + peerId, shouldRefresh: true, withTransition: true, tabId: tabState.id, + }); }); addActionHandler('resetGiftProfileFilter', (global, actions, payload): ActionReturnType => { - const { tabId = getCurrentTabId() } = payload || {}; + const { peerId, tabId = getCurrentTabId() } = payload || {}; + const tabState = selectTabState(global, tabId); - return updateTabState(global, { + global = updateTabState(global, { savedGifts: { - giftsByPeerId: {}, + ...tabState.savedGifts, + giftsByPeerId: { + [peerId]: tabState.savedGifts.giftsByPeerId[peerId], + }, filter: { ...DEFAULT_GIFT_PROFILE_FILTER_OPTIONS, }, }, }, tabId); + setGlobal(global); + + actions.loadPeerSavedGifts({ + peerId, shouldRefresh: true, withTransition: true, tabId: tabState.id, + }); }); diff --git a/src/global/types/actions.ts b/src/global/types/actions.ts index cb23db0fe..7543d4562 100644 --- a/src/global/types/actions.ts +++ b/src/global/types/actions.ts @@ -2369,6 +2369,7 @@ export interface ActionPayloads { loadPeerSavedGifts: { peerId: string; shouldRefresh?: boolean; + withTransition?: boolean; } & WithTabId; changeGiftVisibility: { gift: ApiInputSavedStarGift; @@ -2397,9 +2398,12 @@ export interface ActionPayloads { closeSuggestedStatusModal: WithTabId | undefined; updateGiftProfileFilter: { + peerId: string; filter: Partial; } & WithTabId; - resetGiftProfileFilter: WithTabId | undefined; + resetGiftProfileFilter: { + peerId: string; + } & WithTabId; // Invoice openInvoice: Exclude & WithTabId; diff --git a/src/global/types/tabState.ts b/src/global/types/tabState.ts index c13405947..ac488894c 100644 --- a/src/global/types/tabState.ts +++ b/src/global/types/tabState.ts @@ -209,6 +209,7 @@ export type TabState = { savedGifts: { giftsByPeerId: Record; filter: GiftProfileFilterOptions; + transitionKey?: number; }; globalSearch: {