TypeScript: actions

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
environments/review-develop-3zknud/deployments/246^2
marcin mikołajczak 2 years ago
parent 58539146a4
commit 708c3a9e64

@ -8,6 +8,8 @@
import { baseClient } from '../api';
import type { AnyAction } from 'redux';
export const APP_CREATE_REQUEST = 'APP_CREATE_REQUEST';
export const APP_CREATE_SUCCESS = 'APP_CREATE_SUCCESS';
export const APP_CREATE_FAIL = 'APP_CREATE_FAIL';
@ -16,12 +18,12 @@ export const APP_VERIFY_CREDENTIALS_REQUEST = 'APP_VERIFY_CREDENTIALS_REQUEST';
export const APP_VERIFY_CREDENTIALS_SUCCESS = 'APP_VERIFY_CREDENTIALS_SUCCESS';
export const APP_VERIFY_CREDENTIALS_FAIL = 'APP_VERIFY_CREDENTIALS_FAIL';
export function createApp(params, baseURL) {
return (dispatch, getState) => {
export function createApp(params?: Record<string, string>, baseURL?: string) {
return (dispatch: React.Dispatch<AnyAction>) => {
dispatch({ type: APP_CREATE_REQUEST, params });
return baseClient(null, baseURL).post('/api/v1/apps', params).then(({ data: app }) => {
dispatch({ type: APP_CREATE_SUCCESS, params, app });
return app;
return app as Record<string, string>;
}).catch(error => {
dispatch({ type: APP_CREATE_FAIL, params, error });
throw error;
@ -29,8 +31,8 @@ export function createApp(params, baseURL) {
};
}
export function verifyAppCredentials(token) {
return (dispatch, getState) => {
export function verifyAppCredentials(token: string) {
return (dispatch: React.Dispatch<AnyAction>) => {
dispatch({ type: APP_VERIFY_CREDENTIALS_REQUEST, token });
return baseClient(token).get('/api/v1/apps/verify_credentials').then(({ data: app }) => {
dispatch({ type: APP_VERIFY_CREDENTIALS_SUCCESS, token, app });

@ -26,6 +26,10 @@ import api, { baseClient } from '../api';
import { importFetchedAccount } from './importer';
import type { AxiosError } from 'axios';
import type { Map as ImmutableMap } from 'immutable';
import type { AppDispatch, RootState } from 'soapbox/store';
export const SWITCH_ACCOUNT = 'SWITCH_ACCOUNT';
export const AUTH_APP_CREATED = 'AUTH_APP_CREATED';
@ -48,35 +52,32 @@ export const messages = defineMessages({
invalidCredentials: { id: 'auth.invalid_credentials', defaultMessage: 'Wrong username or password' },
});
const noOp = () => new Promise(f => f());
const noOp = () => new Promise(f => f(undefined));
const getScopes = state => {
const instance = state.get('instance');
const getScopes = (state: RootState) => {
const instance = state.instance;
const { scopes } = getFeatures(instance);
return scopes;
};
function createAppAndToken() {
return (dispatch, getState) => {
return dispatch(getAuthApp()).then(() => {
return dispatch(createAppToken());
});
};
}
const createAppAndToken = () =>
(dispatch: AppDispatch) =>
dispatch(getAuthApp()).then(() =>
dispatch(createAppToken()),
);
/** Create an auth app, or use it from build config */
function getAuthApp() {
return (dispatch, getState) => {
const getAuthApp = () =>
(dispatch: AppDispatch) => {
if (customApp?.client_secret) {
return noOp().then(() => dispatch({ type: AUTH_APP_CREATED, app: customApp }));
} else {
return dispatch(createAuthApp());
}
};
}
function createAuthApp() {
return (dispatch, getState) => {
const createAuthApp = () =>
(dispatch: AppDispatch, getState: () => any) => {
const params = {
client_name: sourceCode.displayName,
redirect_uris: 'urn:ietf:wg:oauth:2.0:oob',
@ -84,15 +85,14 @@ function createAuthApp() {
website: sourceCode.homepage,
};
return dispatch(createApp(params)).then(app => {
return dispatch({ type: AUTH_APP_CREATED, app });
});
return dispatch(createApp(params)).then((app: Record<string, string>) =>
dispatch({ type: AUTH_APP_CREATED, app }),
);
};
}
function createAppToken() {
return (dispatch, getState) => {
const app = getState().getIn(['auth', 'app']);
const createAppToken = () =>
(dispatch: AppDispatch, getState: () => any) => {
const app = getState().auth.get('app');
const params = {
client_id: app.get('client_id'),
@ -102,15 +102,14 @@ function createAppToken() {
scope: getScopes(getState()),
};
return dispatch(obtainOAuthToken(params)).then(token => {
return dispatch({ type: AUTH_APP_AUTHORIZED, app, token });
});
return dispatch(obtainOAuthToken(params)).then((token: Record<string, string | number>) =>
dispatch({ type: AUTH_APP_AUTHORIZED, app, token }),
);
};
}
function createUserToken(username, password) {
return (dispatch, getState) => {
const app = getState().getIn(['auth', 'app']);
const createUserToken = (username: string, password: string) =>
(dispatch: AppDispatch, getState: () => any) => {
const app = getState().auth.get('app');
const params = {
client_id: app.get('client_id'),
@ -123,14 +122,13 @@ function createUserToken(username, password) {
};
return dispatch(obtainOAuthToken(params))
.then(token => dispatch(authLoggedIn(token)));
.then((token: Record<string, string | number>) => dispatch(authLoggedIn(token)));
};
}
export function refreshUserToken() {
return (dispatch, getState) => {
const refreshToken = getState().getIn(['auth', 'user', 'refresh_token']);
const app = getState().getIn(['auth', 'app']);
export const refreshUserToken = () =>
(dispatch: AppDispatch, getState: () => RootState) => {
const refreshToken = getState().auth.getIn(['user', 'refresh_token']);
const app = getState().auth.get('app');
if (!refreshToken) return dispatch(noOp);
@ -144,13 +142,12 @@ export function refreshUserToken() {
};
return dispatch(obtainOAuthToken(params))
.then(token => dispatch(authLoggedIn(token)));
.then((token: Record<string, string | number>) => dispatch(authLoggedIn(token)));
};
}
export function otpVerify(code, mfa_token) {
return (dispatch, getState) => {
const app = getState().getIn(['auth', 'app']);
export const otpVerify = (code: string, mfa_token: string) =>
(dispatch: AppDispatch, getState: () => any) => {
const app = getState().auth.get('app');
return api(getState, 'app').post('/oauth/mfa/challenge', {
client_id: app.get('client_id'),
client_secret: app.get('client_secret'),
@ -161,18 +158,17 @@ export function otpVerify(code, mfa_token) {
scope: getScopes(getState()),
}).then(({ data: token }) => dispatch(authLoggedIn(token)));
};
}
export function verifyCredentials(token, accountUrl) {
export const verifyCredentials = (token: string, accountUrl?: string) => {
const baseURL = parseBaseURL(accountUrl);
return (dispatch, getState) => {
return (dispatch: AppDispatch, getState: () => any) => {
dispatch({ type: VERIFY_CREDENTIALS_REQUEST, token });
return baseClient(token, baseURL).get('/api/v1/accounts/verify_credentials').then(({ data: account }) => {
dispatch(importFetchedAccount(account));
dispatch({ type: VERIFY_CREDENTIALS_SUCCESS, token, account });
if (account.id === getState().get('me')) dispatch(fetchMeSuccess(account));
if (account.id === getState().me) dispatch(fetchMeSuccess(account));
return account;
}).catch(error => {
if (error?.response?.status === 403 && error?.response?.data?.id) {
@ -180,75 +176,64 @@ export function verifyCredentials(token, accountUrl) {
const account = error.response.data;
dispatch(importFetchedAccount(account));
dispatch({ type: VERIFY_CREDENTIALS_SUCCESS, token, account });
if (account.id === getState().get('me')) dispatch(fetchMeSuccess(account));
if (account.id === getState().me) dispatch(fetchMeSuccess(account));
return account;
} else {
if (getState().get('me') === null) dispatch(fetchMeFail(error));
if (getState().me === null) dispatch(fetchMeFail(error));
dispatch({ type: VERIFY_CREDENTIALS_FAIL, token, error, skipAlert: true });
return error;
}
});
};
}
};
export function rememberAuthAccount(accountUrl) {
return (dispatch, getState) => {
export const rememberAuthAccount = (accountUrl: string) =>
(dispatch: AppDispatch, getState: () => any) => {
dispatch({ type: AUTH_ACCOUNT_REMEMBER_REQUEST, accountUrl });
return KVStore.getItemOrError(`authAccount:${accountUrl}`).then(account => {
dispatch(importFetchedAccount(account));
dispatch({ type: AUTH_ACCOUNT_REMEMBER_SUCCESS, account, accountUrl });
if (account.id === getState().get('me')) dispatch(fetchMeSuccess(account));
if (account.id === getState().me) dispatch(fetchMeSuccess(account));
return account;
}).catch(error => {
dispatch({ type: AUTH_ACCOUNT_REMEMBER_FAIL, error, accountUrl, skipAlert: true });
});
};
}
export function loadCredentials(token, accountUrl) {
return (dispatch, getState) => {
return dispatch(rememberAuthAccount(accountUrl))
.then(account => account)
.then(() => {
dispatch(verifyCredentials(token, accountUrl));
})
.catch(error => dispatch(verifyCredentials(token, accountUrl)));
};
}
export function logIn(intl, username, password) {
return (dispatch, getState) => {
return dispatch(getAuthApp()).then(() => {
return dispatch(createUserToken(username, password));
}).catch(error => {
if (error.response.data.error === 'mfa_required') {
// If MFA is required, throw the error and handle it in the component.
throw error;
} else if (error.response.data.error === 'invalid_grant') {
// Mastodon returns this user-unfriendly error as a catch-all
// for everything from "bad request" to "wrong password".
// Assume our code is correct and it's a wrong password.
dispatch(snackbar.error(intl.formatMessage(messages.invalidCredentials)));
} else if (error.response.data.error) {
// If the backend returns an error, display it.
dispatch(snackbar.error(error.response.data.error));
} else {
// Return "wrong password" message.
dispatch(snackbar.error(intl.formatMessage(messages.invalidCredentials)));
}
export const loadCredentials = (token: string, accountUrl: string) =>
(dispatch: AppDispatch) => dispatch(rememberAuthAccount(accountUrl))
.then(() => {
dispatch(verifyCredentials(token, accountUrl));
})
.catch(() => dispatch(verifyCredentials(token, accountUrl)));
export const logIn = (username: string, password: string) =>
(dispatch: AppDispatch) => dispatch(getAuthApp()).then(() => {
return dispatch(createUserToken(username, password));
}).catch((error: AxiosError) => {
if ((error.response?.data as any).error === 'mfa_required') {
// If MFA is required, throw the error and handle it in the component.
throw error;
});
};
}
} else if ((error.response?.data as any).error === 'invalid_grant') {
// Mastodon returns this user-unfriendly error as a catch-all
// for everything from "bad request" to "wrong password".
// Assume our code is correct and it's a wrong password.
dispatch(snackbar.error(messages.invalidCredentials));
} else if ((error.response?.data as any).error) {
// If the backend returns an error, display it.
dispatch(snackbar.error((error.response?.data as any).error));
} else {
// Return "wrong password" message.
dispatch(snackbar.error(messages.invalidCredentials));
}
throw error;
});
export function deleteSession() {
return (dispatch, getState) => {
return api(getState).delete('/api/sign_out');
};
}
export const deleteSession = () =>
(dispatch: AppDispatch, getState: () => any) => api(getState).delete('/api/sign_out');
export function logOut(intl) {
return (dispatch, getState) => {
export const logOut = () =>
(dispatch: AppDispatch, getState: () => RootState) => {
const state = getState();
const account = getLoggedInAccount(state);
const standalone = isStandalone(state);
@ -256,9 +241,9 @@ export function logOut(intl) {
if (!account) return dispatch(noOp);
const params = {
client_id: state.getIn(['auth', 'app', 'client_id']),
client_secret: state.getIn(['auth', 'app', 'client_secret']),
token: state.getIn(['auth', 'users', account.url, 'access_token']),
client_id: state.auth.getIn(['app', 'client_id']),
client_secret: state.auth.getIn(['app', 'client_secret']),
token: state.auth.getIn(['users', account.url, 'access_token']),
};
return Promise.all([
@ -266,52 +251,47 @@ export function logOut(intl) {
dispatch(deleteSession()),
]).finally(() => {
dispatch({ type: AUTH_LOGGED_OUT, account, standalone });
dispatch(snackbar.success(intl.formatMessage(messages.loggedOut)));
return dispatch(snackbar.success(messages.loggedOut));
});
};
}
export function switchAccount(accountId, background = false) {
return (dispatch, getState) => {
const account = getState().getIn(['accounts', accountId]);
dispatch({ type: SWITCH_ACCOUNT, account, background });
export const switchAccount = (accountId: string, background = false) =>
(dispatch: AppDispatch, getState: () => any) => {
const account = getState().accounts.get(accountId);
return dispatch({ type: SWITCH_ACCOUNT, account, background });
};
}
export function fetchOwnAccounts() {
return (dispatch, getState) => {
export const fetchOwnAccounts = () =>
(dispatch: AppDispatch, getState: () => RootState) => {
const state = getState();
state.getIn(['auth', 'users']).forEach(user => {
const account = state.getIn(['accounts', user.get('id')]);
return state.auth.get('users').forEach((user: ImmutableMap<string, string>) => {
const account = state.accounts.get(user.get('id'));
if (!account) {
dispatch(verifyCredentials(user.get('access_token'), user.get('url')));
dispatch(verifyCredentials(user.get('access_token')!, user.get('url')));
}
});
};
}
export function register(params) {
return (dispatch, getState) => {
export const register = (params: Record<string, any>) =>
(dispatch: AppDispatch) => {
params.fullname = params.username;
return dispatch(createAppAndToken())
.then(() => dispatch(createAccount(params)))
.then(({ token }) => {
.then(({ token }: { token: Record<string, string | number> }) => {
dispatch(startOnboarding());
return dispatch(authLoggedIn(token));
});
};
}
export function fetchCaptcha() {
return (dispatch, getState) => {
export const fetchCaptcha = () =>
(_dispatch: AppDispatch, getState: () => any) => {
return api(getState).get('/api/pleroma/captcha');
};
}
export function authLoggedIn(token) {
return (dispatch, getState) => {
export const authLoggedIn = (token: Record<string, string | number>) =>
(dispatch: AppDispatch) => {
dispatch({ type: AUTH_LOGGED_IN, token });
return token;
};
}

@ -1,5 +1,7 @@
import api from '../api';
import type { AppDispatch } from 'soapbox/store';
export const BACKUPS_FETCH_REQUEST = 'BACKUPS_FETCH_REQUEST';
export const BACKUPS_FETCH_SUCCESS = 'BACKUPS_FETCH_SUCCESS';
export const BACKUPS_FETCH_FAIL = 'BACKUPS_FETCH_FAIL';
@ -8,24 +10,22 @@ export const BACKUPS_CREATE_REQUEST = 'BACKUPS_CREATE_REQUEST';
export const BACKUPS_CREATE_SUCCESS = 'BACKUPS_CREATE_SUCCESS';
export const BACKUPS_CREATE_FAIL = 'BACKUPS_CREATE_FAIL';
export function fetchBackups() {
return (dispatch, getState) => {
export const fetchBackups = () =>
(dispatch: AppDispatch, getState: () => any) => {
dispatch({ type: BACKUPS_FETCH_REQUEST });
return api(getState).get('/api/v1/pleroma/backups').then(({ data: backups }) => {
dispatch({ type: BACKUPS_FETCH_SUCCESS, backups });
}).catch(error => {
return api(getState).get('/api/v1/pleroma/backups').then(({ data: backups }) =>
dispatch({ type: BACKUPS_FETCH_SUCCESS, backups }),
).catch(error => {
dispatch({ type: BACKUPS_FETCH_FAIL, error });
});
};
}
export function createBackup() {
return (dispatch, getState) => {
export const createBackup = () =>
(dispatch: AppDispatch, getState: () => any) => {
dispatch({ type: BACKUPS_CREATE_REQUEST });
return api(getState).post('/api/v1/pleroma/backups').then(({ data: backups }) => {
dispatch({ type: BACKUPS_CREATE_SUCCESS, backups });
}).catch(error => {
return api(getState).post('/api/v1/pleroma/backups').then(({ data: backups }) =>
dispatch({ type: BACKUPS_CREATE_SUCCESS, backups }),
).catch(error => {
dispatch({ type: BACKUPS_CREATE_FAIL, error });
});
};
}

@ -18,7 +18,10 @@ import { getQuirks } from 'soapbox/utils/quirks';
import { baseClient } from '../api';
const fetchExternalInstance = baseURL => {
import type { AppDispatch } from 'soapbox/store';
import type { Instance } from 'soapbox/types/entities';
const fetchExternalInstance = (baseURL?: string) => {
return baseClient(null, baseURL)
.get('/api/v1/instance')
.then(({ data: instance }) => normalizeInstance(instance))
@ -33,8 +36,8 @@ const fetchExternalInstance = baseURL => {
});
};
function createExternalApp(instance, baseURL) {
return (dispatch, getState) => {
const createExternalApp = (instance: Instance, baseURL?: string) =>
(dispatch: AppDispatch) => {
// Mitra: skip creating the auth app
if (getQuirks(instance).noApps) return new Promise(f => f({}));
@ -49,14 +52,13 @@ function createExternalApp(instance, baseURL) {
return dispatch(createApp(params, baseURL));
};
}
function externalAuthorize(instance, baseURL) {
return (dispatch, getState) => {
const externalAuthorize = (instance: Instance, baseURL: string) =>
(dispatch: AppDispatch) => {
const { scopes } = getFeatures(instance);
return dispatch(createExternalApp(instance, baseURL)).then(app => {
const { client_id, redirect_uri } = app;
return dispatch(createExternalApp(instance, baseURL)).then((app) => {
const { client_id, redirect_uri } = app as Record<string, string>;
const query = new URLSearchParams({
client_id,
@ -72,58 +74,56 @@ function externalAuthorize(instance, baseURL) {
window.location.href = `${baseURL}/oauth/authorize?${query.toString()}`;
});
};
}
export function externalEthereumLogin(instance, baseURL) {
return (dispatch, getState) => {
const loginMessage = instance.get('login_message');
const externalEthereumLogin = (instance: Instance, baseURL?: string) =>
(dispatch: AppDispatch) => {
const loginMessage = instance.login_message;
return getWalletAndSign(loginMessage).then(({ wallet, signature }) => {
return dispatch(createExternalApp(instance, baseURL)).then(app => {
return dispatch(createExternalApp(instance, baseURL)).then((app) => {
const { client_id, client_secret } = app as Record<string, string>;
const params = {
grant_type: 'ethereum',
wallet_address: wallet.toLowerCase(),
client_id: app.client_id,
client_secret: app.client_secret,
password: signature,
client_id: client_id,
client_secret: client_secret,
password: signature as string,
redirect_uri: 'urn:ietf:wg:oauth:2.0:oob',
scope: getFeatures(instance).scopes,
};
return dispatch(obtainOAuthToken(params, baseURL))
.then(token => dispatch(authLoggedIn(token)))
.then(({ access_token }) => dispatch(verifyCredentials(access_token, baseURL)))
.then(account => dispatch(switchAccount(account.id)))
.then((token: Record<string, string | number>) => dispatch(authLoggedIn(token)))
.then(({ access_token }: any) => dispatch(verifyCredentials(access_token, baseURL)))
.then((account: { id: string }) => dispatch(switchAccount(account.id)))
.then(() => window.location.href = '/');
});
});
};
}
export function externalLogin(host) {
return (dispatch, getState) => {
export const externalLogin = (host: string) =>
(dispatch: AppDispatch) => {
const baseURL = parseBaseURL(host) || parseBaseURL(`https://${host}`);
return fetchExternalInstance(baseURL).then(instance => {
return fetchExternalInstance(baseURL).then((instance) => {
const features = getFeatures(instance);
const quirks = getQuirks(instance);
if (features.ethereumLogin && quirks.noOAuthForm) {
return dispatch(externalEthereumLogin(instance, baseURL));
dispatch(externalEthereumLogin(instance, baseURL));
} else {
return dispatch(externalAuthorize(instance, baseURL));
dispatch(externalAuthorize(instance, baseURL));
}
});
};
}
export function loginWithCode(code) {
return (dispatch, getState) => {
const { client_id, client_secret, redirect_uri } = JSON.parse(localStorage.getItem('soapbox:external:app'));
const baseURL = localStorage.getItem('soapbox:external:baseurl');
const scope = localStorage.getItem('soapbox:external:scopes');
export const loginWithCode = (code: string) =>
(dispatch: AppDispatch) => {
const { client_id, client_secret, redirect_uri } = JSON.parse(localStorage.getItem('soapbox:external:app')!);
const baseURL = localStorage.getItem('soapbox:external:baseurl')!;
const scope = localStorage.getItem('soapbox:external:scopes')!;
const params = {
const params: Record<string, string> = {
client_id,
client_secret,
redirect_uri,
@ -133,9 +133,8 @@ export function loginWithCode(code) {
};
return dispatch(obtainOAuthToken(params, baseURL))
.then(token => dispatch(authLoggedIn(token)))
.then(({ access_token }) => dispatch(verifyCredentials(access_token, baseURL)))
.then(account => dispatch(switchAccount(account.id)))
.then((token: Record<string, string | number>) => dispatch(authLoggedIn(token)))
.then(({ access_token }: any) => dispatch(verifyCredentials(access_token as string, baseURL)))
.then((account: { id: string }) => dispatch(switchAccount(account.id)))
.then(() => window.location.href = '/');
};
}

@ -8,6 +8,8 @@
import { baseClient } from '../api';
import type { AppDispatch } from 'soapbox/store';
export const OAUTH_TOKEN_CREATE_REQUEST = 'OAUTH_TOKEN_CREATE_REQUEST';
export const OAUTH_TOKEN_CREATE_SUCCESS = 'OAUTH_TOKEN_CREATE_SUCCESS';
export const OAUTH_TOKEN_CREATE_FAIL = 'OAUTH_TOKEN_CREATE_FAIL';
@ -16,8 +18,8 @@ export const OAUTH_TOKEN_REVOKE_REQUEST = 'OAUTH_TOKEN_REVOKE_REQUEST';
export const OAUTH_TOKEN_REVOKE_SUCCESS = 'OAUTH_TOKEN_REVOKE_SUCCESS';
export const OAUTH_TOKEN_REVOKE_FAIL = 'OAUTH_TOKEN_REVOKE_FAIL';
export function obtainOAuthToken(params, baseURL) {
return (dispatch, getState) => {
export const obtainOAuthToken = (params: Record<string, string>, baseURL?: string) =>
(dispatch: AppDispatch) => {
dispatch({ type: OAUTH_TOKEN_CREATE_REQUEST, params });
return baseClient(null, baseURL).post('/oauth/token', params).then(({ data: token }) => {
dispatch({ type: OAUTH_TOKEN_CREATE_SUCCESS, params, token });
@ -27,10 +29,9 @@ export function obtainOAuthToken(params, baseURL) {
throw error;
});
};
}
export function revokeOAuthToken(params) {
return (dispatch, getState) => {
export const revokeOAuthToken = (params: Record<string, string>) =>
(dispatch: AppDispatch) => {
dispatch({ type: OAUTH_TOKEN_REVOKE_REQUEST, params });
return baseClient().post('/oauth/revoke', params).then(({ data }) => {
dispatch({ type: OAUTH_TOKEN_REVOKE_SUCCESS, params, data });
@ -40,4 +41,3 @@ export function revokeOAuthToken(params) {
throw error;
});
};
}

@ -53,7 +53,7 @@ const getAuthBaseURL = createSelector([
* @param {string} baseURL
* @returns {object} Axios instance
*/
export const baseClient = (accessToken: string, baseURL: string = ''): AxiosInstance => {
export const baseClient = (accessToken?: string | null, baseURL: string = ''): AxiosInstance => {
return axios.create({
// When BACKEND_URL is set, always use it.
baseURL: isURL(BuildConfig.BACKEND_URL) ? BuildConfig.BACKEND_URL : baseURL,

@ -25,7 +25,7 @@ const BirthdayInput: React.FC<IBirthdayInput> = ({ value, onChange, required })
const features = useFeatures();
const supportsBirthdays = features.birthdays;
const minAge = useAppSelector((state) => state.instance.getIn(['pleroma', 'metadata', 'birthday_min_age'])) as number;
const minAge = useAppSelector((state) => state.instance.pleroma.getIn(['metadata', 'birthday_min_age'])) as number;
const maxDate = useMemo(() => {
if (!supportsBirthdays) return null;

@ -18,7 +18,7 @@ const SidebarNavigation = () => {
const settings = useAppSelector((state) => getSettings(state));
const account = useOwnAccount();
const notificationCount = useAppSelector((state) => state.notifications.get('unread'));
const chatsCount = useAppSelector((state) => state.chats.get('items').reduce((acc: any, curr: any) => acc + Math.min(curr.get('unread', 0), 1), 0));
const chatsCount = useAppSelector((state) => state.chats.items.reduce((acc, curr) => acc + Math.min(curr.unread || 0, 1), 0));
const followRequestsCount = useAppSelector((state) => state.user_lists.getIn(['follow_requests', 'items'], ImmutableOrderedSet()).count());
const dashboardCount = useAppSelector((state) => state.admin.openReports.count() + state.admin.awaitingApproval.count());

@ -109,7 +109,7 @@ const SidebarMenu: React.FC = (): JSX.Element | null => {
const onClickLogOut: React.MouseEventHandler = (e) => {
e.preventDefault();
dispatch(logOut(intl));
dispatch(logOut());
};
const handleSwitcherClick: React.MouseEventHandler = (e) => {

@ -8,7 +8,7 @@ import { getFeatures } from 'soapbox/utils/features';
const ThumbNavigation: React.FC = (): JSX.Element => {
const account = useOwnAccount();
const notificationCount = useAppSelector((state) => state.notifications.unread);
const chatsCount = useAppSelector((state) => state.chats.get('items').reduce((acc: number, curr: any) => acc + Math.min(curr.get('unread', 0), 1), 0));
const chatsCount = useAppSelector((state) => state.chats.items.reduce((acc, curr) => acc + Math.min(curr.unread || 0, 1), 0));
const dashboardCount = useAppSelector((state) => state.admin.openReports.count() + state.admin.awaitingApproval.count());
const features = getFeatures(useAppSelector((state) => state.instance));

@ -6,6 +6,8 @@ import { fetchCaptcha } from 'soapbox/actions/auth';
import { Stack, Text, Input } from 'soapbox/components/ui';
import { useAppDispatch } from 'soapbox/hooks';
import type { AxiosResponse } from 'axios';
const noOp = () => {};
const messages = defineMessages({
@ -39,7 +41,7 @@ const CaptchaField: React.FC<ICaptchaField> = ({
const [refresh, setRefresh] = useState<NodeJS.Timer | undefined>(undefined);
const getCaptcha = () => {
dispatch(fetchCaptcha()).then(response => {
dispatch(fetchCaptcha()).then((response: AxiosResponse) => {
const captcha = ImmutableMap<string, any>(response.data);
setCaptcha(captcha);
onFetch(captcha);

@ -1,5 +1,4 @@
import React, { useState } from 'react';
import { useIntl } from 'react-intl';
import { Redirect } from 'react-router-dom';
import { logIn, verifyCredentials, switchAccount } from 'soapbox/actions/auth';
@ -15,7 +14,6 @@ import OtpAuthForm from './otp_auth_form';
import type { AxiosError } from 'axios';
const LoginPage = () => {
const intl = useIntl();
const dispatch = useAppDispatch();
const me = useAppSelector((state) => state.me);
@ -36,8 +34,8 @@ const LoginPage = () => {
const handleSubmit: React.FormEventHandler = (event) => {
const { username, password } = getFormData(event.target as HTMLFormElement);
dispatch(logIn(intl, username, password)).then(({ access_token }: { access_token: string }) => {
return dispatch(verifyCredentials(access_token))
dispatch(logIn(username, password)).then(({ access_token }) => {
return dispatch(verifyCredentials(access_token as string))
// Refetch the instance for authenticated fetch
.then(() => dispatch(fetchInstance() as any));
}).then((account: { id: string }) => {

@ -1,5 +1,4 @@
import React, { useEffect, useState } from 'react';
import { useIntl } from 'react-intl';
import { useDispatch } from 'react-redux';
import { Redirect } from 'react-router-dom';
@ -8,12 +7,11 @@ import { Spinner } from 'soapbox/components/ui';
/** Component that logs the user out when rendered */
const Logout: React.FC = () => {
const intl = useIntl();
const dispatch = useDispatch();
const [done, setDone] = useState(false);
useEffect(() => {
dispatch(logOut(intl) as any)
dispatch(logOut() as any)
.then(() => setDone(true))
.catch(console.warn);
}, []);

@ -32,8 +32,8 @@ const OtpAuthForm: React.FC<IOtpAuthForm> = ({ mfa_token }) => {
const { code } = getFormData(event.target);
dispatch(otpVerify(code, mfa_token)).then(({ access_token }) => {
setCodeError(false);
return dispatch(verifyCredentials(access_token));
}).then(account => {
return dispatch(verifyCredentials(access_token as string));
}).then((account: Record<string, any>) => {
setShouldRedirect(true);
return dispatch(switchAccount(account.id));
}).catch(() => {

@ -2,10 +2,7 @@ import classNames from 'classnames';
import React, { useEffect, useState } from 'react';
import { defineMessages, useIntl } from 'react-intl';
import {
fetchBackups,
createBackup,
} from 'soapbox/actions/backups';
import { fetchBackups, createBackup } from 'soapbox/actions/backups';
import ScrollableList from 'soapbox/components/scrollable_list';
import { useAppDispatch, useAppSelector } from 'soapbox/hooks';

@ -20,7 +20,7 @@ interface IChat {
const Chat: React.FC<IChat> = ({ chatId, onClick }) => {
const chat = useAppSelector((state) => {
const chat = state.chats.getIn(['items', chatId]);
const chat = state.chats.items.get(chatId);
return chat ? getChat(state, (chat as any).toJS()) : undefined;
}) as ChatEntity;

@ -49,9 +49,9 @@ const ChatList: React.FC<IChatList> = ({ onClickChat, useWindowScroll = false })
const dispatch = useDispatch();
const intl = useIntl();
const chatIds = useAppSelector(state => sortedChatIdsSelector(state.chats.get('items')));
const hasMore = useAppSelector(state => !!state.chats.get('next'));
const isLoading = useAppSelector(state => state.chats.get('isLoading'));
const chatIds = useAppSelector(state => sortedChatIdsSelector(state.chats.items));
const hasMore = useAppSelector(state => !!state.chats.next);
const isLoading = useAppSelector(state => state.chats.isLoading);
const handleLoadMore = useCallback(() => {
if (hasMore && !isLoading) {

@ -48,7 +48,7 @@ const Header = () => {
event.preventDefault();
setLoading(true);
dispatch(logIn(intl, username, password) as any)
dispatch(logIn(username, password) as any)
.then(({ access_token }: { access_token: string }) => {
return (
dispatch(verifyCredentials(access_token) as any)

@ -1,6 +1,6 @@
import classNames from 'classnames';
import React from 'react';
import { FormattedMessage, useIntl } from 'react-intl';
import { FormattedMessage } from 'react-intl';
import { useDispatch } from 'react-redux';
import { Link } from 'react-router-dom';
@ -27,11 +27,10 @@ const LinkFooter: React.FC = (): JSX.Element => {
const features = useFeatures();
const soapboxConfig = useSoapboxConfig();
const intl = useIntl();
const dispatch = useDispatch();
const onClickLogOut: React.EventHandler<React.MouseEvent> = (e) => {
dispatch(logOut(intl));
dispatch(logOut());
e.preventDefault();
};

@ -44,7 +44,7 @@ const Navbar = () => {
event.preventDefault();
setLoading(true);
dispatch(logIn(intl, username, password) as any)
dispatch(logIn(username, password) as any)
.then(({ access_token }: { access_token: string }) => {
setLoading(false);

@ -43,7 +43,7 @@ const ProfileDropdown: React.FC<IProfileDropdown> = ({ account, children }) => {
const otherAccounts = useAppSelector((state) => authUsers.map((authUser: any) => getAccount(state, authUser.get('id'))));
const handleLogOut = () => {
dispatch(logOut(intl));
dispatch(logOut());
};
const handleSwitchAccount = (account: AccountEntity) => {

@ -50,7 +50,7 @@ const Registration = () => {
// TODO: handle validation errors from Pepe
dispatch(createAccount(username, password))
.then(() => dispatch(logIn(intl, username, password)))
.then(() => dispatch(logIn(username, password)))
.then(({ access_token }: any) => dispatch(verifyCredentials(access_token)))
.then(() => dispatch(fetchInstance()))
.then(() => {

@ -1,5 +1,4 @@
import React, { useEffect } from 'react';
import { useIntl } from 'react-intl';
import { useDispatch } from 'react-redux';
import { Link } from 'react-router-dom';
@ -12,7 +11,6 @@ import { useAppSelector, useOwnAccount } from 'soapbox/hooks';
const WaitlistPage = (/* { account } */) => {
const dispatch = useDispatch();
const intl = useIntl();
const title = useAppSelector((state) => state.instance.title);
const me = useOwnAccount();
@ -20,7 +18,7 @@ const WaitlistPage = (/* { account } */) => {
const onClickLogOut: React.MouseEventHandler = (event) => {
event.preventDefault();
dispatch(logOut(intl));
dispatch(logOut());
};
const openVerifySmsModal = () => dispatch(openModal('VERIFY_SMS'));

@ -1,5 +1,5 @@
import { useDispatch } from 'react-redux';
import { AppDispatch } from 'soapbox/store';
import type { AppDispatch } from 'soapbox/store';
export const useAppDispatch = () => useDispatch<AppDispatch>();

@ -39,6 +39,7 @@ export const InstanceRecord = ImmutableRecord({
fedibird_capabilities: ImmutableList(),
invites_enabled: false,
languages: ImmutableList(),
login_message: '',
pleroma: ImmutableMap<string, any>({
metadata: ImmutableMap<string, any>({
account_activation_required: false,

@ -244,8 +244,8 @@ type APIChat = { id: string, last_message: string };
export const makeGetChat = () => {
return createSelector(
[
(state: RootState, { id }: APIChat) => state.chats.getIn(['items', id]) as ReducerChat,
(state: RootState, { id }: APIChat) => state.accounts.get(state.chats.getIn(['items', id, 'account'])),
(state: RootState, { id }: APIChat) => state.chats.items.get(id) as ReducerChat,
(state: RootState, { id }: APIChat) => state.accounts.get(state.chats.items.getIn([id, 'account'])),
(state: RootState, { last_message }: APIChat) => state.chat_messages.get(last_message),
],

@ -30,11 +30,11 @@ export const isLoggedIn = (getState: () => RootState) => {
return validId(getState().me);
};
export const getAppToken = (state: RootState) => state.auth.getIn(['app', 'access_token']);
export const getAppToken = (state: RootState) => state.auth.getIn(['app', 'access_token']) as string;
export const getUserToken = (state: RootState, accountId?: string | false | null) => {
const accountUrl = state.accounts.getIn([accountId, 'url']);
return state.auth.getIn(['users', accountUrl, 'access_token']);
return state.auth.getIn(['users', accountUrl, 'access_token']) as string;
};
export const getAccessToken = (state: RootState) => {

Loading…
Cancel
Save