import React, { useEffect, useRef } from 'react'; import { FormattedMessage } from 'react-intl'; import { useParams } from 'react-router-dom'; import { fetchAccount, fetchAccountByUsername, } from 'soapbox/actions/accounts'; import { openModal } from 'soapbox/actions/modals'; import { expandAccountMediaTimeline } from 'soapbox/actions/timelines'; import LoadMore from 'soapbox/components/load-more'; import MissingIndicator from 'soapbox/components/missing-indicator'; import { Column, Spinner } from 'soapbox/components/ui'; import { useAppDispatch, useAppSelector, useFeatures } from 'soapbox/hooks'; import { getAccountGallery, findAccountByUsername } from 'soapbox/selectors'; import MediaItem from './components/media-item'; import type { List as ImmutableList } from 'immutable'; import type { Attachment, Status } from 'soapbox/types/entities'; interface ILoadMoreMedia { maxId: string | null onLoadMore: (value: string | null) => void } const LoadMoreMedia: React.FC = ({ maxId, onLoadMore }) => { const handleLoadMore = () => { onLoadMore(maxId); }; return ( ); }; const AccountGallery = () => { const dispatch = useAppDispatch(); const { username } = useParams<{ username: string }>(); const features = useFeatures(); const { accountId, unavailable, accountUsername } = useAppSelector((state) => { const me = state.me; const accountFetchError = (state.accounts.get(-1)?.username || '').toLowerCase() === username.toLowerCase(); let accountId: string | -1 | null = -1; let accountUsername = username; if (accountFetchError) { accountId = null; } else { const account = findAccountByUsername(state, username); accountId = account ? (account.id || null) : -1; accountUsername = account?.acct || ''; } const isBlocked = state.relationships.get(String(accountId))?.blocked_by || false; return { accountId, unavailable: (me === accountId) ? false : (isBlocked && !features.blockersVisible), accountUsername, }; }); const isAccount = useAppSelector((state) => !!state.accounts.get(accountId)); const attachments: ImmutableList = useAppSelector((state) => getAccountGallery(state, accountId as string)); const isLoading = useAppSelector((state) => state.timelines.get(`account:${accountId}:media`)?.isLoading); const hasMore = useAppSelector((state) => state.timelines.get(`account:${accountId}:media`)?.hasMore); const node = useRef(null); const handleScrollToBottom = () => { if (hasMore) { handleLoadMore(attachments.size > 0 ? attachments.last()!.status.id : undefined); } }; const handleLoadMore = (maxId: string | null) => { if (accountId && accountId !== -1) { dispatch(expandAccountMediaTimeline(accountId, { maxId })); } }; const handleLoadOlder: React.MouseEventHandler = e => { e.preventDefault(); handleScrollToBottom(); }; const handleOpenMedia = (attachment: Attachment) => { if (attachment.type === 'video') { dispatch(openModal('VIDEO', { media: attachment, status: attachment.status, account: attachment.account })); } else { const media = (attachment.status as Status).media_attachments; const index = media.findIndex((x) => x.id === attachment.id); dispatch(openModal('MEDIA', { media, index, status: attachment.status })); } }; useEffect(() => { if (accountId && accountId !== -1) { dispatch(fetchAccount(accountId)); dispatch(expandAccountMediaTimeline(accountId)); } else { dispatch(fetchAccountByUsername(username)); } }, [accountId]); if (!isAccount && accountId !== -1) { return ( ); } if (accountId === -1 || (!attachments && isLoading)) { return ( ); } let loadOlder = null; if (hasMore && !(isLoading && attachments.size === 0)) { loadOlder = ; } if (unavailable) { return (
); } return (
{attachments.map((attachment, index) => attachment === null ? ( 0 ? (attachments.get(index - 1)?.id || null) : null} onLoadMore={handleLoadMore} /> ) : ( ))} {!isLoading && attachments.size === 0 && (
)} {loadOlder}
{isLoading && attachments.size === 0 && (
)}
); }; export default AccountGallery;