fix: Update hashtags when (un)following a hashtag (#35101)
This commit is contained in:
parent
d28a4428b5
commit
b9b1500fc5
6 changed files with 107 additions and 65 deletions
|
|
@ -1,4 +1,4 @@
|
|||
import { useEffect, useState, useCallback, useRef } from 'react';
|
||||
import { useEffect, useCallback, useRef } from 'react';
|
||||
|
||||
import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
|
||||
|
||||
|
|
@ -7,8 +7,10 @@ import { Helmet } from 'react-helmet';
|
|||
import { isFulfilled } from '@reduxjs/toolkit';
|
||||
|
||||
import TagIcon from '@/material-icons/400-24px/tag.svg?react';
|
||||
import { unfollowHashtag } from 'mastodon/actions/tags_typed';
|
||||
import { apiGetFollowedTags } from 'mastodon/api/tags';
|
||||
import {
|
||||
fetchFollowedHashtags,
|
||||
unfollowHashtag,
|
||||
} from 'mastodon/actions/tags_typed';
|
||||
import type { ApiHashtagJSON } from 'mastodon/api_types/tags';
|
||||
import { Button } from 'mastodon/components/button';
|
||||
import { Column } from 'mastodon/components/column';
|
||||
|
|
@ -16,7 +18,7 @@ import type { ColumnRef } from 'mastodon/components/column';
|
|||
import { ColumnHeader } from 'mastodon/components/column_header';
|
||||
import { Hashtag } from 'mastodon/components/hashtag';
|
||||
import ScrollableList from 'mastodon/components/scrollable_list';
|
||||
import { useAppDispatch } from 'mastodon/store';
|
||||
import { useAppDispatch, useAppSelector } from 'mastodon/store';
|
||||
|
||||
const messages = defineMessages({
|
||||
heading: { id: 'followed_tags', defaultMessage: 'Followed hashtags' },
|
||||
|
|
@ -59,55 +61,32 @@ const FollowedTag: React.FC<{
|
|||
|
||||
const FollowedTags: React.FC<{ multiColumn: boolean }> = ({ multiColumn }) => {
|
||||
const intl = useIntl();
|
||||
const [tags, setTags] = useState<ApiHashtagJSON[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [next, setNext] = useState<string | undefined>();
|
||||
const dispatch = useAppDispatch();
|
||||
const { tags, loading, next, stale } = useAppSelector(
|
||||
(state) => state.followedTags,
|
||||
);
|
||||
const hasMore = !!next;
|
||||
const columnRef = useRef<ColumnRef>(null);
|
||||
|
||||
useEffect(() => {
|
||||
setLoading(true);
|
||||
|
||||
void apiGetFollowedTags()
|
||||
.then(({ tags, links }) => {
|
||||
const next = links.refs.find((link) => link.rel === 'next');
|
||||
|
||||
setTags(tags);
|
||||
setLoading(false);
|
||||
setNext(next?.uri);
|
||||
|
||||
return '';
|
||||
})
|
||||
.catch(() => {
|
||||
setLoading(false);
|
||||
});
|
||||
}, [setTags, setLoading, setNext]);
|
||||
if (stale) {
|
||||
void dispatch(fetchFollowedHashtags());
|
||||
}
|
||||
}, [dispatch, stale]);
|
||||
|
||||
const handleLoadMore = useCallback(() => {
|
||||
setLoading(true);
|
||||
|
||||
void apiGetFollowedTags(next)
|
||||
.then(({ tags, links }) => {
|
||||
const next = links.refs.find((link) => link.rel === 'next');
|
||||
|
||||
setLoading(false);
|
||||
setTags((previousTags) => [...previousTags, ...tags]);
|
||||
setNext(next?.uri);
|
||||
|
||||
return '';
|
||||
})
|
||||
.catch(() => {
|
||||
setLoading(false);
|
||||
});
|
||||
}, [setTags, setLoading, setNext, next]);
|
||||
if (next) {
|
||||
void dispatch(fetchFollowedHashtags({ next }));
|
||||
}
|
||||
}, [dispatch, next]);
|
||||
|
||||
const handleUnfollow = useCallback(
|
||||
(tagId: string) => {
|
||||
setTags((tags) => tags.filter((tag) => tag.name !== tagId));
|
||||
void dispatch(unfollowHashtag({ tagId }));
|
||||
},
|
||||
[setTags],
|
||||
[dispatch],
|
||||
);
|
||||
|
||||
const columnRef = useRef<ColumnRef>(null);
|
||||
const handleHeaderClick = useCallback(() => {
|
||||
columnRef.current?.scrollTop();
|
||||
}, []);
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import { useEffect, useState } from 'react';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { useIntl, defineMessages } from 'react-intl';
|
||||
|
||||
import TagIcon from '@/material-icons/400-24px/tag.svg?react';
|
||||
import { apiGetFollowedTags } from 'mastodon/api/tags';
|
||||
import type { ApiHashtagJSON } from 'mastodon/api_types/tags';
|
||||
import { fetchFollowedHashtags } from 'mastodon/actions/tags_typed';
|
||||
import { ColumnLink } from 'mastodon/features/ui/components/column_link';
|
||||
import { useAppDispatch, useAppSelector } from 'mastodon/store';
|
||||
|
||||
import { CollapsiblePanel } from './collapsible_panel';
|
||||
|
||||
|
|
@ -24,25 +24,20 @@ const messages = defineMessages({
|
|||
},
|
||||
});
|
||||
|
||||
const TAG_LIMIT = 4;
|
||||
|
||||
export const FollowedTagsPanel: React.FC = () => {
|
||||
const intl = useIntl();
|
||||
const [tags, setTags] = useState<ApiHashtagJSON[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const dispatch = useAppDispatch();
|
||||
const { tags, stale, loading } = useAppSelector(
|
||||
(state) => state.followedTags,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setLoading(true);
|
||||
|
||||
void apiGetFollowedTags(undefined, 4)
|
||||
.then(({ tags }) => {
|
||||
setTags(tags);
|
||||
setLoading(false);
|
||||
|
||||
return '';
|
||||
})
|
||||
.catch(() => {
|
||||
setLoading(false);
|
||||
});
|
||||
}, [setLoading, setTags]);
|
||||
if (stale) {
|
||||
void dispatch(fetchFollowedHashtags());
|
||||
}
|
||||
}, [dispatch, stale]);
|
||||
|
||||
return (
|
||||
<CollapsiblePanel
|
||||
|
|
@ -54,14 +49,14 @@ export const FollowedTagsPanel: React.FC = () => {
|
|||
expandTitle={intl.formatMessage(messages.expand)}
|
||||
loading={loading}
|
||||
>
|
||||
{tags.map((tag) => (
|
||||
{tags.slice(0, TAG_LIMIT).map((tag) => (
|
||||
<ColumnLink
|
||||
transparent
|
||||
icon='hashtag'
|
||||
key={tag.name}
|
||||
iconComponent={TagIcon}
|
||||
text={`#${tag.name}`}
|
||||
to={`/tags/${tag.name}`}
|
||||
transparent
|
||||
/>
|
||||
))}
|
||||
</CollapsiblePanel>
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ export const ColumnLink: React.FC<{
|
|||
method?: string;
|
||||
badge?: React.ReactNode;
|
||||
transparent?: boolean;
|
||||
optional?: boolean;
|
||||
className?: string;
|
||||
id?: string;
|
||||
}> = ({
|
||||
|
|
@ -30,13 +29,11 @@ export const ColumnLink: React.FC<{
|
|||
method,
|
||||
badge,
|
||||
transparent,
|
||||
optional,
|
||||
...other
|
||||
}) => {
|
||||
const match = useRouteMatch(to ?? '');
|
||||
const className = classNames('column-link', {
|
||||
'column-link--transparent': transparent,
|
||||
'column-link--optional': optional,
|
||||
});
|
||||
const badgeElement =
|
||||
typeof badge !== 'undefined' ? (
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue