diff --git a/packages/pl-fe/src/actions/compose.ts b/packages/pl-fe/src/actions/compose.ts index 7d246fdbe..b8e9cfe6e 100644 --- a/packages/pl-fe/src/actions/compose.ts +++ b/packages/pl-fe/src/actions/compose.ts @@ -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>(['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); diff --git a/packages/pl-fe/src/actions/custom-emojis.ts b/packages/pl-fe/src/actions/custom-emojis.ts deleted file mode 100644 index ba1151a8c..000000000 --- a/packages/pl-fe/src/actions/custom-emojis.ts +++ /dev/null @@ -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) => ({ - type: CUSTOM_EMOJIS_FETCH_SUCCESS, - custom_emojis, -}); - -const fetchCustomEmojisFail = (error: unknown) => ({ - type: CUSTOM_EMOJIS_FETCH_FAIL, - error, -}); - -type CustomEmojisAction = - ReturnType - | ReturnType - | ReturnType; - -export { - CUSTOM_EMOJIS_FETCH_REQUEST, - CUSTOM_EMOJIS_FETCH_SUCCESS, - CUSTOM_EMOJIS_FETCH_FAIL, - fetchCustomEmojis, - type CustomEmojisAction, -}; diff --git a/packages/pl-fe/src/components/announcements/announcements-panel.tsx b/packages/pl-fe/src/components/announcements/announcements-panel.tsx index 1f66af996..cb1d6c511 100644 --- a/packages/pl-fe/src/components/announcements/announcements-panel.tsx +++ b/packages/pl-fe/src/components/announcements/announcements-panel.tsx @@ -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>((map, emoji) => (map[emoji.shortcode] = emoji, map), {})); +const makeCustomEmojiMap = (items: Array) => items.reduce>((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(); diff --git a/packages/pl-fe/src/components/status-action-bar.tsx b/packages/pl-fe/src/components/status-action-bar.tsx index cb8174599..0554dc5c8 100644 --- a/packages/pl-fe/src/components/status-action-bar.tsx +++ b/packages/pl-fe/src/components/status-action-bar.tsx @@ -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 = ({ ); }; -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) => emojis.find(({ shortcode }) => shortcode === 'longestest_wrench') || emojis.find(({ shortcode }) => shortcode === 'longest_wrench'); const WrenchButton: React.FC = ({ status, @@ -481,7 +477,7 @@ const WrenchButton: React.FC = ({ const { openModal } = useModalsStore(); const { showWrenchButton } = useSettings(); - const hasLongerWrench = useAppSelector(getLongerWrench); + const { data: hasLongerWrench } = useCustomEmojis(getLongerWrench); if (!me || withLabels || !features.emojiReacts || !showWrenchButton) return; diff --git a/packages/pl-fe/src/features/backups/index.tsx b/packages/pl-fe/src/features/backups/index.tsx index acb0ea1cb..22af98463 100644 --- a/packages/pl-fe/src/features/backups/index.tsx +++ b/packages/pl-fe/src/features/backups/index.tsx @@ -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 = ({ 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 => { diff --git a/packages/pl-fe/src/features/emoji/components/emoji-picker-dropdown.tsx b/packages/pl-fe/src/features/emoji/components/emoji-picker-dropdown.tsx index 3209af4e5..42611cae5 100644 --- a/packages/pl-fe/src/features/emoji/components/emoji-picker-dropdown.tsx +++ b/packages/pl-fe/src/features/emoji/components/emoji-picker-dropdown.tsx @@ -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) => { 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) => 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 = ({ 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 = ({ = ({ children }) => { // The user has logged in useEffect(() => { loadAccountData(); - dispatch(fetchCustomEmojis()); + prefetchCustomEmojis(client); }, [!!account]); useEffect(() => { diff --git a/packages/pl-fe/src/queries/instance/use-custom-emojis.ts b/packages/pl-fe/src/queries/instance/use-custom-emojis.ts new file mode 100644 index 000000000..282dac06b --- /dev/null +++ b/packages/pl-fe/src/queries/instance/use-custom-emojis.ts @@ -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 = (select?: (data: Array) => 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 }; diff --git a/packages/pl-fe/src/queries/settings/use-backups.ts b/packages/pl-fe/src/queries/settings/use-backups.ts index 70c7fe205..2cafcf315 100644 --- a/packages/pl-fe/src/queries/settings/use-backups.ts +++ b/packages/pl-fe/src/queries/settings/use-backups.ts @@ -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 }; diff --git a/packages/pl-fe/src/reducers/custom-emojis.test.ts b/packages/pl-fe/src/reducers/custom-emojis.test.ts deleted file mode 100644 index f72df1bac..000000000 --- a/packages/pl-fe/src/reducers/custom-emojis.test.ts +++ /dev/null @@ -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()); - }); -}); diff --git a/packages/pl-fe/src/reducers/custom-emojis.ts b/packages/pl-fe/src/reducers/custom-emojis.ts deleted file mode 100644 index 4273d44c9..000000000 --- a/packages/pl-fe/src/reducers/custom-emojis.ts +++ /dev/null @@ -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 = []; - -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 }; diff --git a/packages/pl-fe/src/reducers/index.ts b/packages/pl-fe/src/reducers/index.ts index ef720af6a..bb18ca1af 100644 --- a/packages/pl-fe/src/reducers/index.ts +++ b/packages/pl-fe/src/reducers/index.ts @@ -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 => { 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) => {