Add ability to feature and unfeature hashtags from web UI (#34490)
This commit is contained in:
		@@ -1,4 +1,10 @@
 | 
			
		||||
import { apiGetTag, apiFollowTag, apiUnfollowTag } from 'mastodon/api/tags';
 | 
			
		||||
import {
 | 
			
		||||
  apiGetTag,
 | 
			
		||||
  apiFollowTag,
 | 
			
		||||
  apiUnfollowTag,
 | 
			
		||||
  apiFeatureTag,
 | 
			
		||||
  apiUnfeatureTag,
 | 
			
		||||
} from 'mastodon/api/tags';
 | 
			
		||||
import { createDataLoadingThunk } from 'mastodon/store/typed_functions';
 | 
			
		||||
 | 
			
		||||
export const fetchHashtag = createDataLoadingThunk(
 | 
			
		||||
@@ -15,3 +21,13 @@ export const unfollowHashtag = createDataLoadingThunk(
 | 
			
		||||
  'tags/unfollow',
 | 
			
		||||
  ({ tagId }: { tagId: string }) => apiUnfollowTag(tagId),
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
export const featureHashtag = createDataLoadingThunk(
 | 
			
		||||
  'tags/feature',
 | 
			
		||||
  ({ tagId }: { tagId: string }) => apiFeatureTag(tagId),
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
export const unfeatureHashtag = createDataLoadingThunk(
 | 
			
		||||
  'tags/unfeature',
 | 
			
		||||
  ({ tagId }: { tagId: string }) => apiUnfeatureTag(tagId),
 | 
			
		||||
);
 | 
			
		||||
 
 | 
			
		||||
@@ -10,6 +10,12 @@ export const apiFollowTag = (tagId: string) =>
 | 
			
		||||
export const apiUnfollowTag = (tagId: string) =>
 | 
			
		||||
  apiRequestPost<ApiHashtagJSON>(`v1/tags/${tagId}/unfollow`);
 | 
			
		||||
 | 
			
		||||
export const apiFeatureTag = (tagId: string) =>
 | 
			
		||||
  apiRequestPost<ApiHashtagJSON>(`v1/tags/${tagId}/feature`);
 | 
			
		||||
 | 
			
		||||
export const apiUnfeatureTag = (tagId: string) =>
 | 
			
		||||
  apiRequestPost<ApiHashtagJSON>(`v1/tags/${tagId}/unfeature`);
 | 
			
		||||
 | 
			
		||||
export const apiGetFollowedTags = async (url?: string) => {
 | 
			
		||||
  const response = await api().request<ApiHashtagJSON[]>({
 | 
			
		||||
    method: 'GET',
 | 
			
		||||
 
 | 
			
		||||
@@ -10,4 +10,5 @@ export interface ApiHashtagJSON {
 | 
			
		||||
  url: string;
 | 
			
		||||
  history: [ApiHistoryJSON, ...ApiHistoryJSON[]];
 | 
			
		||||
  following?: boolean;
 | 
			
		||||
  featuring?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,8 @@ import {
 | 
			
		||||
  fetchHashtag,
 | 
			
		||||
  followHashtag,
 | 
			
		||||
  unfollowHashtag,
 | 
			
		||||
  featureHashtag,
 | 
			
		||||
  unfeatureHashtag,
 | 
			
		||||
} from 'mastodon/actions/tags_typed';
 | 
			
		||||
import type { ApiHashtagJSON } from 'mastodon/api_types/tags';
 | 
			
		||||
import { Button } from 'mastodon/components/button';
 | 
			
		||||
@@ -28,6 +30,11 @@ const messages = defineMessages({
 | 
			
		||||
    id: 'hashtag.admin_moderation',
 | 
			
		||||
    defaultMessage: 'Open moderation interface for #{name}',
 | 
			
		||||
  },
 | 
			
		||||
  feature: { id: 'hashtag.feature', defaultMessage: 'Feature on profile' },
 | 
			
		||||
  unfeature: {
 | 
			
		||||
    id: 'hashtag.unfeature',
 | 
			
		||||
    defaultMessage: "Don't feature on profile",
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const usesRenderer = (displayNumber: React.ReactNode, pluralReady: number) => (
 | 
			
		||||
@@ -88,22 +95,51 @@ export const HashtagHeader: React.FC<{
 | 
			
		||||
  }, [dispatch, tagId, setTag]);
 | 
			
		||||
 | 
			
		||||
  const menu = useMemo(() => {
 | 
			
		||||
    const tmp = [];
 | 
			
		||||
    const arr = [];
 | 
			
		||||
 | 
			
		||||
    if (
 | 
			
		||||
      tag &&
 | 
			
		||||
      signedIn &&
 | 
			
		||||
      (permissions & PERMISSION_MANAGE_TAXONOMIES) ===
 | 
			
		||||
        PERMISSION_MANAGE_TAXONOMIES
 | 
			
		||||
    ) {
 | 
			
		||||
      tmp.push({
 | 
			
		||||
        text: intl.formatMessage(messages.adminModeration, { name: tag.id }),
 | 
			
		||||
        href: `/admin/tags/${tag.id}`,
 | 
			
		||||
    if (tag && signedIn) {
 | 
			
		||||
      const handleFeature = () => {
 | 
			
		||||
        if (tag.featuring) {
 | 
			
		||||
          void dispatch(unfeatureHashtag({ tagId })).then((result) => {
 | 
			
		||||
            if (isFulfilled(result)) {
 | 
			
		||||
              setTag(result.payload);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return '';
 | 
			
		||||
          });
 | 
			
		||||
        } else {
 | 
			
		||||
          void dispatch(featureHashtag({ tagId })).then((result) => {
 | 
			
		||||
            if (isFulfilled(result)) {
 | 
			
		||||
              setTag(result.payload);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return '';
 | 
			
		||||
          });
 | 
			
		||||
        }
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      arr.push({
 | 
			
		||||
        text: intl.formatMessage(
 | 
			
		||||
          tag.featuring ? messages.unfeature : messages.feature,
 | 
			
		||||
        ),
 | 
			
		||||
        action: handleFeature,
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      arr.push(null);
 | 
			
		||||
 | 
			
		||||
      if (
 | 
			
		||||
        (permissions & PERMISSION_MANAGE_TAXONOMIES) ===
 | 
			
		||||
        PERMISSION_MANAGE_TAXONOMIES
 | 
			
		||||
      ) {
 | 
			
		||||
        arr.push({
 | 
			
		||||
          text: intl.formatMessage(messages.adminModeration, { name: tagId }),
 | 
			
		||||
          href: `/admin/tags/${tag.id}`,
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return tmp;
 | 
			
		||||
  }, [signedIn, permissions, intl, tag]);
 | 
			
		||||
    return arr;
 | 
			
		||||
  }, [setTag, dispatch, tagId, signedIn, permissions, intl, tag]);
 | 
			
		||||
 | 
			
		||||
  const handleFollow = useCallback(() => {
 | 
			
		||||
    if (!signedIn || !tag) {
 | 
			
		||||
 
 | 
			
		||||
@@ -405,8 +405,10 @@
 | 
			
		||||
  "hashtag.counter_by_accounts": "{count, plural, one {{counter} participant} other {{counter} participants}}",
 | 
			
		||||
  "hashtag.counter_by_uses": "{count, plural, one {{counter} post} other {{counter} posts}}",
 | 
			
		||||
  "hashtag.counter_by_uses_today": "{count, plural, one {{counter} post} other {{counter} posts}} today",
 | 
			
		||||
  "hashtag.feature": "Feature on profile",
 | 
			
		||||
  "hashtag.follow": "Follow hashtag",
 | 
			
		||||
  "hashtag.mute": "Mute #{hashtag}",
 | 
			
		||||
  "hashtag.unfeature": "Don't feature on profile",
 | 
			
		||||
  "hashtag.unfollow": "Unfollow hashtag",
 | 
			
		||||
  "hashtags.and_other": "…and {count, plural, other {# more}}",
 | 
			
		||||
  "hints.profiles.followers_may_be_missing": "Followers for this profile may be missing.",
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user