diff --git a/app/soapbox/actions/instance.ts b/app/soapbox/actions/instance.ts index 1c826e3d2..0d6d6c2e4 100644 --- a/app/soapbox/actions/instance.ts +++ b/app/soapbox/actions/instance.ts @@ -1,30 +1,19 @@ +import { createAsyncThunk } from '@reduxjs/toolkit'; import { get } from 'lodash'; import KVStore from 'soapbox/storage/kv_store'; -import { AppDispatch, RootState } from 'soapbox/store'; +import { RootState } from 'soapbox/store'; import { getAuthUserUrl } from 'soapbox/utils/auth'; import { parseVersion } from 'soapbox/utils/features'; import api from '../api'; -export const INSTANCE_FETCH_REQUEST = 'INSTANCE_FETCH_REQUEST'; -export const INSTANCE_FETCH_SUCCESS = 'INSTANCE_FETCH_SUCCESS'; -export const INSTANCE_FETCH_FAIL = 'INSTANCE_FETCH_FAIL'; - -export const INSTANCE_REMEMBER_REQUEST = 'INSTANCE_REMEMBER_REQUEST'; -export const INSTANCE_REMEMBER_SUCCESS = 'INSTANCE_REMEMBER_SUCCESS'; -export const INSTANCE_REMEMBER_FAIL = 'INSTANCE_REMEMBER_FAIL'; - -export const NODEINFO_FETCH_REQUEST = 'NODEINFO_FETCH_REQUEST'; -export const NODEINFO_FETCH_SUCCESS = 'NODEINFO_FETCH_SUCCESS'; -export const NODEINFO_FETCH_FAIL = 'NODEINFO_FETCH_FAIL'; - const getMeUrl = (state: RootState) => { const me = state.me; return state.accounts.getIn([me, 'url']); }; -// Figure out the appropriate instance to fetch depending on the state +/** Figure out the appropriate instance to fetch depending on the state */ export const getHost = (state: RootState) => { const accountUrl = getMeUrl(state) || getAuthUserUrl(state); @@ -35,60 +24,45 @@ export const getHost = (state: RootState) => { } }; -export function rememberInstance(host: string) { - return (dispatch: AppDispatch, _getState: () => RootState) => { - dispatch({ type: INSTANCE_REMEMBER_REQUEST, host }); - return KVStore.getItemOrError(`instance:${host}`).then((instance: Record) => { - dispatch({ type: INSTANCE_REMEMBER_SUCCESS, host, instance }); - return instance; - }).catch((error: Error) => { - dispatch({ type: INSTANCE_REMEMBER_FAIL, host, error, skipAlert: true }); - }); - }; -} +export const rememberInstance = createAsyncThunk( + 'instance/remember', + async(host: string) => { + return await KVStore.getItemOrError(`instance:${host}`); + }, +); -// We may need to fetch nodeinfo on Pleroma < 2.1 +/** We may need to fetch nodeinfo on Pleroma < 2.1 */ const needsNodeinfo = (instance: Record): boolean => { const v = parseVersion(get(instance, 'version')); return v.software === 'Pleroma' && !get(instance, ['pleroma', 'metadata']); }; -export function fetchInstance() { - return (dispatch: AppDispatch, getState: () => RootState) => { - dispatch({ type: INSTANCE_FETCH_REQUEST }); - return api(getState).get('/api/v1/instance').then(({ data: instance }: { data: Record }) => { - dispatch({ type: INSTANCE_FETCH_SUCCESS, instance }); - if (needsNodeinfo(instance)) { - // @ts-ignore: ??? - dispatch(fetchNodeinfo()); // Pleroma < 2.1 backwards compatibility - } - }).catch(error => { - console.error(error); - dispatch({ type: INSTANCE_FETCH_FAIL, error, skipAlert: true }); - }); - }; -} +export const fetchInstance = createAsyncThunk( + 'instance/fetch', + async(_arg, { dispatch, getState }) => { + const { data: instance } = await api(getState).get('/api/v1/instance'); + if (needsNodeinfo(instance)) { + dispatch(fetchNodeinfo()); + } + return instance; + }, +); -// Tries to remember the instance from browser storage before fetching it -export function loadInstance() { - return (dispatch: AppDispatch, getState: () => RootState) => { +/** Tries to remember the instance from browser storage before fetching it */ +export const loadInstance = createAsyncThunk( + 'instance/load', + async(_arg, { dispatch, getState }) => { const host = getHost(getState()); + await Promise.all([ + dispatch(rememberInstance(host || '')), + dispatch(fetchInstance()), + ]); + }, +); - // @ts-ignore: ??? - return dispatch(rememberInstance(host)).finally(() => { - // @ts-ignore: ??? - return dispatch(fetchInstance()); - }); - }; -} - -export function fetchNodeinfo() { - return (dispatch: AppDispatch, getState: () => RootState) => { - dispatch({ type: NODEINFO_FETCH_REQUEST }); - return api(getState).get('/nodeinfo/2.1.json').then(({ data: nodeinfo }) => { - return dispatch({ type: NODEINFO_FETCH_SUCCESS, nodeinfo }); - }).catch((error: Error) => { - return dispatch({ type: NODEINFO_FETCH_FAIL, error, skipAlert: true }); - }); - }; -} +export const fetchNodeinfo = createAsyncThunk( + 'nodeinfo/fetch', + async(_arg, { getState }) => { + return await api(getState).get('/nodeinfo/2.1.json'); + }, +); diff --git a/app/soapbox/reducers/instance.ts b/app/soapbox/reducers/instance.ts index 7c832c200..16523d474 100644 --- a/app/soapbox/reducers/instance.ts +++ b/app/soapbox/reducers/instance.ts @@ -8,10 +8,9 @@ import KVStore from 'soapbox/storage/kv_store'; import { ConfigDB } from 'soapbox/utils/config_db'; import { - INSTANCE_REMEMBER_SUCCESS, - INSTANCE_FETCH_SUCCESS, - INSTANCE_FETCH_FAIL, - NODEINFO_FETCH_SUCCESS, + rememberInstance, + fetchInstance, + fetchNodeinfo, } from '../actions/instance'; const initialState = normalizeInstance(ImmutableMap()); @@ -115,15 +114,15 @@ export default function instance(state = initialState, action: AnyAction) { switch(action.type) { case PLEROMA_PRELOAD_IMPORT: return preloadImport(state, action, '/api/v1/instance'); - case INSTANCE_REMEMBER_SUCCESS: - return importInstance(state, ImmutableMap(fromJS(action.instance))); - case INSTANCE_FETCH_SUCCESS: - persistInstance(action.instance); - return importInstance(state, ImmutableMap(fromJS(action.instance))); - case INSTANCE_FETCH_FAIL: + case rememberInstance.fulfilled.toString(): + return importInstance(state, ImmutableMap(fromJS(action.payload))); + case fetchInstance.fulfilled.toString(): + persistInstance(action.payload); + return importInstance(state, ImmutableMap(fromJS(action.payload))); + case fetchInstance.rejected.toString(): return handleInstanceFetchFail(state, action.error); - case NODEINFO_FETCH_SUCCESS: - return importNodeinfo(state, ImmutableMap(fromJS(action.nodeinfo))); + case fetchNodeinfo.fulfilled.toString(): + return importNodeinfo(state, ImmutableMap(fromJS(action.payload))); case ADMIN_CONFIG_UPDATE_REQUEST: case ADMIN_CONFIG_UPDATE_SUCCESS: return importConfigs(state, ImmutableList(fromJS(action.configs))); diff --git a/app/soapbox/reducers/meta.ts b/app/soapbox/reducers/meta.ts index cdcdaf580..026b050b3 100644 --- a/app/soapbox/reducers/meta.ts +++ b/app/soapbox/reducers/meta.ts @@ -2,7 +2,7 @@ import { Record as ImmutableRecord } from 'immutable'; -import { INSTANCE_FETCH_FAIL } from 'soapbox/actions/instance'; +import { fetchInstance } from 'soapbox/actions/instance'; import type { AnyAction } from 'redux'; @@ -12,7 +12,7 @@ const ReducerRecord = ImmutableRecord({ export default function meta(state = ReducerRecord(), action: AnyAction) { switch(action.type) { - case INSTANCE_FETCH_FAIL: + case fetchInstance.rejected.toString(): return state.set('instance_fetch_failed', true); default: return state;