@@ -146,7 +168,7 @@ const ScrollableList = React.forwardRef
(({
);
};
- /** Render a single item */
+ /** Render a single item. */
const renderItem = (_i: number, element: JSX.Element): JSX.Element => {
if (showPlaceholder) {
return ;
@@ -192,7 +214,7 @@ const ScrollableList = React.forwardRef(({
return 0;
}, [showLoading, initialTopMostItemIndex]);
- /** Render the actual Virtuoso list */
+ /** Render the actual Virtuoso list. */
const renderFeed = (): JSX.Element => (
(({
/>
);
- /** Conditionally render inner elements */
+ /** Conditionally render inner elements. */
const renderBody = (): JSX.Element => {
if (isEmpty) {
return renderEmpty();
diff --git a/app/soapbox/components/status-reply-mentions.tsx b/app/soapbox/components/status-reply-mentions.tsx
index 05a90611e..9f8d890ae 100644
--- a/app/soapbox/components/status-reply-mentions.tsx
+++ b/app/soapbox/components/status-reply-mentions.tsx
@@ -1,4 +1,3 @@
-import { List as ImmutableList } from 'immutable';
import React from 'react';
import { FormattedList, FormattedMessage } from 'react-intl';
import { Link } from 'react-router-dom';
@@ -7,7 +6,7 @@ import { openModal } from 'soapbox/actions/modals';
import HoverRefWrapper from 'soapbox/components/hover_ref_wrapper';
import { useAppDispatch } from 'soapbox/hooks';
-import type { Status } from 'soapbox/types/entities';
+import type { Account, Status } from 'soapbox/types/entities';
interface IStatusReplyMentions {
status: Status,
@@ -19,8 +18,10 @@ const StatusReplyMentions: React.FC = ({ status }) => {
const handleOpenMentionsModal: React.MouseEventHandler = (e) => {
e.stopPropagation();
+ const account = status.account as Account;
+
dispatch(openModal('MENTIONS', {
- username: status.getIn(['account', 'acct']),
+ username: account.acct,
statusId: status.id,
}));
};
@@ -29,7 +30,7 @@ const StatusReplyMentions: React.FC = ({ status }) => {
return null;
}
- const to = status.mentions || ImmutableList();
+ const to = status.mentions;
// The post is a reply, but it has no mentions.
// Rare, but it can happen.
@@ -46,14 +47,14 @@ const StatusReplyMentions: React.FC = ({ status }) => {
// The typical case with a reply-to and a list of mentions.
const accounts = to.slice(0, 2).map(account => (
-
- @{account.get('username')}
+
+ @{account.username}
)).toArray();
if (to.size > 2) {
accounts.push(
-
+
,
);
diff --git a/app/soapbox/components/status_list.tsx b/app/soapbox/components/status_list.tsx
index a421f62a3..37e37f59d 100644
--- a/app/soapbox/components/status_list.tsx
+++ b/app/soapbox/components/status_list.tsx
@@ -14,24 +14,31 @@ import type { VirtuosoHandle } from 'react-virtuoso';
import type { IScrollableList } from 'soapbox/components/scrollable_list';
interface IStatusList extends Omit {
+ /** Unique key to preserve the scroll position when navigating back. */
scrollKey: string,
+ /** List of status IDs to display. */
statusIds: ImmutableOrderedSet,
+ /** Last _unfiltered_ status ID (maxId) for pagination. */
lastStatusId?: string,
+ /** Pinned statuses to show at the top of the feed. */
featuredStatusIds?: ImmutableOrderedSet,
+ /** Pagination callback when the end of the list is reached. */
onLoadMore?: (lastStatusId: string) => void,
+ /** Whether the data is currently being fetched. */
isLoading: boolean,
+ /** Whether the server did not return a complete page. */
isPartial?: boolean,
+ /** Whether we expect an additional page of data. */
hasMore: boolean,
- prepend?: React.ReactNode,
+ /** Message to display when the list is loaded but empty. */
emptyMessage: React.ReactNode,
- alwaysPrepend?: boolean,
+ /** ID of the timeline in Redux. */
timelineId?: string,
- queuedItemSize?: number,
- onScrollToTop?: () => void,
- onScroll?: () => void,
+ /** Whether to display a gap or border between statuses in the list. */
divideType: 'space' | 'border',
}
+/** Feed of statuses, built atop ScrollableList. */
const StatusList: React.FC = ({
statusIds,
lastStatusId,
@@ -68,11 +75,11 @@ const StatusList: React.FC = ({
};
const handleLoadOlder = useCallback(debounce(() => {
- const loadMoreID = lastStatusId || statusIds.last();
- if (onLoadMore && loadMoreID) {
- onLoadMore(loadMoreID);
+ const maxId = lastStatusId || statusIds.last();
+ if (onLoadMore && maxId) {
+ onLoadMore(maxId);
}
- }, 300, { leading: true }), []);
+ }, 300, { leading: true }), [onLoadMore, lastStatusId, statusIds.last()]);
const selectChild = (index: number) => {
node.current?.scrollIntoView({
diff --git a/app/soapbox/components/tombstone.tsx b/app/soapbox/components/tombstone.tsx
index 672d1c5f6..e90125b39 100644
--- a/app/soapbox/components/tombstone.tsx
+++ b/app/soapbox/components/tombstone.tsx
@@ -1,16 +1,30 @@
import React from 'react';
+import { HotKeys } from 'react-hotkeys';
import { FormattedMessage } from 'react-intl';
import { Text } from 'soapbox/components/ui';
+interface ITombstone {
+ id: string,
+ onMoveUp: (statusId: string) => void,
+ onMoveDown: (statusId: string) => void,
+}
+
/** Represents a deleted item. */
-const Tombstone: React.FC = () => {
+const Tombstone: React.FC = ({ id, onMoveUp, onMoveDown }) => {
+ const handlers = {
+ moveUp: () => onMoveUp(id),
+ moveDown: () => onMoveDown(id),
+ };
+
return (
-
-
-
-
-
+
+
+
+
+
+
+
);
};
diff --git a/app/soapbox/features/community_timeline/index.js b/app/soapbox/features/community_timeline/index.js
index 1ccc6076f..cb64b49b3 100644
--- a/app/soapbox/features/community_timeline/index.js
+++ b/app/soapbox/features/community_timeline/index.js
@@ -9,7 +9,7 @@ import { expandCommunityTimeline } from 'soapbox/actions/timelines';
import SubNavigation from 'soapbox/components/sub_navigation';
import { Column } from 'soapbox/components/ui';
-import StatusListContainer from '../ui/containers/status_list_container';
+import Timeline from '../ui/components/timeline';
import ColumnSettings from './containers/column_settings_container';
@@ -81,7 +81,7 @@ class CommunityTimeline extends React.PureComponent {
return (
- {
onSelected={handleSuggestion}
/>
- {
const me = state.get('me');
@@ -90,7 +90,7 @@ class GroupTimeline extends React.PureComponent {
)}
- ({
hasUnread: state.getIn(['timelines', `hashtag:${props.params.id}`, 'unread']) > 0,
@@ -114,7 +114,7 @@ class HashtagTimeline extends React.PureComponent {
return (
- }
) : (
- {
*/}
-
{filterBarContainer}
-
}
-