import { useEffect, useCallback } from 'react'; import { FormattedMessage, useIntl, defineMessages } from 'react-intl'; import { List as ImmutableList, isList } from 'immutable'; import { isServerFeatureEnabled } from '@/flavours/glitch/utils/environment'; import PersonIcon from '@/material-icons/400-24px/person.svg?react'; import { openModal } from 'flavours/glitch/actions/modal'; import { expandAccountMediaTimeline } from 'flavours/glitch/actions/timelines'; import { RemoteHint } from 'flavours/glitch/components/remote_hint'; import ScrollableList from 'flavours/glitch/components/scrollable_list'; import { AccountHeader } from 'flavours/glitch/features/account_timeline/components/account_header'; import { LimitedAccountHint } from 'flavours/glitch/features/account_timeline/components/limited_account_hint'; import BundleColumnError from 'flavours/glitch/features/ui/components/bundle_column_error'; import Column from 'flavours/glitch/features/ui/components/column'; import { useAccountId } from 'flavours/glitch/hooks/useAccountId'; import { useAccountVisibility } from 'flavours/glitch/hooks/useAccountVisibility'; import type { MediaAttachment } from 'flavours/glitch/models/media_attachment'; import { useAppSelector, useAppDispatch, createAppSelector, } from 'flavours/glitch/store'; import { MediaItem } from './components/media_item'; const messages = defineMessages({ profile: { id: 'column_header.profile', defaultMessage: 'Profile' }, }); const emptyList = ImmutableList(); const redesignEnabled = isServerFeatureEnabled('profile_redesign'); const selectGalleryTimeline = createAppSelector( [ (_state, accountId?: string | null) => accountId, (state) => state.timelines, (state) => state.accounts, (state) => state.statuses, ], (accountId, timelines, accounts, statuses) => { let items = emptyList; if (!accountId) { return { items, hasMore: false, isLoading: false, withReplies: false, }; } const account = accounts.get(accountId); if (!account) { return { items, hasMore: false, isLoading: false, withReplies: false, }; } const { show_media, show_media_replies } = account; // If the account disabled showing media, don't display anything. if (!show_media && redesignEnabled) { return { items, hasMore: false, isLoading: false, withReplies: false, }; } const withReplies = show_media_replies && redesignEnabled; const timeline = timelines.get( `account:${accountId}:media${withReplies ? ':with_replies' : ''}`, ); const statusIds = timeline?.get('items'); if (isList(statusIds)) { for (const statusId of statusIds) { const status = statuses.get(statusId); items = items.concat( ( status?.get('media_attachments') as ImmutableList ).map((media) => media.set('status', status)), ); } } return { items, hasMore: !!timeline?.get('hasMore'), isLoading: timeline?.get('isLoading') ? true : false, withReplies, }; }, ); export const AccountGallery: React.FC<{ multiColumn: boolean; }> = ({ multiColumn }) => { const intl = useIntl(); const dispatch = useAppDispatch(); const accountId = useAccountId(); const { isLoading, items: attachments, hasMore, withReplies, } = useAppSelector((state) => selectGalleryTimeline(state, accountId)); const { suspended, blockedBy, hidden } = useAccountVisibility(accountId); const maxId = attachments.last()?.getIn(['status', 'id']) as | string | undefined; useEffect(() => { if (accountId) { void dispatch(expandAccountMediaTimeline(accountId, { withReplies })); } }, [dispatch, accountId, withReplies]); const handleLoadMore = useCallback(() => { if (maxId) { void dispatch( expandAccountMediaTimeline(accountId, { maxId, withReplies }), ); } }, [maxId, dispatch, accountId, withReplies]); const handleOpenMedia = useCallback( (attachment: MediaAttachment) => { const statusId = attachment.getIn(['status', 'id']); const lang = attachment.getIn(['status', 'language']); if (attachment.get('type') === 'video') { dispatch( openModal({ modalType: 'VIDEO', modalProps: { media: attachment, statusId, lang, options: { autoPlay: true }, }, }), ); } else if (attachment.get('type') === 'audio') { dispatch( openModal({ modalType: 'AUDIO', modalProps: { media: attachment, statusId, lang, options: { autoPlay: true }, }, }), ); } else { const media = attachment.getIn([ 'status', 'media_attachments', ]) as ImmutableList; const index = media.findIndex( (x) => x.get('id') === attachment.get('id'), ); dispatch( openModal({ modalType: 'MEDIA', modalProps: { media, index, statusId, lang }, }), ); } }, [dispatch], ); if (accountId === null) { return ; } let emptyMessage; if (accountId) { if (suspended) { emptyMessage = ( ); } else if (hidden) { emptyMessage = ; } else if (blockedBy) { emptyMessage = ( ); } else if (attachments.isEmpty()) { emptyMessage = ; } else { emptyMessage = ( ); } } const forceEmptyState = suspended || blockedBy || hidden; return ( ) } alwaysPrepend append={accountId && } scrollKey='account_gallery' showLoading={isLoading} hasMore={!forceEmptyState && hasMore} onLoadMore={handleLoadMore} emptyMessage={emptyMessage} bindToDocument={!multiColumn} > {attachments.map((attachment) => ( ))} ); }; // eslint-disable-next-line import/no-default-export export default AccountGallery;