import { useEffect, useState } from '../lib/teact/teact'; import { getGlobal } from '../global'; import type { ApiUser } from '../api/types'; import { SESSION_ACCOUNT_PREFIX } from '../config'; import { getChatAvatarHash } from '../global/helpers'; import { selectIsSynced } from '../global/selectors'; import { preloadImage } from '../util/files'; import { resizeImage } from '../util/imageResize'; import { ACCOUNT_SLOT, getAccountsInfo, storeAccountData } from '../util/multiaccount'; import useSelector from './data/useSelector'; import useInterval from './schedulers/useInterval'; import useLastCallback from './useLastCallback'; import useMedia from './useMedia'; import useThrottledCallback from './useThrottledCallback'; const LOCAL_STORAGE_LISTENING_THROTTLE = 1000; const REFRESH_INTERVAL = 1000 * 60; const PREVIEW_SIZE = 72; export default function useMultiaccountInfo(currentUser?: ApiUser) { const isUpdater = Boolean(currentUser) && getGlobal().authRememberMe; const isSynced = useSelector(selectIsSynced); const [accountsInfo, setAccountsInfo] = useState(getAccountsInfo()); const avatarHash = currentUser && getChatAvatarHash(currentUser); const avatarUrl = useMedia(avatarHash, !isUpdater); const refresh = useThrottledCallback(() => { setAccountsInfo(getAccountsInfo()); }, [], LOCAL_STORAGE_LISTENING_THROTTLE); useEffect(() => { if (!isUpdater || !isSynced) return; storeAccountData(ACCOUNT_SLOT, { userId: currentUser.id, firstName: currentUser.firstName, lastName: currentUser.lastName, emojiStatusId: currentUser.emojiStatus?.documentId, color: currentUser.color?.color, isPremium: currentUser.isPremium, phone: currentUser.phoneNumber, }); refresh(); }, [ isUpdater, currentUser?.emojiStatus?.documentId, currentUser?.firstName, currentUser?.id, currentUser?.lastName, currentUser?.color?.color, currentUser?.isPremium, currentUser?.phoneNumber, refresh, isSynced, ]); const updateAvatar = useLastCallback(async (url: string, abortSignal?: AbortSignal) => { const resizedAvatar = await resizeImage(url, PREVIEW_SIZE, PREVIEW_SIZE); const img = await preloadImage(resizedAvatar); if (abortSignal?.aborted) return; const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d')!; canvas.width = img.width; canvas.height = img.height; ctx.drawImage(img, 0, 0); const dataUrl = canvas.toDataURL('image/png'); storeAccountData(ACCOUNT_SLOT, { avatarUri: dataUrl }); refresh(); }); useEffect(() => { if (!avatarUrl || !isUpdater || !isSynced) return undefined; const controller = new AbortController(); updateAvatar(avatarUrl, controller.signal); return () => { controller.abort(); }; }, [avatarUrl, isSynced, isUpdater]); // Storage event only thrown when other tabs change the storage useInterval(refresh, REFRESH_INTERVAL); useEffect(() => { function handleStorageChange(e: StorageEvent) { if (!e.key?.startsWith(SESSION_ACCOUNT_PREFIX)) return; refresh(); } window.addEventListener('storage', handleStorageChange); return () => { window.removeEventListener('storage', handleStorageChange); }; }, [refresh]); return accountsInfo; }