From 3fee5f06bd8d6cb6e918f57cdb444428f7c34747 Mon Sep 17 00:00:00 2001 From: zubiden <19638254+zubiden@users.noreply.github.com> Date: Mon, 14 Jul 2025 02:49:06 +0200 Subject: [PATCH] Profile: Fix gift error (#6060) --- src/api/types/stars.ts | 1 + src/components/right/Profile.tsx | 14 ++++++-------- src/global/helpers/stars.ts | 11 +++++++++++ src/global/reducers/users.ts | 12 ++++++++++++ 4 files changed, 30 insertions(+), 8 deletions(-) create mode 100644 src/global/helpers/stars.ts diff --git a/src/api/types/stars.ts b/src/api/types/stars.ts index 3c8f95962..f2588a756 100644 --- a/src/api/types/stars.ts +++ b/src/api/types/stars.ts @@ -96,6 +96,7 @@ export interface ApiSavedStarGift { isPinned?: boolean; isConverted?: boolean; // Local field, used for Action Message upgradeMsgId?: number; // Local field, used for Action Message + localTag?: number; // Local field, used for key in list } export type StarGiftAttributeIdModel = { diff --git a/src/components/right/Profile.tsx b/src/components/right/Profile.tsx index 3fdac29a8..e58b10eca 100644 --- a/src/components/right/Profile.tsx +++ b/src/components/right/Profile.tsx @@ -41,6 +41,7 @@ import { isUserBot, isUserRightBanned, } from '../../global/helpers'; +import { getSavedGiftKey } from '../../global/helpers/stars'; import { selectActiveDownloads, selectChat, @@ -360,10 +361,7 @@ const Profile: FC = ({ const [renderingGifts, setRenderingGifts] = useState(gifts); const { startViewTransition, shouldApplyVtn } = useViewTransition(); - const getGiftId = useLastCallback((gift: ApiSavedStarGift) => ( - `${gift.date}-${gift.fromId}-${gift.gift.id}` - )); - const giftIds = useMemo(() => renderingGifts?.map(getGiftId), [renderingGifts]); + const giftIds = useMemo(() => renderingGifts?.map((gift) => getSavedGiftKey(gift)), [renderingGifts]); const renderingActiveTab = activeTab > tabs.length - 1 ? tabs.length - 1 : activeTab; const tabType = tabs[renderingActiveTab].type; @@ -389,8 +387,8 @@ const Profile: FC = ({ return; } - const prevGiftIds = prevGifts.map(getGiftId); - const newGiftIds = gifts.map(getGiftId); + const prevGiftIds = prevGifts.map((gift) => getSavedGiftKey(gift)); + const newGiftIds = gifts.map((gift) => getSavedGiftKey(gift)); const hasOrderChanged = prevGiftIds.some((id, index) => id !== newGiftIds[index]); if (hasOrderChanged) { @@ -847,8 +845,8 @@ const Profile: FC = ({ return ( diff --git a/src/global/helpers/stars.ts b/src/global/helpers/stars.ts new file mode 100644 index 000000000..665409263 --- /dev/null +++ b/src/global/helpers/stars.ts @@ -0,0 +1,11 @@ +import type { ApiSavedStarGift } from '../../api/types'; + +export function getSavedGiftKey(gift: ApiSavedStarGift, withoutTag?: boolean) { + return [ + gift.date, + gift.fromId, + gift.gift.id, + gift.gift.type === 'starGiftUnique' ? gift.gift.number : undefined, + !withoutTag ? gift.localTag : undefined, + ].filter(Boolean).join('-'); +} diff --git a/src/global/reducers/users.ts b/src/global/reducers/users.ts index 8ef7c8a2d..b065c60e8 100644 --- a/src/global/reducers/users.ts +++ b/src/global/reducers/users.ts @@ -13,6 +13,7 @@ import { areDeepEqual } from '../../util/areDeepEqual'; import { getCurrentTabId } from '../../util/establishMultitabRole'; import { omit, omitUndefined, unique } from '../../util/iteratees'; import { MEMO_EMPTY_ARRAY } from '../../util/memo'; +import { getSavedGiftKey } from '../helpers/stars'; import { selectTabState } from '../selectors'; import { updateTabState } from './tabs'; @@ -332,6 +333,17 @@ export function replacePeerSavedGifts( ): T { const tabState = selectTabState(global, tabId); + // Some non-unique gifts can be entirely identical and break `key` + const keyCounts = new Map(); + gifts.forEach((gift) => { + const id = getSavedGiftKey(gift, true); + const count = keyCounts.get(id) || 0; + if (count > 0) { + gift.localTag = count; + } + keyCounts.set(id, count + 1); + }); + return updateTabState(global, { savedGifts: { ...tabState.savedGifts,