diff --git a/app/javascript/mastodon/actions/accounts_typed.ts b/app/javascript/mastodon/actions/accounts_typed.ts index fcdec97e08..fe7c7327ce 100644 --- a/app/javascript/mastodon/actions/accounts_typed.ts +++ b/app/javascript/mastodon/actions/accounts_typed.ts @@ -1,18 +1,18 @@ import { createAction } from '@reduxjs/toolkit'; -import { apiRemoveAccountFromFollowers } from 'mastodon/api/accounts'; -import type { ApiAccountJSON } from 'mastodon/api_types/accounts'; +import { + apiRemoveAccountFromFollowers, + apiGetEndorsedAccounts, +} from 'mastodon/api/accounts'; import type { ApiRelationshipJSON } from 'mastodon/api_types/relationships'; import { createDataLoadingThunk } from 'mastodon/store/typed_functions'; +import { importFetchedAccounts } from './importer'; + export const revealAccount = createAction<{ id: string; }>('accounts/revealAccount'); -export const importAccounts = createAction<{ accounts: ApiAccountJSON[] }>( - 'accounts/importAccounts', -); - function actionWithSkipLoadingTrue(args: Args) { return { payload: { @@ -104,3 +104,12 @@ export const removeAccountFromFollowers = createDataLoadingThunk( apiRemoveAccountFromFollowers(accountId), (relationship) => ({ relationship }), ); + +export const fetchEndorsedAccounts = createDataLoadingThunk( + 'accounts/endorsements', + ({ accountId }: { accountId: string }) => apiGetEndorsedAccounts(accountId), + (data, { dispatch }) => { + dispatch(importFetchedAccounts(data)); + return data; + }, +); diff --git a/app/javascript/mastodon/actions/featured_tags.js b/app/javascript/mastodon/actions/featured_tags.js deleted file mode 100644 index 6ee4dee2bc..0000000000 --- a/app/javascript/mastodon/actions/featured_tags.js +++ /dev/null @@ -1,34 +0,0 @@ -import api from '../api'; - -export const FEATURED_TAGS_FETCH_REQUEST = 'FEATURED_TAGS_FETCH_REQUEST'; -export const FEATURED_TAGS_FETCH_SUCCESS = 'FEATURED_TAGS_FETCH_SUCCESS'; -export const FEATURED_TAGS_FETCH_FAIL = 'FEATURED_TAGS_FETCH_FAIL'; - -export const fetchFeaturedTags = (id) => (dispatch, getState) => { - if (getState().getIn(['user_lists', 'featured_tags', id, 'items'])) { - return; - } - - dispatch(fetchFeaturedTagsRequest(id)); - - api().get(`/api/v1/accounts/${id}/featured_tags`) - .then(({ data }) => dispatch(fetchFeaturedTagsSuccess(id, data))) - .catch(err => dispatch(fetchFeaturedTagsFail(id, err))); -}; - -export const fetchFeaturedTagsRequest = (id) => ({ - type: FEATURED_TAGS_FETCH_REQUEST, - id, -}); - -export const fetchFeaturedTagsSuccess = (id, tags) => ({ - type: FEATURED_TAGS_FETCH_SUCCESS, - id, - tags, -}); - -export const fetchFeaturedTagsFail = (id, error) => ({ - type: FEATURED_TAGS_FETCH_FAIL, - id, - error, -}); diff --git a/app/javascript/mastodon/actions/featured_tags.ts b/app/javascript/mastodon/actions/featured_tags.ts new file mode 100644 index 0000000000..12ed6282af --- /dev/null +++ b/app/javascript/mastodon/actions/featured_tags.ts @@ -0,0 +1,7 @@ +import { apiGetFeaturedTags } from 'mastodon/api/accounts'; +import { createDataLoadingThunk } from 'mastodon/store/typed_functions'; + +export const fetchFeaturedTags = createDataLoadingThunk( + 'accounts/featured_tags', + ({ accountId }: { accountId: string }) => apiGetFeaturedTags(accountId), +); diff --git a/app/javascript/mastodon/actions/importer/accounts.ts b/app/javascript/mastodon/actions/importer/accounts.ts new file mode 100644 index 0000000000..9eedad6da5 --- /dev/null +++ b/app/javascript/mastodon/actions/importer/accounts.ts @@ -0,0 +1,7 @@ +import { createAction } from '@reduxjs/toolkit'; + +import type { ApiAccountJSON } from 'mastodon/api_types/accounts'; + +export const importAccounts = createAction<{ accounts: ApiAccountJSON[] }>( + 'accounts/importAccounts', +); diff --git a/app/javascript/mastodon/actions/importer/index.js b/app/javascript/mastodon/actions/importer/index.js index a527043940..becbdb88c3 100644 --- a/app/javascript/mastodon/actions/importer/index.js +++ b/app/javascript/mastodon/actions/importer/index.js @@ -1,7 +1,6 @@ import { createPollFromServerJSON } from 'mastodon/models/poll'; -import { importAccounts } from '../accounts_typed'; - +import { importAccounts } from './accounts'; import { normalizeStatus } from './normalizer'; import { importPolls } from './polls'; diff --git a/app/javascript/mastodon/api/accounts.ts b/app/javascript/mastodon/api/accounts.ts index c574a47459..074bcffaa1 100644 --- a/app/javascript/mastodon/api/accounts.ts +++ b/app/javascript/mastodon/api/accounts.ts @@ -1,5 +1,7 @@ -import { apiRequestPost } from 'mastodon/api'; +import { apiRequestPost, apiRequestGet } from 'mastodon/api'; +import type { ApiAccountJSON } from 'mastodon/api_types/accounts'; import type { ApiRelationshipJSON } from 'mastodon/api_types/relationships'; +import type { ApiHashtagJSON } from 'mastodon/api_types/tags'; export const apiSubmitAccountNote = (id: string, value: string) => apiRequestPost(`v1/accounts/${id}/note`, { @@ -23,3 +25,9 @@ export const apiRemoveAccountFromFollowers = (id: string) => apiRequestPost( `v1/accounts/${id}/remove_from_followers`, ); + +export const apiGetFeaturedTags = (id: string) => + apiRequestGet(`v1/accounts/${id}/featured_tags`); + +export const apiGetEndorsedAccounts = (id: string) => + apiRequestGet(`v1/accounts/${id}/endorsements`); diff --git a/app/javascript/mastodon/features/account_featured/index.tsx b/app/javascript/mastodon/features/account_featured/index.tsx index 70e411f61a..d516bc3411 100644 --- a/app/javascript/mastodon/features/account_featured/index.tsx +++ b/app/javascript/mastodon/features/account_featured/index.tsx @@ -7,19 +7,21 @@ import { useParams } from 'react-router'; import type { Map as ImmutableMap } from 'immutable'; import { List as ImmutableList } from 'immutable'; +import { fetchEndorsedAccounts } from 'mastodon/actions/accounts'; import { fetchFeaturedTags } from 'mastodon/actions/featured_tags'; import { expandAccountFeaturedTimeline } from 'mastodon/actions/timelines'; +import { Account } from 'mastodon/components/account'; import { ColumnBackButton } from 'mastodon/components/column_back_button'; import { LoadingIndicator } from 'mastodon/components/loading_indicator'; import { RemoteHint } from 'mastodon/components/remote_hint'; import StatusContainer from 'mastodon/containers/status_container'; +import { AccountHeader } from 'mastodon/features/account_timeline/components/account_header'; +import BundleColumnError from 'mastodon/features/ui/components/bundle_column_error'; +import Column from 'mastodon/features/ui/components/column'; import { useAccountId } from 'mastodon/hooks/useAccountId'; import { useAccountVisibility } from 'mastodon/hooks/useAccountVisibility'; import { useAppDispatch, useAppSelector } from 'mastodon/store'; -import { AccountHeader } from '../account_timeline/components/account_header'; -import Column from '../ui/components/column'; - import { EmptyMessage } from './components/empty_message'; import { FeaturedTag } from './components/featured_tag'; import type { TagMap } from './components/featured_tag'; @@ -29,7 +31,9 @@ interface Params { id?: string; } -const AccountFeatured = () => { +const AccountFeatured: React.FC<{ multiColumn: boolean }> = ({ + multiColumn, +}) => { const accountId = useAccountId(); const { suspended, blockedBy, hidden } = useAccountVisibility(accountId); const forceEmptyState = suspended || blockedBy || hidden; @@ -40,7 +44,8 @@ const AccountFeatured = () => { useEffect(() => { if (accountId) { void dispatch(expandAccountFeaturedTimeline(accountId)); - dispatch(fetchFeaturedTags(accountId)); + void dispatch(fetchFeaturedTags({ accountId })); + void dispatch(fetchEndorsedAccounts({ accountId })); } }, [accountId, dispatch]); @@ -67,6 +72,17 @@ const AccountFeatured = () => { ImmutableList(), ) as ImmutableList, ); + const featuredAccountIds = useAppSelector( + (state) => + state.user_lists.getIn( + ['featured_accounts', accountId, 'items'], + ImmutableList(), + ) as ImmutableList, + ); + + if (accountId === null) { + return ; + } if (isLoading) { return ( @@ -78,7 +94,11 @@ const AccountFeatured = () => { ); } - if (featuredStatusIds.isEmpty() && featuredTags.isEmpty()) { + if ( + featuredStatusIds.isEmpty() && + featuredTags.isEmpty() && + featuredAccountIds.isEmpty() + ) { return ( { ))} )} + {!featuredAccountIds.isEmpty() && ( + <> +

+ +

+ {featuredAccountIds.map((featuredAccountId) => ( + + ))} + + )} diff --git a/app/javascript/mastodon/features/account_gallery/index.tsx b/app/javascript/mastodon/features/account_gallery/index.tsx index 0027329c93..594f71cb23 100644 --- a/app/javascript/mastodon/features/account_gallery/index.tsx +++ b/app/javascript/mastodon/features/account_gallery/index.tsx @@ -147,7 +147,7 @@ export const AccountGallery: React.FC<{ [dispatch], ); - if (accountId && !isAccount) { + if (accountId === null) { return ; } diff --git a/app/javascript/mastodon/features/account_timeline/components/account_header.tsx b/app/javascript/mastodon/features/account_timeline/components/account_header.tsx index 9d4825d302..b7908cc8d3 100644 --- a/app/javascript/mastodon/features/account_timeline/components/account_header.tsx +++ b/app/javascript/mastodon/features/account_timeline/components/account_header.tsx @@ -107,7 +107,6 @@ const messages = defineMessages({ id: 'account.disable_notifications', defaultMessage: 'Stop notifying me when @{name} posts', }, - pins: { id: 'navigation_bar.pins', defaultMessage: 'Pinned posts' }, preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences', @@ -451,7 +450,6 @@ export const AccountHeader: React.FC<{ text: intl.formatMessage(messages.preferences), href: '/settings/preferences', }); - arr.push({ text: intl.formatMessage(messages.pins), to: '/pinned' }); arr.push(null); arr.push({ text: intl.formatMessage(messages.follow_requests), diff --git a/app/javascript/mastodon/features/account_timeline/index.jsx b/app/javascript/mastodon/features/account_timeline/index.jsx index a5223275b3..6fc7d0a4ef 100644 --- a/app/javascript/mastodon/features/account_timeline/index.jsx +++ b/app/javascript/mastodon/features/account_timeline/index.jsx @@ -13,7 +13,6 @@ import { normalizeForLookup } from 'mastodon/reducers/accounts_map'; import { getAccountHidden } from 'mastodon/selectors/accounts'; import { lookupAccount, fetchAccount } from '../../actions/accounts'; -import { fetchFeaturedTags } from '../../actions/featured_tags'; import { expandAccountFeaturedTimeline, expandAccountTimeline, connectTimeline, disconnectTimeline } from '../../actions/timelines'; import { ColumnBackButton } from '../../components/column_back_button'; import { LoadingIndicator } from '../../components/loading_indicator'; @@ -27,7 +26,7 @@ import { LimitedAccountHint } from './components/limited_account_hint'; const emptyList = ImmutableList(); const mapStateToProps = (state, { params: { acct, id, tagged }, withReplies = false }) => { - const accountId = id || state.getIn(['accounts_map', normalizeForLookup(acct)]); + const accountId = id || state.accounts_map[normalizeForLookup(acct)]; if (accountId === null) { return { @@ -86,7 +85,6 @@ class AccountTimeline extends ImmutablePureComponent { dispatch(expandAccountFeaturedTimeline(accountId, { tagged })); } - dispatch(fetchFeaturedTags(accountId)); dispatch(expandAccountTimeline(accountId, { withReplies, tagged })); if (accountId === me) { diff --git a/app/javascript/mastodon/features/compose/components/action_bar.tsx b/app/javascript/mastodon/features/compose/components/action_bar.tsx index af24c565f6..55e95fb5d8 100644 --- a/app/javascript/mastodon/features/compose/components/action_bar.tsx +++ b/app/javascript/mastodon/features/compose/components/action_bar.tsx @@ -9,7 +9,6 @@ import { useAppDispatch } from 'mastodon/store'; const messages = defineMessages({ edit_profile: { id: 'account.edit_profile', defaultMessage: 'Edit profile' }, - pins: { id: 'navigation_bar.pins', defaultMessage: 'Pinned posts' }, preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences', @@ -53,7 +52,6 @@ export const ActionBar: React.FC = () => { text: intl.formatMessage(messages.preferences), href: '/settings/preferences', }, - { text: intl.formatMessage(messages.pins), to: '/pinned' }, null, { text: intl.formatMessage(messages.follow_requests), diff --git a/app/javascript/mastodon/features/followers/index.jsx b/app/javascript/mastodon/features/followers/index.jsx index eaafb3d193..e55d3d9cd6 100644 --- a/app/javascript/mastodon/features/followers/index.jsx +++ b/app/javascript/mastodon/features/followers/index.jsx @@ -29,7 +29,7 @@ import { LimitedAccountHint } from '../account_timeline/components/limited_accou import Column from '../ui/components/column'; const mapStateToProps = (state, { params: { acct, id } }) => { - const accountId = id || state.getIn(['accounts_map', normalizeForLookup(acct)]); + const accountId = id || state.accounts_map[normalizeForLookup(acct)]; if (!accountId) { return { diff --git a/app/javascript/mastodon/features/following/index.jsx b/app/javascript/mastodon/features/following/index.jsx index 3200f1543b..1dc39df0ee 100644 --- a/app/javascript/mastodon/features/following/index.jsx +++ b/app/javascript/mastodon/features/following/index.jsx @@ -29,7 +29,7 @@ import { LimitedAccountHint } from '../account_timeline/components/limited_accou import Column from '../ui/components/column'; const mapStateToProps = (state, { params: { acct, id } }) => { - const accountId = id || state.getIn(['accounts_map', normalizeForLookup(acct)]); + const accountId = id || state.accounts_map[normalizeForLookup(acct)]; if (!accountId) { return { diff --git a/app/javascript/mastodon/hooks/useAccountId.ts b/app/javascript/mastodon/hooks/useAccountId.ts index 1cc819ca59..af1c93d17d 100644 --- a/app/javascript/mastodon/hooks/useAccountId.ts +++ b/app/javascript/mastodon/hooks/useAccountId.ts @@ -11,27 +11,25 @@ interface Params { id?: string; } -export function useAccountId() { +export const useAccountId = () => { const { acct, id } = useParams(); + const dispatch = useAppDispatch(); const accountId = useAppSelector( (state) => - id ?? - (state.accounts_map.get(normalizeForLookup(acct)) as string | undefined), + id ?? (acct ? state.accounts_map[normalizeForLookup(acct)] : undefined), ); - const account = useAppSelector((state) => accountId ? state.accounts.get(accountId) : undefined, ); - const isAccount = !!account; + const accountInStore = !!account; - const dispatch = useAppDispatch(); useEffect(() => { - if (!accountId) { + if (typeof accountId === 'undefined' && acct) { dispatch(lookupAccount(acct)); - } else if (!isAccount) { + } else if (accountId && !accountInStore) { dispatch(fetchAccount(accountId)); } - }, [dispatch, accountId, acct, isAccount]); + }, [dispatch, accountId, acct, accountInStore]); return accountId; -} +}; diff --git a/app/javascript/mastodon/hooks/useAccountVisibility.ts b/app/javascript/mastodon/hooks/useAccountVisibility.ts index 55651af5a0..7ef98eef69 100644 --- a/app/javascript/mastodon/hooks/useAccountVisibility.ts +++ b/app/javascript/mastodon/hooks/useAccountVisibility.ts @@ -1,12 +1,14 @@ import { getAccountHidden } from 'mastodon/selectors/accounts'; import { useAppSelector } from 'mastodon/store'; -export function useAccountVisibility(accountId?: string) { - const blockedBy = useAppSelector( - (state) => !!state.relationships.getIn([accountId, 'blocked_by'], false), +export function useAccountVisibility(accountId?: string | null) { + const blockedBy = useAppSelector((state) => + accountId + ? !!state.relationships.getIn([accountId, 'blocked_by'], false) + : false, ); - const suspended = useAppSelector( - (state) => !!state.accounts.getIn([accountId, 'suspended'], false), + const suspended = useAppSelector((state) => + accountId ? !!state.accounts.getIn([accountId, 'suspended'], false) : false, ); const hidden = useAppSelector((state) => accountId ? Boolean(getAccountHidden(state, accountId)) : false, diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json index e193e10a6d..3d6e166498 100644 --- a/app/javascript/mastodon/locales/en.json +++ b/app/javascript/mastodon/locales/en.json @@ -29,6 +29,7 @@ "account.enable_notifications": "Notify me when @{name} posts", "account.endorse": "Feature on profile", "account.featured": "Featured", + "account.featured.accounts": "Profiles", "account.featured.hashtags": "Hashtags", "account.featured.posts": "Posts", "account.featured_tags.last_status_at": "Last post on {date}", diff --git a/app/javascript/mastodon/reducers/accounts.ts b/app/javascript/mastodon/reducers/accounts.ts index 2001353b2e..692c4feec4 100644 --- a/app/javascript/mastodon/reducers/accounts.ts +++ b/app/javascript/mastodon/reducers/accounts.ts @@ -4,9 +4,9 @@ import { Map as ImmutableMap } from 'immutable'; import { followAccountSuccess, unfollowAccountSuccess, - importAccounts, revealAccount, } from 'mastodon/actions/accounts_typed'; +import { importAccounts } from 'mastodon/actions/importer/accounts'; import type { ApiAccountJSON } from 'mastodon/api_types/accounts'; import { me } from 'mastodon/initial_state'; import type { Account } from 'mastodon/models/account'; diff --git a/app/javascript/mastodon/reducers/accounts_map.js b/app/javascript/mastodon/reducers/accounts_map.js deleted file mode 100644 index d1229169cc..0000000000 --- a/app/javascript/mastodon/reducers/accounts_map.js +++ /dev/null @@ -1,23 +0,0 @@ -import { Map as ImmutableMap } from 'immutable'; - -import { ACCOUNT_LOOKUP_FAIL } from '../actions/accounts'; -import { importAccounts } from '../actions/accounts_typed'; -import { domain } from '../initial_state'; - -const pattern = new RegExp(`@${domain}$`, 'gi'); - -export const normalizeForLookup = str => - str.toLowerCase().replace(pattern, ''); - -const initialState = ImmutableMap(); - -export default function accountsMap(state = initialState, action) { - switch(action.type) { - case ACCOUNT_LOOKUP_FAIL: - return action.error?.response?.status === 404 ? state.set(normalizeForLookup(action.acct), null) : state; - case importAccounts.type: - return state.withMutations(map => action.payload.accounts.forEach(account => map.set(normalizeForLookup(account.acct), account.id))); - default: - return state; - } -} diff --git a/app/javascript/mastodon/reducers/accounts_map.ts b/app/javascript/mastodon/reducers/accounts_map.ts new file mode 100644 index 0000000000..820082e3d8 --- /dev/null +++ b/app/javascript/mastodon/reducers/accounts_map.ts @@ -0,0 +1,38 @@ +import { createReducer } from '@reduxjs/toolkit'; +import type { UnknownAction } from '@reduxjs/toolkit'; + +import type { AxiosError } from 'axios'; + +import { ACCOUNT_LOOKUP_FAIL } from 'mastodon/actions/accounts'; +import { importAccounts } from 'mastodon/actions/importer/accounts'; +import { domain } from 'mastodon/initial_state'; + +interface AccountLookupFailAction extends UnknownAction { + acct: string; + error?: AxiosError; +} + +const pattern = new RegExp(`@${domain}$`, 'gi'); + +export const normalizeForLookup = (str: string) => + str.toLowerCase().replace(pattern, ''); + +const initialState: Record = {}; + +export const accountsMapReducer = createReducer(initialState, (builder) => { + builder + .addCase(importAccounts, (state, action) => { + action.payload.accounts.forEach((account) => { + state[normalizeForLookup(account.acct)] = account.id; + }); + }) + .addMatcher( + (action: UnknownAction): action is AccountLookupFailAction => + action.type === ACCOUNT_LOOKUP_FAIL, + (state, action) => { + if (action.error?.response?.status === 404) { + state[normalizeForLookup(action.acct)] = null; + } + }, + ); +}); diff --git a/app/javascript/mastodon/reducers/index.ts b/app/javascript/mastodon/reducers/index.ts index a1b349af80..0b6e66a1b2 100644 --- a/app/javascript/mastodon/reducers/index.ts +++ b/app/javascript/mastodon/reducers/index.ts @@ -4,7 +4,7 @@ import { loadingBarReducer } from 'react-redux-loading-bar'; import { combineReducers } from 'redux-immutable'; import { accountsReducer } from './accounts'; -import accounts_map from './accounts_map'; +import { accountsMapReducer } from './accounts_map'; import { alertsReducer } from './alerts'; import announcements from './announcements'; import { composeReducer } from './compose'; @@ -49,7 +49,7 @@ const reducers = { user_lists, status_lists, accounts: accountsReducer, - accounts_map, + accounts_map: accountsMapReducer, statuses, relationships: relationshipsReducer, settings, diff --git a/app/javascript/mastodon/reducers/user_lists.js b/app/javascript/mastodon/reducers/user_lists.js index 7a4c04c5c7..466bfe54d6 100644 --- a/app/javascript/mastodon/reducers/user_lists.js +++ b/app/javascript/mastodon/reducers/user_lists.js @@ -5,9 +5,7 @@ import { fetchDirectory } from 'mastodon/actions/directory'; import { - FEATURED_TAGS_FETCH_REQUEST, - FEATURED_TAGS_FETCH_SUCCESS, - FEATURED_TAGS_FETCH_FAIL, + fetchFeaturedTags } from 'mastodon/actions/featured_tags'; import { @@ -31,6 +29,7 @@ import { FOLLOW_REQUESTS_EXPAND_FAIL, authorizeFollowRequestSuccess, rejectFollowRequestSuccess, + fetchEndorsedAccounts, } from '../actions/accounts'; import { BLOCKS_FETCH_REQUEST, @@ -191,21 +190,27 @@ export default function userLists(state = initialState, action) { case MUTES_FETCH_FAIL: case MUTES_EXPAND_FAIL: return state.setIn(['mutes', 'isLoading'], false); - case FEATURED_TAGS_FETCH_SUCCESS: - return normalizeFeaturedTags(state, ['featured_tags', action.id], action.tags, action.id); - case FEATURED_TAGS_FETCH_REQUEST: - return state.setIn(['featured_tags', action.id, 'isLoading'], true); - case FEATURED_TAGS_FETCH_FAIL: - return state.setIn(['featured_tags', action.id, 'isLoading'], false); default: - if(fetchDirectory.fulfilled.match(action)) + if (fetchEndorsedAccounts.fulfilled.match(action)) + return normalizeList(state, ['featured_accounts', action.meta.arg.accountId], action.payload, undefined); + else if (fetchEndorsedAccounts.pending.match(action)) + return state.setIn(['featured_accounts', action.meta.arg.accountId, 'isLoading'], true); + else if (fetchEndorsedAccounts.rejected.match(action)) + return state.setIn(['featured_accounts', action.meta.arg.accountId, 'isLoading'], false); + else if (fetchFeaturedTags.fulfilled.match(action)) + return normalizeFeaturedTags(state, ['featured_tags', action.meta.arg.accountId], action.payload, action.meta.arg.accountId); + else if (fetchFeaturedTags.pending.match(action)) + return state.setIn(['featured_tags', action.meta.arg.accountId, 'isLoading'], true); + else if (fetchFeaturedTags.rejected.match(action)) + return state.setIn(['featured_tags', action.meta.arg.accountId, 'isLoading'], false); + else if (fetchDirectory.fulfilled.match(action)) return normalizeList(state, ['directory'], action.payload.accounts, undefined); - else if( expandDirectory.fulfilled.match(action)) + else if (expandDirectory.fulfilled.match(action)) return appendToList(state, ['directory'], action.payload.accounts, undefined); - else if(fetchDirectory.pending.match(action) || + else if (fetchDirectory.pending.match(action) || expandDirectory.pending.match(action)) return state.setIn(['directory', 'isLoading'], true); - else if(fetchDirectory.rejected.match(action) || + else if (fetchDirectory.rejected.match(action) || expandDirectory.rejected.match(action)) return state.setIn(['directory', 'isLoading'], false); else