diff --git a/app/soapbox/actions/statuses.js b/app/soapbox/actions/statuses.js index 3433f47f22..cbb1c6ed23 100644 Binary files a/app/soapbox/actions/statuses.js and b/app/soapbox/actions/statuses.js differ diff --git a/app/soapbox/api.ts b/app/soapbox/api.ts index 6c81042bb0..34ed699f84 100644 --- a/app/soapbox/api.ts +++ b/app/soapbox/api.ts @@ -24,6 +24,10 @@ export const getLinks = (response: AxiosResponse): LinkHeader => { return new LinkHeader(response.headers?.link); }; +export const getNextLink = (response: AxiosResponse): string | undefined => { + return getLinks(response).refs.find(link => link.rel === 'next')?.uri; +}; + const getToken = (state: RootState, authType: string) => { return authType === 'app' ? getAppToken(state) : getAccessToken(state); }; diff --git a/app/soapbox/features/status/index.tsx b/app/soapbox/features/status/index.tsx index 2c8e1a75ce..9795bcb8d0 100644 --- a/app/soapbox/features/status/index.tsx +++ b/app/soapbox/features/status/index.tsx @@ -51,7 +51,7 @@ import { hideStatus, revealStatus, } from '../../actions/statuses'; -import { fetchStatusWithContext } from '../../actions/statuses'; +import { fetchStatusWithContext, fetchNext } from '../../actions/statuses'; import MissingIndicator from '../../components/missing_indicator'; import { textForScreenReader, defaultMediaVisibility } from '../../components/status'; import { makeGetStatus } from '../../selectors'; @@ -189,6 +189,7 @@ interface IStatusState { emojiSelectorFocused: boolean, isLoaded: boolean, error?: AxiosError, + next?: string, } class Status extends ImmutablePureComponent { @@ -200,17 +201,18 @@ class Status extends ImmutablePureComponent { emojiSelectorFocused: false, isLoaded: Boolean(this.props.status), error: undefined, + next: undefined, }; node: HTMLDivElement | null = null; status: HTMLDivElement | null = null; _scrolledIntoView: boolean = false; - fetchData = () => { + fetchData = async() => { const { dispatch, params } = this.props; const { statusId } = params; - - return dispatch(fetchStatusWithContext(statusId)); + const { next } = await dispatch(fetchStatusWithContext(statusId)); + this.setState({ next }); } componentDidMount() { @@ -641,6 +643,16 @@ class Status extends ImmutablePureComponent { return this.fetchData(); } + handleLoadMore = () => { + const { next } = this.state; + + if (next) { + this.props.dispatch(fetchNext(next)).then(({ next }) => { + this.setState({ next }); + }).catch(() => {}); + } + } + render() { const { status, ancestorsIds, descendantsIds, intl } = this.props; @@ -754,7 +766,11 @@ class Status extends ImmutablePureComponent {
- + {children}
diff --git a/app/soapbox/utils/features.ts b/app/soapbox/utils/features.ts index 947dc4d12a..9864e8889c 100644 --- a/app/soapbox/utils/features.ts +++ b/app/soapbox/utils/features.ts @@ -286,6 +286,13 @@ const getInstanceFeatures = (instance: Instance) => { v.software === PLEROMA && gte(v.version, '2.4.50'), ]), + /** + * Supports pagination in threads. + * @see GET /api/v1/statuses/:id/context/ancestors + * @see GET /api/v1/statuses/:id/context/descendants + */ + paginatedContext: v.software === TRUTHSOCIAL, + /** Truth Social account registration API. */ pepe: v.software === TRUTHSOCIAL,