pl-fe: migrate custom emojis to tanstack query
Signed-off-by: mkljczk <git@mkljczk.pl>
This commit is contained in:
parent
ab70e2a257
commit
f541ba1f11
12 changed files with 56 additions and 114 deletions
|
@ -19,7 +19,7 @@ import { saveSettings } from './settings';
|
|||
import { createStatus } from './statuses';
|
||||
|
||||
import type { EditorState } from 'lexical';
|
||||
import type { Account as BaseAccount, CreateStatusParams, Group, MediaAttachment, Status as BaseStatus, Tag, Poll, ScheduledStatus } from 'pl-api';
|
||||
import type { Account as BaseAccount, CreateStatusParams, CustomEmoji, Group, MediaAttachment, Status as BaseStatus, Tag, Poll, ScheduledStatus } from 'pl-api';
|
||||
import type { AutoSuggestion } from 'pl-fe/components/autosuggest-input';
|
||||
import type { Emoji } from 'pl-fe/features/emoji';
|
||||
import type { Account } from 'pl-fe/normalizers/account';
|
||||
|
@ -595,9 +595,9 @@ const fetchComposeSuggestionsAccounts = throttle((dispatch, getState, composeId,
|
|||
});
|
||||
}, 200, { leading: true, trailing: true });
|
||||
|
||||
const fetchComposeSuggestionsEmojis = (dispatch: AppDispatch, getState: () => RootState, composeId: string, token: string) => {
|
||||
const state = getState();
|
||||
const results = emojiSearch(token.replace(':', ''), { maxResults: 10 }, state.custom_emojis);
|
||||
const fetchComposeSuggestionsEmojis = (dispatch: AppDispatch, composeId: string, token: string) => {
|
||||
const customEmojis = queryClient.getQueryData<Array<CustomEmoji>>(['instance', 'customEmojis']);
|
||||
const results = emojiSearch(token.replace(':', ''), { maxResults: 10 }, customEmojis);
|
||||
|
||||
dispatch(readyComposeSuggestionsEmojis(composeId, token, results));
|
||||
};
|
||||
|
@ -633,7 +633,7 @@ const fetchComposeSuggestions = (composeId: string, token: string) =>
|
|||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
switch (token[0]) {
|
||||
case ':':
|
||||
fetchComposeSuggestionsEmojis(dispatch, getState, composeId, token);
|
||||
fetchComposeSuggestionsEmojis(dispatch, composeId, token);
|
||||
break;
|
||||
case '#':
|
||||
fetchComposeSuggestionsTags(dispatch, getState, composeId, token);
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
import { getClient } from '../api';
|
||||
|
||||
import type { CustomEmoji } from 'pl-api';
|
||||
import type { AppDispatch, RootState } from 'pl-fe/store';
|
||||
|
||||
const CUSTOM_EMOJIS_FETCH_REQUEST = 'CUSTOM_EMOJIS_FETCH_REQUEST' as const;
|
||||
const CUSTOM_EMOJIS_FETCH_SUCCESS = 'CUSTOM_EMOJIS_FETCH_SUCCESS' as const;
|
||||
const CUSTOM_EMOJIS_FETCH_FAIL = 'CUSTOM_EMOJIS_FETCH_FAIL' as const;
|
||||
|
||||
const fetchCustomEmojis = () =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
const me = getState().me;
|
||||
if (!me) return;
|
||||
|
||||
dispatch(fetchCustomEmojisRequest());
|
||||
|
||||
return getClient(getState()).instance.getCustomEmojis().then(response => {
|
||||
dispatch(fetchCustomEmojisSuccess(response));
|
||||
}).catch(error => {
|
||||
dispatch(fetchCustomEmojisFail(error));
|
||||
});
|
||||
};
|
||||
|
||||
const fetchCustomEmojisRequest = () => ({
|
||||
type: CUSTOM_EMOJIS_FETCH_REQUEST,
|
||||
});
|
||||
|
||||
const fetchCustomEmojisSuccess = (custom_emojis: Array<CustomEmoji>) => ({
|
||||
type: CUSTOM_EMOJIS_FETCH_SUCCESS,
|
||||
custom_emojis,
|
||||
});
|
||||
|
||||
const fetchCustomEmojisFail = (error: unknown) => ({
|
||||
type: CUSTOM_EMOJIS_FETCH_FAIL,
|
||||
error,
|
||||
});
|
||||
|
||||
type CustomEmojisAction =
|
||||
ReturnType<typeof fetchCustomEmojisRequest>
|
||||
| ReturnType<typeof fetchCustomEmojisSuccess>
|
||||
| ReturnType<typeof fetchCustomEmojisFail>;
|
||||
|
||||
export {
|
||||
CUSTOM_EMOJIS_FETCH_REQUEST,
|
||||
CUSTOM_EMOJIS_FETCH_SUCCESS,
|
||||
CUSTOM_EMOJIS_FETCH_FAIL,
|
||||
fetchCustomEmojis,
|
||||
type CustomEmojisAction,
|
||||
};
|
|
@ -2,23 +2,21 @@ import clsx from 'clsx';
|
|||
import React, { useState } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import ReactSwipeableViews from 'react-swipeable-views';
|
||||
import { createSelector } from 'reselect';
|
||||
|
||||
import Card from 'pl-fe/components/ui/card';
|
||||
import HStack from 'pl-fe/components/ui/hstack';
|
||||
import Widget from 'pl-fe/components/ui/widget';
|
||||
import { useAppSelector } from 'pl-fe/hooks/use-app-selector';
|
||||
import { useAnnouncements } from 'pl-fe/queries/announcements/use-announcements';
|
||||
import { useCustomEmojis } from 'pl-fe/queries/instance/use-custom-emojis';
|
||||
|
||||
import Announcement from './announcement';
|
||||
|
||||
import type { CustomEmoji } from 'pl-api';
|
||||
import type { RootState } from 'pl-fe/store';
|
||||
|
||||
const customEmojiMap = createSelector([(state: RootState) => state.custom_emojis], items => items.reduce<Record<string, CustomEmoji>>((map, emoji) => (map[emoji.shortcode] = emoji, map), {}));
|
||||
const makeCustomEmojiMap = (items: Array<CustomEmoji>) => items.reduce<Record<string, CustomEmoji>>((map, emoji) => (map[emoji.shortcode] = emoji, map), {});
|
||||
|
||||
const AnnouncementsPanel = () => {
|
||||
const emojiMap = useAppSelector(state => customEmojiMap(state));
|
||||
const { data: emojiMap = {} } = useCustomEmojis(makeCustomEmojiMap);
|
||||
const [index, setIndex] = useState(0);
|
||||
|
||||
const { data: announcements } = useAnnouncements();
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
import { GroupRoles } from 'pl-api';
|
||||
import { type CustomEmoji, GroupRoles } from 'pl-api';
|
||||
import React, { useMemo } from 'react';
|
||||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||
import { useHistory, useRouteMatch } from 'react-router-dom';
|
||||
import { createSelector } from 'reselect';
|
||||
|
||||
import { blockAccount } from 'pl-fe/actions/accounts';
|
||||
import { directCompose, mentionCompose, quoteCompose, replyCompose } from 'pl-fe/actions/compose';
|
||||
|
@ -30,8 +29,8 @@ import { useOwnAccount } from 'pl-fe/hooks/use-own-account';
|
|||
import { useSettings } from 'pl-fe/hooks/use-settings';
|
||||
import { useChats } from 'pl-fe/queries/chats';
|
||||
import { useBlockGroupUserMutation } from 'pl-fe/queries/groups/use-group-blocks';
|
||||
import { useCustomEmojis } from 'pl-fe/queries/instance/use-custom-emojis';
|
||||
import { useTranslationLanguages } from 'pl-fe/queries/instance/use-translation-languages';
|
||||
import { RootState } from 'pl-fe/store';
|
||||
import { useModalsStore } from 'pl-fe/stores/modals';
|
||||
import { useStatusMetaStore } from 'pl-fe/stores/status-meta';
|
||||
import toast from 'pl-fe/toast';
|
||||
|
@ -463,10 +462,7 @@ const DislikeButton: React.FC<IActionButton> = ({
|
|||
);
|
||||
};
|
||||
|
||||
const getLongerWrench = createSelector(
|
||||
[(state: RootState) => state.custom_emojis],
|
||||
(emojis) => emojis.find(({ shortcode }) => shortcode === 'longestest_wrench') || emojis.find(({ shortcode }) => shortcode === 'longest_wrench'),
|
||||
);
|
||||
const getLongerWrench = (emojis: Array<CustomEmoji>) => emojis.find(({ shortcode }) => shortcode === 'longestest_wrench') || emojis.find(({ shortcode }) => shortcode === 'longest_wrench');
|
||||
|
||||
const WrenchButton: React.FC<IActionButton> = ({
|
||||
status,
|
||||
|
@ -481,7 +477,7 @@ const WrenchButton: React.FC<IActionButton> = ({
|
|||
const { openModal } = useModalsStore();
|
||||
const { showWrenchButton } = useSettings();
|
||||
|
||||
const hasLongerWrench = useAppSelector(getLongerWrench);
|
||||
const { data: hasLongerWrench } = useCustomEmojis(getLongerWrench);
|
||||
|
||||
if (!me || withLabels || !features.emojiReacts || !showWrenchButton) return;
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ import HStack from 'pl-fe/components/ui/hstack';
|
|||
import Spinner from 'pl-fe/components/ui/spinner';
|
||||
import Stack from 'pl-fe/components/ui/stack';
|
||||
import Text from 'pl-fe/components/ui/text';
|
||||
import { useBackupsQuery, useCreateBackupMutation } from 'pl-fe/queries/settings/use-backups';
|
||||
import { useBackups, useCreateBackupMutation } from 'pl-fe/queries/settings/use-backups';
|
||||
|
||||
import type { Backup as BackupEntity } from 'pl-api';
|
||||
|
||||
|
@ -62,7 +62,7 @@ const Backup: React.FC<IBackup> = ({ backup }) => {
|
|||
const Backups = () => {
|
||||
const intl = useIntl();
|
||||
|
||||
const { data: backups = [], isLoading } = useBackupsQuery();
|
||||
const { data: backups = [], isLoading } = useBackups();
|
||||
const { mutate: createBackup } = useCreateBackupMutation();
|
||||
|
||||
const handleCreateBackup: React.MouseEventHandler = e => {
|
||||
|
|
|
@ -1,18 +1,17 @@
|
|||
import React, { useEffect, useState, useLayoutEffect, Suspense, useMemo } from 'react';
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
import { createSelector } from 'reselect';
|
||||
|
||||
import { changeSetting, saveSettings } from 'pl-fe/actions/settings';
|
||||
import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch';
|
||||
import { useAppSelector } from 'pl-fe/hooks/use-app-selector';
|
||||
import { useSettings } from 'pl-fe/hooks/use-settings';
|
||||
import { useTheme } from 'pl-fe/hooks/use-theme';
|
||||
import { RootState } from 'pl-fe/store';
|
||||
import { useCustomEmojis } from 'pl-fe/queries/instance/use-custom-emojis';
|
||||
import { useSettingsStore } from 'pl-fe/stores/settings';
|
||||
|
||||
import { buildCustomEmojis } from '../../emoji';
|
||||
import { EmojiPicker } from '../../ui/util/async-components';
|
||||
|
||||
import type { CustomEmoji as BaseCustomEmoji } from 'pl-api';
|
||||
import type { Emoji, CustomEmoji, NativeEmoji } from 'pl-fe/features/emoji';
|
||||
|
||||
const messages = defineMessages({
|
||||
|
@ -87,9 +86,7 @@ const getFrequentlyUsedEmojis = (emojiCounters: Record<string, number>) => {
|
|||
return emojis;
|
||||
};
|
||||
|
||||
const getCustomEmojis = createSelector([
|
||||
(state: RootState) => state.custom_emojis,
|
||||
], emojis => emojis.filter(e => e.visible_in_picker).toSorted((a, b) => {
|
||||
const getCustomEmojis = (emojis: Array<BaseCustomEmoji>) => emojis.filter(e => e.visible_in_picker).toSorted((a, b) => {
|
||||
const aShort = a.shortcode.toLowerCase();
|
||||
const bShort = b.shortcode.toLowerCase();
|
||||
|
||||
|
@ -100,7 +97,7 @@ const getCustomEmojis = createSelector([
|
|||
} else {
|
||||
return 0;
|
||||
}
|
||||
}));
|
||||
});
|
||||
|
||||
// Fixes render bug where popover has a delayed position update
|
||||
const RenderAfter = ({ children, update }: any) => {
|
||||
|
@ -130,7 +127,7 @@ const EmojiPickerDropdown: React.FC<IEmojiPickerDropdown> = ({
|
|||
const theme = useTheme();
|
||||
const { rememberEmojiUse } = useSettingsStore();
|
||||
|
||||
const customEmojis = useAppSelector((state) => getCustomEmojis(state));
|
||||
const { data: customEmojis } = useCustomEmojis(getCustomEmojis);
|
||||
|
||||
const settings = useSettings();
|
||||
const frequentlyUsedEmojis = useMemo(() => getFrequentlyUsedEmojis(settings.frequentlyUsedEmojis), [settings.frequentlyUsedEmojis]);
|
||||
|
@ -217,7 +214,7 @@ const EmojiPickerDropdown: React.FC<IEmojiPickerDropdown> = ({
|
|||
<RenderAfter update={update}>
|
||||
<Suspense>
|
||||
<EmojiPicker
|
||||
custom={withCustom ? [{ emojis: buildCustomEmojis(customEmojis) }] : undefined}
|
||||
custom={withCustom ? [{ emojis: buildCustomEmojis(customEmojis || []) }] : undefined}
|
||||
title={title}
|
||||
onEmojiSelect={handlePick}
|
||||
recent={frequentlyUsedEmojis}
|
||||
|
|
|
@ -3,7 +3,6 @@ import React, { Suspense, lazy, useEffect, useRef } from 'react';
|
|||
import { Redirect, Switch, useHistory, useLocation } from 'react-router-dom';
|
||||
|
||||
import { fetchConfig, fetchReports, fetchUsers } from 'pl-fe/actions/admin';
|
||||
import { fetchCustomEmojis } from 'pl-fe/actions/custom-emojis';
|
||||
import { fetchDraftStatuses } from 'pl-fe/actions/draft-statuses';
|
||||
import { fetchFilters } from 'pl-fe/actions/filters';
|
||||
import { fetchMarker } from 'pl-fe/actions/markers';
|
||||
|
@ -41,6 +40,7 @@ import RemoteInstanceLayout from 'pl-fe/layouts/remote-instance-layout';
|
|||
import SearchLayout from 'pl-fe/layouts/search-layout';
|
||||
import StatusLayout from 'pl-fe/layouts/status-layout';
|
||||
import { prefetchFollowRequests } from 'pl-fe/queries/accounts/use-follow-requests';
|
||||
import { prefetchCustomEmojis } from 'pl-fe/queries/instance/use-custom-emojis';
|
||||
import { useUiStore } from 'pl-fe/stores/ui';
|
||||
import { getVapidKey } from 'pl-fe/utils/auth';
|
||||
import { isStandalone } from 'pl-fe/utils/state';
|
||||
|
@ -445,7 +445,7 @@ const UI: React.FC<IUI> = ({ children }) => {
|
|||
// The user has logged in
|
||||
useEffect(() => {
|
||||
loadAccountData();
|
||||
dispatch(fetchCustomEmojis());
|
||||
prefetchCustomEmojis(client);
|
||||
}, [!!account]);
|
||||
|
||||
useEffect(() => {
|
||||
|
|
30
packages/pl-fe/src/queries/instance/use-custom-emojis.ts
Normal file
30
packages/pl-fe/src/queries/instance/use-custom-emojis.ts
Normal file
|
@ -0,0 +1,30 @@
|
|||
import { queryOptions, useQuery } from '@tanstack/react-query';
|
||||
|
||||
import { buildCustomEmojis } from 'pl-fe/features/emoji';
|
||||
import { addCustomToPool } from 'pl-fe/features/emoji/search';
|
||||
import { useClient } from 'pl-fe/hooks/use-client';
|
||||
|
||||
import { queryClient } from '../client';
|
||||
|
||||
import type { CustomEmoji, PlApiClient } from 'pl-api';
|
||||
|
||||
const customEmojisQueryOptions = (client: PlApiClient) => queryOptions({
|
||||
queryKey: ['instance', 'customEmojis'],
|
||||
queryFn: () => client.instance.getCustomEmojis().then((emojis) => {
|
||||
addCustomToPool(buildCustomEmojis(emojis));
|
||||
return emojis;
|
||||
}),
|
||||
});
|
||||
|
||||
const useCustomEmojis = <T>(select?: (data: Array<CustomEmoji>) => T) => {
|
||||
const client = useClient();
|
||||
|
||||
return useQuery({
|
||||
...customEmojisQueryOptions(client),
|
||||
select: select ?? ((data) => data as T),
|
||||
});
|
||||
};
|
||||
|
||||
const prefetchCustomEmojis = (client: PlApiClient) => queryClient.prefetchQuery(customEmojisQueryOptions(client));
|
||||
|
||||
export { useCustomEmojis, prefetchCustomEmojis };
|
|
@ -4,7 +4,7 @@ import { useClient } from 'pl-fe/hooks/use-client';
|
|||
|
||||
import { queryClient } from '../client';
|
||||
|
||||
const useBackupsQuery = () => {
|
||||
const useBackups = () => {
|
||||
const client = useClient();
|
||||
|
||||
return useQuery({
|
||||
|
@ -26,4 +26,4 @@ const useCreateBackupMutation = () => {
|
|||
});
|
||||
};
|
||||
|
||||
export { useBackupsQuery, useCreateBackupMutation };
|
||||
export { useBackups, useCreateBackupMutation };
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
import { List as ImmutableList } from 'immutable';
|
||||
|
||||
import reducer from './custom-emojis';
|
||||
|
||||
describe('custom_emojis reducer', () => {
|
||||
it('should return the initial state', () => {
|
||||
expect(reducer(undefined, {} as any)).toEqual(ImmutableList());
|
||||
});
|
||||
});
|
|
@ -1,19 +0,0 @@
|
|||
import { buildCustomEmojis } from 'pl-fe/features/emoji';
|
||||
import { addCustomToPool } from 'pl-fe/features/emoji/search';
|
||||
|
||||
import { CUSTOM_EMOJIS_FETCH_SUCCESS, type CustomEmojisAction } from '../actions/custom-emojis';
|
||||
|
||||
import type { CustomEmoji } from 'pl-api';
|
||||
|
||||
const initialState: Array<CustomEmoji> = [];
|
||||
|
||||
const custom_emojis = (state = initialState, action: CustomEmojisAction) => {
|
||||
if (action.type === CUSTOM_EMOJIS_FETCH_SUCCESS) {
|
||||
addCustomToPool(buildCustomEmojis(action.custom_emojis));
|
||||
return action.custom_emojis;
|
||||
}
|
||||
|
||||
return state;
|
||||
};
|
||||
|
||||
export { custom_emojis as default };
|
|
@ -12,7 +12,6 @@ import auth from './auth';
|
|||
import compose from './compose';
|
||||
import contexts from './contexts';
|
||||
import conversations from './conversations';
|
||||
import custom_emojis from './custom-emojis';
|
||||
import domain_lists from './domain-lists';
|
||||
import draft_statuses from './draft-statuses';
|
||||
import filters from './filters';
|
||||
|
@ -45,7 +44,6 @@ const reducers = {
|
|||
compose,
|
||||
contexts,
|
||||
conversations,
|
||||
custom_emojis,
|
||||
domain_lists,
|
||||
draft_statuses,
|
||||
entities,
|
||||
|
@ -83,8 +81,8 @@ const logOut = (state: AppState): ReturnType<typeof appReducer> => {
|
|||
|
||||
const newState = rootReducer(undefined, { type: '' });
|
||||
|
||||
const { instance, plfe, custom_emojis, auth } = state;
|
||||
return { ...newState, instance, plfe, custom_emojis, auth };
|
||||
const { instance, plfe, auth } = state;
|
||||
return { ...newState, instance, plfe, auth };
|
||||
};
|
||||
|
||||
const rootReducer: typeof appReducer = (state, action) => {
|
||||
|
|
Loading…
Reference in a new issue