diff --git a/app/soapbox/features/ui/components/profile_media_panel.js b/app/soapbox/features/ui/components/profile_media_panel.js
deleted file mode 100644
index 54482ad79..000000000
--- a/app/soapbox/features/ui/components/profile_media_panel.js
+++ /dev/null
@@ -1,128 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import ImmutablePropTypes from 'react-immutable-proptypes';
-import ImmutablePureComponent from 'react-immutable-pure-component';
-import { FormattedMessage, injectIntl } from 'react-intl';
-import { connect } from 'react-redux';
-
-import { openModal } from 'soapbox/actions/modals';
-import Icon from 'soapbox/components/icon';
-import { Spinner } from 'soapbox/components/ui';
-import { getAccountGallery } from 'soapbox/selectors';
-
-import { expandAccountMediaTimeline } from '../../../actions/timelines';
-import MediaItem from '../../account_gallery/components/media_item';
-
-class ProfileMediaPanel extends ImmutablePureComponent {
-
- static propTypes = {
- account: ImmutablePropTypes.record,
- attachments: ImmutablePropTypes.list,
- dispatch: PropTypes.func.isRequired,
- };
-
- state = {
- isLoading: true,
- }
-
- handleOpenMedia = attachment => {
- if (attachment.get('type') === 'video') {
- this.props.dispatch(openModal('VIDEO', { media: attachment, status: attachment.get('status') }));
- } else {
- const media = attachment.getIn(['status', 'media_attachments']);
- const index = media.findIndex(x => x.get('id') === attachment.get('id'));
-
- this.props.dispatch(openModal('MEDIA', { media, index, status: attachment.get('status'), account: attachment.get('account') }));
- }
- }
-
- fetchMedia = () => {
- const { account } = this.props;
-
- if (account) {
- const accountId = account.get('id');
-
- this.props.dispatch(expandAccountMediaTimeline(accountId))
- .then(() => this.setState({ isLoading: false }))
- .catch(() => {});
-
- }
- }
-
- componentDidMount() {
- this.fetchMedia();
- }
-
- componentDidUpdate(prevProps) {
- const oldId = prevProps.account && prevProps.account.get('id');
- const newId = this.props.account && this.props.account.get('id');
-
- if (newId !== oldId) {
- this.setState({ isLoading: true });
- this.fetchMedia();
- }
- }
-
- renderAttachments() {
- const { attachments } = this.props;
- const publicAttachments = attachments.filter(attachment => attachment.getIn(['status', 'visibility']) === 'public');
- const nineAttachments = publicAttachments.slice(0, 9);
-
- if (!nineAttachments.isEmpty()) {
- return (
-
- {nineAttachments.map((attachment, index) => (
-
- ))}
-
- );
- } else {
- return (
-
-
-
- );
- }
- }
-
- render() {
- const { account } = this.props;
- const { isLoading } = this.state;
-
- return (
-
-
-
-
-
-
-
- {account &&
-
- {isLoading ? (
-
- ) : (
- this.renderAttachments()
- )}
-
- }
-
- );
- }
-
-}
-
-const mapStateToProps = (state, { account }) => ({
- attachments: getAccountGallery(state, account.get('id')),
-});
-
-export default injectIntl(
- connect(mapStateToProps, null, null, {
- forwardRef: true,
- },
- )(ProfileMediaPanel));
diff --git a/app/soapbox/features/ui/components/profile_media_panel.tsx b/app/soapbox/features/ui/components/profile_media_panel.tsx
new file mode 100644
index 000000000..29738ec3f
--- /dev/null
+++ b/app/soapbox/features/ui/components/profile_media_panel.tsx
@@ -0,0 +1,90 @@
+import { List as ImmutableList } from 'immutable';
+import React, { useState, useEffect } from 'react';
+import { FormattedMessage } from 'react-intl';
+import { useDispatch } from 'react-redux';
+
+import { openModal } from 'soapbox/actions/modals';
+import { Spinner, Widget } from 'soapbox/components/ui';
+import { useAppSelector } from 'soapbox/hooks';
+import { getAccountGallery } from 'soapbox/selectors';
+
+import { expandAccountMediaTimeline } from '../../../actions/timelines';
+import MediaItem from '../../account_gallery/components/media_item';
+
+import type { Account, Attachment } from 'soapbox/types/entities';
+
+interface IProfileMediaPanel {
+ account?: Account,
+}
+
+const ProfileMediaPanel: React.FC = ({ account }) => {
+ const dispatch = useDispatch();
+
+ const [loading, setLoading] = useState(true);
+
+ const attachments: ImmutableList = useAppSelector((state) => account ? getAccountGallery(state, account?.id) : ImmutableList());
+
+ const handleOpenMedia = (attachment: Attachment): void => {
+ if (attachment.type === 'video') {
+ dispatch(openModal('VIDEO', { media: attachment, status: attachment.status }));
+ } else {
+ const media = attachment.getIn(['status', 'media_attachments']) as ImmutableList;
+ const index = media.findIndex(x => x.id === attachment.id);
+
+ dispatch(openModal('MEDIA', { media, index, status: attachment.status, account: attachment.account }));
+ }
+ };
+
+ useEffect(() => {
+ setLoading(true);
+
+ if (account) {
+ dispatch(expandAccountMediaTimeline(account.id))
+ // @ts-ignore yes it does
+ .then(() => setLoading(false))
+ .catch(() => {});
+ }
+ }, [account?.id]);
+
+ const renderAttachments = () => {
+ const publicAttachments = attachments.filter(attachment => attachment.getIn(['status', 'visibility']) === 'public');
+ const nineAttachments = publicAttachments.slice(0, 9);
+
+ if (!nineAttachments.isEmpty()) {
+ return (
+
+ {nineAttachments.map((attachment, _index) => (
+
+ ))}
+
+ );
+ } else {
+ return (
+
+
+
+ );
+ }
+ };
+
+ return (
+ }>
+ {account && (
+
+ {loading ? (
+
+ ) : (
+ renderAttachments()
+ )}
+
+ )}
+
+ );
+};
+
+export default ProfileMediaPanel;
diff --git a/app/soapbox/pages/profile_page.js b/app/soapbox/pages/profile_page.js
index 05960b6fe..b4b3854c2 100644
--- a/app/soapbox/pages/profile_page.js
+++ b/app/soapbox/pages/profile_page.js
@@ -13,6 +13,7 @@ import {
WhoToFollowPanel,
TrendsPanel,
ProfileInfoPanel,
+ ProfileMediaPanel,
SignUpPanel,
} from 'soapbox/features/ui/util/async-components';
import { findAccountByUsername } from 'soapbox/selectors';
@@ -155,6 +156,9 @@ class ProfilePage extends ImmutablePureComponent {
{Component => }
)}
+
+ {Component => }
+
{showTrendsPanel && (
{Component => }
diff --git a/app/styles/components/profile-media-panel.scss b/app/styles/components/profile-media-panel.scss
index fb0b6a502..ca13ec4ba 100644
--- a/app/styles/components/profile-media-panel.scss
+++ b/app/styles/components/profile-media-panel.scss
@@ -47,13 +47,11 @@
}
&__list {
- padding: 0 5px;
display: flex;
flex-wrap: wrap;
}
&__empty {
- padding: 0 15px 10px 15px;
font-size: 14px;
color: var(--primary-text-color--faint);
}