kopia lustrzana https://gitlab.com/soapbox-pub/soapbox
Change eslint config, prefer arrow functions, prefer no braces
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>cleanup
rodzic
6413bed23f
commit
9b2d3ba1ee
|
@ -68,6 +68,7 @@ module.exports = {
|
|||
},
|
||||
|
||||
rules: {
|
||||
'arrow-body-style': 'error',
|
||||
'brace-style': 'error',
|
||||
'comma-dangle': ['error', 'always-multiline'],
|
||||
'comma-spacing': [
|
||||
|
@ -83,6 +84,7 @@ module.exports = {
|
|||
'space-in-parens': ['error', 'never'],
|
||||
'keyword-spacing': 'error',
|
||||
'dot-notation': 'error',
|
||||
'eol-last': ['error', 'always'],
|
||||
eqeqeq: 'error',
|
||||
indent: ['error', 2, {
|
||||
SwitchCase: 1, // https://stackoverflow.com/a/53055584/8811886
|
||||
|
@ -284,6 +286,7 @@ module.exports = {
|
|||
},
|
||||
],
|
||||
'tailwindcss/migration-from-tailwind-2': 'error',
|
||||
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
|
|
|
@ -163,4 +163,4 @@ describe('toasts', () =>{
|
|||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -31,44 +31,37 @@ const submitAccountNote = () => (dispatch: React.Dispatch<AnyAction>, getState:
|
|||
.catch(error => dispatch(submitAccountNoteFail(error)));
|
||||
};
|
||||
|
||||
function submitAccountNoteRequest() {
|
||||
return {
|
||||
type: ACCOUNT_NOTE_SUBMIT_REQUEST,
|
||||
const submitAccountNoteRequest = () => ({
|
||||
type: ACCOUNT_NOTE_SUBMIT_REQUEST,
|
||||
});
|
||||
|
||||
const submitAccountNoteSuccess = (relationship: any) => ({
|
||||
type: ACCOUNT_NOTE_SUBMIT_SUCCESS,
|
||||
relationship,
|
||||
});
|
||||
|
||||
const submitAccountNoteFail = (error: AxiosError) => ({
|
||||
type: ACCOUNT_NOTE_SUBMIT_FAIL,
|
||||
error,
|
||||
});
|
||||
|
||||
const initAccountNoteModal = (account: Account) =>
|
||||
(dispatch: React.Dispatch<AnyAction>, getState: () => RootState) => {
|
||||
const comment = getState().relationships.get(account.id)!.note;
|
||||
|
||||
dispatch({
|
||||
type: ACCOUNT_NOTE_INIT_MODAL,
|
||||
account,
|
||||
comment,
|
||||
});
|
||||
|
||||
dispatch(openModal('ACCOUNT_NOTE'));
|
||||
};
|
||||
}
|
||||
|
||||
function submitAccountNoteSuccess(relationship: any) {
|
||||
return {
|
||||
type: ACCOUNT_NOTE_SUBMIT_SUCCESS,
|
||||
relationship,
|
||||
};
|
||||
}
|
||||
|
||||
function submitAccountNoteFail(error: AxiosError) {
|
||||
return {
|
||||
type: ACCOUNT_NOTE_SUBMIT_FAIL,
|
||||
error,
|
||||
};
|
||||
}
|
||||
|
||||
const initAccountNoteModal = (account: Account) => (dispatch: React.Dispatch<AnyAction>, getState: () => RootState) => {
|
||||
const comment = getState().relationships.get(account.id)!.note;
|
||||
|
||||
dispatch({
|
||||
type: ACCOUNT_NOTE_INIT_MODAL,
|
||||
account,
|
||||
comment,
|
||||
});
|
||||
|
||||
dispatch(openModal('ACCOUNT_NOTE'));
|
||||
};
|
||||
|
||||
function changeAccountNoteComment(comment: string) {
|
||||
return {
|
||||
type: ACCOUNT_NOTE_CHANGE_COMMENT,
|
||||
comment,
|
||||
};
|
||||
}
|
||||
const changeAccountNoteComment = (comment: string) => ({
|
||||
type: ACCOUNT_NOTE_CHANGE_COMMENT,
|
||||
comment,
|
||||
});
|
||||
|
||||
export {
|
||||
submitAccountNote,
|
||||
|
|
|
@ -135,9 +135,9 @@ const noOp = () => new Promise(f => f(undefined));
|
|||
const createAccount = (params: Record<string, any>) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
dispatch({ type: ACCOUNT_CREATE_REQUEST, params });
|
||||
return api(getState, 'app').post('/api/v1/accounts', params).then(({ data: token }) => {
|
||||
return dispatch({ type: ACCOUNT_CREATE_SUCCESS, params, token });
|
||||
}).catch(error => {
|
||||
return api(getState, 'app').post('/api/v1/accounts', params).then(({ data: token }) =>
|
||||
dispatch({ type: ACCOUNT_CREATE_SUCCESS, params, token }),
|
||||
).catch(error => {
|
||||
dispatch({ type: ACCOUNT_CREATE_FAIL, error, params });
|
||||
throw error;
|
||||
});
|
||||
|
@ -310,10 +310,10 @@ const blockAccount = (id: string) =>
|
|||
|
||||
return api(getState)
|
||||
.post(`/api/v1/accounts/${id}/block`)
|
||||
.then(response => {
|
||||
.then(response =>
|
||||
// Pass in entire statuses map so we can use it to filter stuff in different parts of the reducers
|
||||
return dispatch(blockAccountSuccess(response.data, getState().statuses));
|
||||
}).catch(error => dispatch(blockAccountFail(error)));
|
||||
dispatch(blockAccountSuccess(response.data, getState().statuses)),
|
||||
).catch(error => dispatch(blockAccountFail(error)));
|
||||
};
|
||||
|
||||
const unblockAccount = (id: string) =>
|
||||
|
@ -383,10 +383,10 @@ const muteAccount = (id: string, notifications?: boolean, duration = 0) =>
|
|||
|
||||
return api(getState)
|
||||
.post(`/api/v1/accounts/${id}/mute`, params)
|
||||
.then(response => {
|
||||
.then(response =>
|
||||
// Pass in entire statuses map so we can use it to filter stuff in different parts of the reducers
|
||||
return dispatch(muteAccountSuccess(response.data, getState().statuses));
|
||||
})
|
||||
dispatch(muteAccountSuccess(response.data, getState().statuses)),
|
||||
)
|
||||
.catch(error => dispatch(muteAccountFail(error)));
|
||||
};
|
||||
|
||||
|
|
|
@ -7,31 +7,31 @@ import type { AxiosError } from 'axios';
|
|||
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||
import type { APIEntity } from 'soapbox/types/entities';
|
||||
|
||||
export const ANNOUNCEMENTS_FETCH_REQUEST = 'ANNOUNCEMENTS_FETCH_REQUEST';
|
||||
export const ANNOUNCEMENTS_FETCH_SUCCESS = 'ANNOUNCEMENTS_FETCH_SUCCESS';
|
||||
export const ANNOUNCEMENTS_FETCH_FAIL = 'ANNOUNCEMENTS_FETCH_FAIL';
|
||||
export const ANNOUNCEMENTS_UPDATE = 'ANNOUNCEMENTS_UPDATE';
|
||||
export const ANNOUNCEMENTS_DELETE = 'ANNOUNCEMENTS_DELETE';
|
||||
const ANNOUNCEMENTS_FETCH_REQUEST = 'ANNOUNCEMENTS_FETCH_REQUEST';
|
||||
const ANNOUNCEMENTS_FETCH_SUCCESS = 'ANNOUNCEMENTS_FETCH_SUCCESS';
|
||||
const ANNOUNCEMENTS_FETCH_FAIL = 'ANNOUNCEMENTS_FETCH_FAIL';
|
||||
const ANNOUNCEMENTS_UPDATE = 'ANNOUNCEMENTS_UPDATE';
|
||||
const ANNOUNCEMENTS_DELETE = 'ANNOUNCEMENTS_DELETE';
|
||||
|
||||
export const ANNOUNCEMENTS_DISMISS_REQUEST = 'ANNOUNCEMENTS_DISMISS_REQUEST';
|
||||
export const ANNOUNCEMENTS_DISMISS_SUCCESS = 'ANNOUNCEMENTS_DISMISS_SUCCESS';
|
||||
export const ANNOUNCEMENTS_DISMISS_FAIL = 'ANNOUNCEMENTS_DISMISS_FAIL';
|
||||
const ANNOUNCEMENTS_DISMISS_REQUEST = 'ANNOUNCEMENTS_DISMISS_REQUEST';
|
||||
const ANNOUNCEMENTS_DISMISS_SUCCESS = 'ANNOUNCEMENTS_DISMISS_SUCCESS';
|
||||
const ANNOUNCEMENTS_DISMISS_FAIL = 'ANNOUNCEMENTS_DISMISS_FAIL';
|
||||
|
||||
export const ANNOUNCEMENTS_REACTION_ADD_REQUEST = 'ANNOUNCEMENTS_REACTION_ADD_REQUEST';
|
||||
export const ANNOUNCEMENTS_REACTION_ADD_SUCCESS = 'ANNOUNCEMENTS_REACTION_ADD_SUCCESS';
|
||||
export const ANNOUNCEMENTS_REACTION_ADD_FAIL = 'ANNOUNCEMENTS_REACTION_ADD_FAIL';
|
||||
const ANNOUNCEMENTS_REACTION_ADD_REQUEST = 'ANNOUNCEMENTS_REACTION_ADD_REQUEST';
|
||||
const ANNOUNCEMENTS_REACTION_ADD_SUCCESS = 'ANNOUNCEMENTS_REACTION_ADD_SUCCESS';
|
||||
const ANNOUNCEMENTS_REACTION_ADD_FAIL = 'ANNOUNCEMENTS_REACTION_ADD_FAIL';
|
||||
|
||||
export const ANNOUNCEMENTS_REACTION_REMOVE_REQUEST = 'ANNOUNCEMENTS_REACTION_REMOVE_REQUEST';
|
||||
export const ANNOUNCEMENTS_REACTION_REMOVE_SUCCESS = 'ANNOUNCEMENTS_REACTION_REMOVE_SUCCESS';
|
||||
export const ANNOUNCEMENTS_REACTION_REMOVE_FAIL = 'ANNOUNCEMENTS_REACTION_REMOVE_FAIL';
|
||||
const ANNOUNCEMENTS_REACTION_REMOVE_REQUEST = 'ANNOUNCEMENTS_REACTION_REMOVE_REQUEST';
|
||||
const ANNOUNCEMENTS_REACTION_REMOVE_SUCCESS = 'ANNOUNCEMENTS_REACTION_REMOVE_SUCCESS';
|
||||
const ANNOUNCEMENTS_REACTION_REMOVE_FAIL = 'ANNOUNCEMENTS_REACTION_REMOVE_FAIL';
|
||||
|
||||
export const ANNOUNCEMENTS_REACTION_UPDATE = 'ANNOUNCEMENTS_REACTION_UPDATE';
|
||||
const ANNOUNCEMENTS_REACTION_UPDATE = 'ANNOUNCEMENTS_REACTION_UPDATE';
|
||||
|
||||
export const ANNOUNCEMENTS_TOGGLE_SHOW = 'ANNOUNCEMENTS_TOGGLE_SHOW';
|
||||
const ANNOUNCEMENTS_TOGGLE_SHOW = 'ANNOUNCEMENTS_TOGGLE_SHOW';
|
||||
|
||||
const noOp = () => {};
|
||||
|
||||
export const fetchAnnouncements = (done = noOp) =>
|
||||
const fetchAnnouncements = (done = noOp) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
const { instance } = getState();
|
||||
const features = getFeatures(instance);
|
||||
|
@ -50,30 +50,30 @@ export const fetchAnnouncements = (done = noOp) =>
|
|||
});
|
||||
};
|
||||
|
||||
export const fetchAnnouncementsRequest = () => ({
|
||||
const fetchAnnouncementsRequest = () => ({
|
||||
type: ANNOUNCEMENTS_FETCH_REQUEST,
|
||||
skipLoading: true,
|
||||
});
|
||||
|
||||
export const fetchAnnouncementsSuccess = (announcements: APIEntity) => ({
|
||||
const fetchAnnouncementsSuccess = (announcements: APIEntity) => ({
|
||||
type: ANNOUNCEMENTS_FETCH_SUCCESS,
|
||||
announcements,
|
||||
skipLoading: true,
|
||||
});
|
||||
|
||||
export const fetchAnnouncementsFail = (error: AxiosError) => ({
|
||||
const fetchAnnouncementsFail = (error: AxiosError) => ({
|
||||
type: ANNOUNCEMENTS_FETCH_FAIL,
|
||||
error,
|
||||
skipLoading: true,
|
||||
skipAlert: true,
|
||||
});
|
||||
|
||||
export const updateAnnouncements = (announcement: APIEntity) => ({
|
||||
const updateAnnouncements = (announcement: APIEntity) => ({
|
||||
type: ANNOUNCEMENTS_UPDATE,
|
||||
announcement: announcement,
|
||||
});
|
||||
|
||||
export const dismissAnnouncement = (announcementId: string) =>
|
||||
const dismissAnnouncement = (announcementId: string) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
dispatch(dismissAnnouncementRequest(announcementId));
|
||||
|
||||
|
@ -84,23 +84,23 @@ export const dismissAnnouncement = (announcementId: string) =>
|
|||
});
|
||||
};
|
||||
|
||||
export const dismissAnnouncementRequest = (announcementId: string) => ({
|
||||
const dismissAnnouncementRequest = (announcementId: string) => ({
|
||||
type: ANNOUNCEMENTS_DISMISS_REQUEST,
|
||||
id: announcementId,
|
||||
});
|
||||
|
||||
export const dismissAnnouncementSuccess = (announcementId: string) => ({
|
||||
const dismissAnnouncementSuccess = (announcementId: string) => ({
|
||||
type: ANNOUNCEMENTS_DISMISS_SUCCESS,
|
||||
id: announcementId,
|
||||
});
|
||||
|
||||
export const dismissAnnouncementFail = (announcementId: string, error: AxiosError) => ({
|
||||
const dismissAnnouncementFail = (announcementId: string, error: AxiosError) => ({
|
||||
type: ANNOUNCEMENTS_DISMISS_FAIL,
|
||||
id: announcementId,
|
||||
error,
|
||||
});
|
||||
|
||||
export const addReaction = (announcementId: string, name: string) =>
|
||||
const addReaction = (announcementId: string, name: string) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
const announcement = getState().announcements.items.find(x => x.get('id') === announcementId);
|
||||
|
||||
|
@ -127,21 +127,21 @@ export const addReaction = (announcementId: string, name: string) =>
|
|||
});
|
||||
};
|
||||
|
||||
export const addReactionRequest = (announcementId: string, name: string, alreadyAdded?: boolean) => ({
|
||||
const addReactionRequest = (announcementId: string, name: string, alreadyAdded?: boolean) => ({
|
||||
type: ANNOUNCEMENTS_REACTION_ADD_REQUEST,
|
||||
id: announcementId,
|
||||
name,
|
||||
skipLoading: true,
|
||||
});
|
||||
|
||||
export const addReactionSuccess = (announcementId: string, name: string, alreadyAdded?: boolean) => ({
|
||||
const addReactionSuccess = (announcementId: string, name: string, alreadyAdded?: boolean) => ({
|
||||
type: ANNOUNCEMENTS_REACTION_ADD_SUCCESS,
|
||||
id: announcementId,
|
||||
name,
|
||||
skipLoading: true,
|
||||
});
|
||||
|
||||
export const addReactionFail = (announcementId: string, name: string, error: AxiosError) => ({
|
||||
const addReactionFail = (announcementId: string, name: string, error: AxiosError) => ({
|
||||
type: ANNOUNCEMENTS_REACTION_ADD_FAIL,
|
||||
id: announcementId,
|
||||
name,
|
||||
|
@ -149,7 +149,7 @@ export const addReactionFail = (announcementId: string, name: string, error: Axi
|
|||
skipLoading: true,
|
||||
});
|
||||
|
||||
export const removeReaction = (announcementId: string, name: string) =>
|
||||
const removeReaction = (announcementId: string, name: string) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
dispatch(removeReactionRequest(announcementId, name));
|
||||
|
||||
|
@ -160,21 +160,21 @@ export const removeReaction = (announcementId: string, name: string) =>
|
|||
});
|
||||
};
|
||||
|
||||
export const removeReactionRequest = (announcementId: string, name: string) => ({
|
||||
const removeReactionRequest = (announcementId: string, name: string) => ({
|
||||
type: ANNOUNCEMENTS_REACTION_REMOVE_REQUEST,
|
||||
id: announcementId,
|
||||
name,
|
||||
skipLoading: true,
|
||||
});
|
||||
|
||||
export const removeReactionSuccess = (announcementId: string, name: string) => ({
|
||||
const removeReactionSuccess = (announcementId: string, name: string) => ({
|
||||
type: ANNOUNCEMENTS_REACTION_REMOVE_SUCCESS,
|
||||
id: announcementId,
|
||||
name,
|
||||
skipLoading: true,
|
||||
});
|
||||
|
||||
export const removeReactionFail = (announcementId: string, name: string, error: AxiosError) => ({
|
||||
const removeReactionFail = (announcementId: string, name: string, error: AxiosError) => ({
|
||||
type: ANNOUNCEMENTS_REACTION_REMOVE_FAIL,
|
||||
id: announcementId,
|
||||
name,
|
||||
|
@ -182,16 +182,55 @@ export const removeReactionFail = (announcementId: string, name: string, error:
|
|||
skipLoading: true,
|
||||
});
|
||||
|
||||
export const updateReaction = (reaction: APIEntity) => ({
|
||||
const updateReaction = (reaction: APIEntity) => ({
|
||||
type: ANNOUNCEMENTS_REACTION_UPDATE,
|
||||
reaction,
|
||||
});
|
||||
|
||||
export const toggleShowAnnouncements = () => ({
|
||||
const toggleShowAnnouncements = () => ({
|
||||
type: ANNOUNCEMENTS_TOGGLE_SHOW,
|
||||
});
|
||||
|
||||
export const deleteAnnouncement = (id: string) => ({
|
||||
const deleteAnnouncement = (id: string) => ({
|
||||
type: ANNOUNCEMENTS_DELETE,
|
||||
id,
|
||||
});
|
||||
|
||||
export {
|
||||
ANNOUNCEMENTS_FETCH_REQUEST,
|
||||
ANNOUNCEMENTS_FETCH_SUCCESS,
|
||||
ANNOUNCEMENTS_FETCH_FAIL,
|
||||
ANNOUNCEMENTS_UPDATE,
|
||||
ANNOUNCEMENTS_DELETE,
|
||||
ANNOUNCEMENTS_DISMISS_REQUEST,
|
||||
ANNOUNCEMENTS_DISMISS_SUCCESS,
|
||||
ANNOUNCEMENTS_DISMISS_FAIL,
|
||||
ANNOUNCEMENTS_REACTION_ADD_REQUEST,
|
||||
ANNOUNCEMENTS_REACTION_ADD_SUCCESS,
|
||||
ANNOUNCEMENTS_REACTION_ADD_FAIL,
|
||||
ANNOUNCEMENTS_REACTION_REMOVE_REQUEST,
|
||||
ANNOUNCEMENTS_REACTION_REMOVE_SUCCESS,
|
||||
ANNOUNCEMENTS_REACTION_REMOVE_FAIL,
|
||||
ANNOUNCEMENTS_REACTION_UPDATE,
|
||||
ANNOUNCEMENTS_TOGGLE_SHOW,
|
||||
fetchAnnouncements,
|
||||
fetchAnnouncementsRequest,
|
||||
fetchAnnouncementsSuccess,
|
||||
fetchAnnouncementsFail,
|
||||
updateAnnouncements,
|
||||
dismissAnnouncement,
|
||||
dismissAnnouncementRequest,
|
||||
dismissAnnouncementSuccess,
|
||||
dismissAnnouncementFail,
|
||||
addReaction,
|
||||
addReactionRequest,
|
||||
addReactionSuccess,
|
||||
addReactionFail,
|
||||
removeReaction,
|
||||
removeReactionRequest,
|
||||
removeReactionSuccess,
|
||||
removeReactionFail,
|
||||
updateReaction,
|
||||
toggleShowAnnouncements,
|
||||
deleteAnnouncement,
|
||||
};
|
||||
|
|
|
@ -10,17 +10,18 @@ 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';
|
||||
const APP_CREATE_REQUEST = 'APP_CREATE_REQUEST';
|
||||
const APP_CREATE_SUCCESS = 'APP_CREATE_SUCCESS';
|
||||
const APP_CREATE_FAIL = 'APP_CREATE_FAIL';
|
||||
|
||||
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';
|
||||
const APP_VERIFY_CREDENTIALS_REQUEST = 'APP_VERIFY_CREDENTIALS_REQUEST';
|
||||
const APP_VERIFY_CREDENTIALS_SUCCESS = 'APP_VERIFY_CREDENTIALS_SUCCESS';
|
||||
const APP_VERIFY_CREDENTIALS_FAIL = 'APP_VERIFY_CREDENTIALS_FAIL';
|
||||
|
||||
export function createApp(params?: Record<string, string>, baseURL?: string) {
|
||||
return (dispatch: React.Dispatch<AnyAction>) => {
|
||||
const createApp = (params?: Record<string, string>, baseURL?: string) =>
|
||||
(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 as Record<string, string>;
|
||||
|
@ -29,11 +30,11 @@ export function createApp(params?: Record<string, string>, baseURL?: string) {
|
|||
throw error;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function verifyAppCredentials(token: string) {
|
||||
return (dispatch: React.Dispatch<AnyAction>) => {
|
||||
const verifyAppCredentials = (token: string) =>
|
||||
(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 });
|
||||
return app;
|
||||
|
@ -42,4 +43,14 @@ export function verifyAppCredentials(token: string) {
|
|||
throw error;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export {
|
||||
APP_CREATE_REQUEST,
|
||||
APP_CREATE_SUCCESS,
|
||||
APP_CREATE_FAIL,
|
||||
APP_VERIFY_CREDENTIALS_REQUEST,
|
||||
APP_VERIFY_CREDENTIALS_SUCCESS,
|
||||
APP_VERIFY_CREDENTIALS_FAIL,
|
||||
createApp,
|
||||
verifyAppCredentials,
|
||||
};
|
||||
|
|
|
@ -31,24 +31,24 @@ import { importFetchedAccount } from './importer';
|
|||
import type { AxiosError } from 'axios';
|
||||
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||
|
||||
export const SWITCH_ACCOUNT = 'SWITCH_ACCOUNT';
|
||||
const SWITCH_ACCOUNT = 'SWITCH_ACCOUNT';
|
||||
|
||||
export const AUTH_APP_CREATED = 'AUTH_APP_CREATED';
|
||||
export const AUTH_APP_AUTHORIZED = 'AUTH_APP_AUTHORIZED';
|
||||
export const AUTH_LOGGED_IN = 'AUTH_LOGGED_IN';
|
||||
export const AUTH_LOGGED_OUT = 'AUTH_LOGGED_OUT';
|
||||
const AUTH_APP_CREATED = 'AUTH_APP_CREATED';
|
||||
const AUTH_APP_AUTHORIZED = 'AUTH_APP_AUTHORIZED';
|
||||
const AUTH_LOGGED_IN = 'AUTH_LOGGED_IN';
|
||||
const AUTH_LOGGED_OUT = 'AUTH_LOGGED_OUT';
|
||||
|
||||
export const VERIFY_CREDENTIALS_REQUEST = 'VERIFY_CREDENTIALS_REQUEST';
|
||||
export const VERIFY_CREDENTIALS_SUCCESS = 'VERIFY_CREDENTIALS_SUCCESS';
|
||||
export const VERIFY_CREDENTIALS_FAIL = 'VERIFY_CREDENTIALS_FAIL';
|
||||
const VERIFY_CREDENTIALS_REQUEST = 'VERIFY_CREDENTIALS_REQUEST';
|
||||
const VERIFY_CREDENTIALS_SUCCESS = 'VERIFY_CREDENTIALS_SUCCESS';
|
||||
const VERIFY_CREDENTIALS_FAIL = 'VERIFY_CREDENTIALS_FAIL';
|
||||
|
||||
export const AUTH_ACCOUNT_REMEMBER_REQUEST = 'AUTH_ACCOUNT_REMEMBER_REQUEST';
|
||||
export const AUTH_ACCOUNT_REMEMBER_SUCCESS = 'AUTH_ACCOUNT_REMEMBER_SUCCESS';
|
||||
export const AUTH_ACCOUNT_REMEMBER_FAIL = 'AUTH_ACCOUNT_REMEMBER_FAIL';
|
||||
const AUTH_ACCOUNT_REMEMBER_REQUEST = 'AUTH_ACCOUNT_REMEMBER_REQUEST';
|
||||
const AUTH_ACCOUNT_REMEMBER_SUCCESS = 'AUTH_ACCOUNT_REMEMBER_SUCCESS';
|
||||
const AUTH_ACCOUNT_REMEMBER_FAIL = 'AUTH_ACCOUNT_REMEMBER_FAIL';
|
||||
|
||||
const customApp = custom('app');
|
||||
|
||||
export const messages = defineMessages({
|
||||
const messages = defineMessages({
|
||||
loggedOut: { id: 'auth.logged_out', defaultMessage: 'Logged out.' },
|
||||
awaitingApproval: { id: 'auth.awaiting_approval', defaultMessage: 'Your account is awaiting approval' },
|
||||
invalidCredentials: { id: 'auth.invalid_credentials', defaultMessage: 'Wrong username or password' },
|
||||
|
@ -121,7 +121,7 @@ const createUserToken = (username: string, password: string) =>
|
|||
.then((token: Record<string, string | number>) => dispatch(authLoggedIn(token)));
|
||||
};
|
||||
|
||||
export const otpVerify = (code: string, mfa_token: string) =>
|
||||
const otpVerify = (code: string, mfa_token: string) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
const app = getState().auth.app;
|
||||
return api(getState, 'app').post('/oauth/mfa/challenge', {
|
||||
|
@ -135,7 +135,7 @@ export const otpVerify = (code: string, mfa_token: string) =>
|
|||
}).then(({ data: token }) => dispatch(authLoggedIn(token)));
|
||||
};
|
||||
|
||||
export const verifyCredentials = (token: string, accountUrl?: string) => {
|
||||
const verifyCredentials = (token: string, accountUrl?: string) => {
|
||||
const baseURL = parseBaseURL(accountUrl);
|
||||
|
||||
return (dispatch: AppDispatch, getState: () => RootState) => {
|
||||
|
@ -163,7 +163,7 @@ export const verifyCredentials = (token: string, accountUrl?: string) => {
|
|||
};
|
||||
};
|
||||
|
||||
export const rememberAuthAccount = (accountUrl: string) =>
|
||||
const rememberAuthAccount = (accountUrl: string) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
dispatch({ type: AUTH_ACCOUNT_REMEMBER_REQUEST, accountUrl });
|
||||
return KVStore.getItemOrError(`authAccount:${accountUrl}`).then(account => {
|
||||
|
@ -176,15 +176,15 @@ export const rememberAuthAccount = (accountUrl: string) =>
|
|||
});
|
||||
};
|
||||
|
||||
export const loadCredentials = (token: string, accountUrl: string) =>
|
||||
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(normalizeUsername(username), password));
|
||||
}).catch((error: AxiosError) => {
|
||||
const logIn = (username: string, password: string) =>
|
||||
(dispatch: AppDispatch) => dispatch(getAuthApp()).then(() =>
|
||||
dispatch(createUserToken(normalizeUsername(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;
|
||||
|
@ -197,10 +197,10 @@ export const logIn = (username: string, password: string) =>
|
|||
throw error;
|
||||
});
|
||||
|
||||
export const deleteSession = () =>
|
||||
const deleteSession = () =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => api(getState).delete('/api/sign_out');
|
||||
|
||||
export const logOut = () =>
|
||||
const logOut = () =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
const state = getState();
|
||||
const account = getLoggedInAccount(state);
|
||||
|
@ -226,7 +226,7 @@ export const logOut = () =>
|
|||
});
|
||||
};
|
||||
|
||||
export const switchAccount = (accountId: string, background = false) =>
|
||||
const switchAccount = (accountId: string, background = false) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
const account = getState().accounts.get(accountId);
|
||||
// Clear all stored cache from React Query
|
||||
|
@ -236,7 +236,7 @@ export const switchAccount = (accountId: string, background = false) =>
|
|||
return dispatch({ type: SWITCH_ACCOUNT, account, background });
|
||||
};
|
||||
|
||||
export const fetchOwnAccounts = () =>
|
||||
const fetchOwnAccounts = () =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
const state = getState();
|
||||
return state.auth.users.forEach((user) => {
|
||||
|
@ -247,7 +247,7 @@ export const fetchOwnAccounts = () =>
|
|||
});
|
||||
};
|
||||
|
||||
export const register = (params: Record<string, any>) =>
|
||||
const register = (params: Record<string, any>) =>
|
||||
(dispatch: AppDispatch) => {
|
||||
params.fullname = params.username;
|
||||
|
||||
|
@ -259,13 +259,39 @@ export const register = (params: Record<string, any>) =>
|
|||
});
|
||||
};
|
||||
|
||||
export const fetchCaptcha = () =>
|
||||
(_dispatch: AppDispatch, getState: () => RootState) => {
|
||||
return api(getState).get('/api/pleroma/captcha');
|
||||
};
|
||||
const fetchCaptcha = () =>
|
||||
(_dispatch: AppDispatch, getState: () => RootState) =>
|
||||
api(getState).get('/api/pleroma/captcha');
|
||||
|
||||
export const authLoggedIn = (token: Record<string, string | number>) =>
|
||||
const authLoggedIn = (token: Record<string, string | number>) =>
|
||||
(dispatch: AppDispatch) => {
|
||||
dispatch({ type: AUTH_LOGGED_IN, token });
|
||||
return token;
|
||||
};
|
||||
|
||||
export {
|
||||
SWITCH_ACCOUNT,
|
||||
AUTH_APP_CREATED,
|
||||
AUTH_APP_AUTHORIZED,
|
||||
AUTH_LOGGED_IN,
|
||||
AUTH_LOGGED_OUT,
|
||||
VERIFY_CREDENTIALS_REQUEST,
|
||||
VERIFY_CREDENTIALS_SUCCESS,
|
||||
VERIFY_CREDENTIALS_FAIL,
|
||||
AUTH_ACCOUNT_REMEMBER_REQUEST,
|
||||
AUTH_ACCOUNT_REMEMBER_SUCCESS,
|
||||
AUTH_ACCOUNT_REMEMBER_FAIL,
|
||||
messages,
|
||||
otpVerify,
|
||||
verifyCredentials,
|
||||
rememberAuthAccount,
|
||||
loadCredentials,
|
||||
logIn,
|
||||
deleteSession,
|
||||
logOut,
|
||||
switchAccount,
|
||||
fetchOwnAccounts,
|
||||
register,
|
||||
fetchCaptcha,
|
||||
authLoggedIn,
|
||||
};
|
||||
|
|
|
@ -2,15 +2,15 @@ import api from '../api';
|
|||
|
||||
import type { AppDispatch, RootState } 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';
|
||||
const BACKUPS_FETCH_REQUEST = 'BACKUPS_FETCH_REQUEST';
|
||||
const BACKUPS_FETCH_SUCCESS = 'BACKUPS_FETCH_SUCCESS';
|
||||
const BACKUPS_FETCH_FAIL = 'BACKUPS_FETCH_FAIL';
|
||||
|
||||
export const BACKUPS_CREATE_REQUEST = 'BACKUPS_CREATE_REQUEST';
|
||||
export const BACKUPS_CREATE_SUCCESS = 'BACKUPS_CREATE_SUCCESS';
|
||||
export const BACKUPS_CREATE_FAIL = 'BACKUPS_CREATE_FAIL';
|
||||
const BACKUPS_CREATE_REQUEST = 'BACKUPS_CREATE_REQUEST';
|
||||
const BACKUPS_CREATE_SUCCESS = 'BACKUPS_CREATE_SUCCESS';
|
||||
const BACKUPS_CREATE_FAIL = 'BACKUPS_CREATE_FAIL';
|
||||
|
||||
export const fetchBackups = () =>
|
||||
const fetchBackups = () =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
dispatch({ type: BACKUPS_FETCH_REQUEST });
|
||||
return api(getState).get('/api/v1/pleroma/backups').then(({ data: backups }) =>
|
||||
|
@ -20,7 +20,7 @@ export const fetchBackups = () =>
|
|||
});
|
||||
};
|
||||
|
||||
export const createBackup = () =>
|
||||
const createBackup = () =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
dispatch({ type: BACKUPS_CREATE_REQUEST });
|
||||
return api(getState).post('/api/v1/pleroma/backups').then(({ data: backups }) =>
|
||||
|
@ -29,3 +29,14 @@ export const createBackup = () =>
|
|||
dispatch({ type: BACKUPS_CREATE_FAIL, error });
|
||||
});
|
||||
};
|
||||
|
||||
export {
|
||||
BACKUPS_FETCH_REQUEST,
|
||||
BACKUPS_FETCH_SUCCESS,
|
||||
BACKUPS_FETCH_FAIL,
|
||||
BACKUPS_CREATE_REQUEST,
|
||||
BACKUPS_CREATE_SUCCESS,
|
||||
BACKUPS_CREATE_FAIL,
|
||||
fetchBackups,
|
||||
createBackup,
|
||||
};
|
||||
|
|
|
@ -35,24 +35,18 @@ const fetchBlocks = () => (dispatch: React.Dispatch<AnyAction>, getState: () =>
|
|||
.catch(error => dispatch(fetchBlocksFail(error)));
|
||||
};
|
||||
|
||||
function fetchBlocksRequest() {
|
||||
return { type: BLOCKS_FETCH_REQUEST };
|
||||
}
|
||||
const fetchBlocksRequest = () => ({ type: BLOCKS_FETCH_REQUEST });
|
||||
|
||||
function fetchBlocksSuccess(accounts: any, next: any) {
|
||||
return {
|
||||
type: BLOCKS_FETCH_SUCCESS,
|
||||
accounts,
|
||||
next,
|
||||
};
|
||||
}
|
||||
const fetchBlocksSuccess = (accounts: any, next: any) => ({
|
||||
type: BLOCKS_FETCH_SUCCESS,
|
||||
accounts,
|
||||
next,
|
||||
});
|
||||
|
||||
function fetchBlocksFail(error: AxiosError) {
|
||||
return {
|
||||
type: BLOCKS_FETCH_FAIL,
|
||||
error,
|
||||
};
|
||||
}
|
||||
const fetchBlocksFail = (error: AxiosError) => ({
|
||||
type: BLOCKS_FETCH_FAIL,
|
||||
error,
|
||||
});
|
||||
|
||||
const expandBlocks = () => (dispatch: React.Dispatch<AnyAction>, getState: () => RootState) => {
|
||||
if (!isLoggedIn(getState)) return null;
|
||||
|
@ -77,26 +71,20 @@ const expandBlocks = () => (dispatch: React.Dispatch<AnyAction>, getState: () =>
|
|||
.catch(error => dispatch(expandBlocksFail(error)));
|
||||
};
|
||||
|
||||
function expandBlocksRequest() {
|
||||
return {
|
||||
type: BLOCKS_EXPAND_REQUEST,
|
||||
};
|
||||
}
|
||||
const expandBlocksRequest = () => ({
|
||||
type: BLOCKS_EXPAND_REQUEST,
|
||||
});
|
||||
|
||||
function expandBlocksSuccess(accounts: any, next: any) {
|
||||
return {
|
||||
type: BLOCKS_EXPAND_SUCCESS,
|
||||
accounts,
|
||||
next,
|
||||
};
|
||||
}
|
||||
const expandBlocksSuccess = (accounts: any, next: any) => ({
|
||||
type: BLOCKS_EXPAND_SUCCESS,
|
||||
accounts,
|
||||
next,
|
||||
});
|
||||
|
||||
function expandBlocksFail(error: AxiosError) {
|
||||
return {
|
||||
type: BLOCKS_EXPAND_FAIL,
|
||||
error,
|
||||
};
|
||||
}
|
||||
const expandBlocksFail = (error: AxiosError) => ({
|
||||
type: BLOCKS_EXPAND_FAIL,
|
||||
error,
|
||||
});
|
||||
|
||||
export {
|
||||
fetchBlocks,
|
||||
|
|
|
@ -213,16 +213,16 @@ const deleteChatMessage = (chatId: string, messageId: string) =>
|
|||
const launchChat = (accountId: string, router: History, forceNavigate = false) => {
|
||||
const isMobile = (width: number) => width <= 1190;
|
||||
|
||||
return (dispatch: AppDispatch) => {
|
||||
return (dispatch: AppDispatch) =>
|
||||
// TODO: make this faster
|
||||
return dispatch(startChat(accountId)).then(chat => {
|
||||
dispatch(startChat(accountId)).then(chat => {
|
||||
if (forceNavigate || isMobile(window.innerWidth)) {
|
||||
router.push(`/chats/${chat.id}`);
|
||||
} else {
|
||||
dispatch(openChat(chat.id));
|
||||
}
|
||||
});
|
||||
};
|
||||
})
|
||||
;
|
||||
};
|
||||
|
||||
export {
|
||||
|
|
|
@ -292,12 +292,12 @@ const submitCompose = (composeId: string, routerHistory?: History, force = false
|
|||
group_id: compose.privacy === 'group' ? compose.group_id : null,
|
||||
};
|
||||
|
||||
dispatch(createStatus(params, idempotencyKey, statusId)).then(function(data) {
|
||||
dispatch(createStatus(params, idempotencyKey, statusId)).then((data) => {
|
||||
if (!statusId && data.visibility === 'direct' && getState().conversations.mounted <= 0 && routerHistory) {
|
||||
routerHistory.push('/messages');
|
||||
}
|
||||
handleComposeSubmit(dispatch, getState, composeId, data, status, !!statusId);
|
||||
}).catch(function(error) {
|
||||
}).catch((error) => {
|
||||
dispatch(submitComposeFail(composeId, error));
|
||||
});
|
||||
};
|
||||
|
|
|
@ -9,8 +9,8 @@ import { createApp } from './apps';
|
|||
|
||||
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||
|
||||
const createProviderApp = () => {
|
||||
return async(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
const createProviderApp = () =>
|
||||
async(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
const scopes = getScopes(getState());
|
||||
|
||||
const params = {
|
||||
|
@ -22,10 +22,9 @@ const createProviderApp = () => {
|
|||
|
||||
return dispatch(createApp(params));
|
||||
};
|
||||
};
|
||||
|
||||
export const prepareRequest = (provider: string) => {
|
||||
return async(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
const prepareRequest = (provider: string) =>
|
||||
async(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
const baseURL = isURL(BuildConfig.BACKEND_URL) ? BuildConfig.BACKEND_URL : '';
|
||||
|
||||
const scopes = getScopes(getState());
|
||||
|
@ -50,4 +49,5 @@ export const prepareRequest = (provider: string) => {
|
|||
|
||||
location.href = `${baseURL}/oauth/prepare_request?${query.toString()}`;
|
||||
};
|
||||
};
|
||||
|
||||
export { prepareRequest };
|
||||
|
|
|
@ -110,4 +110,4 @@ export {
|
|||
expandConversationsSuccess,
|
||||
expandConversationsFail,
|
||||
updateConversations,
|
||||
};
|
||||
};
|
||||
|
|
|
@ -82,4 +82,4 @@ export {
|
|||
expandDirectoryRequest,
|
||||
expandDirectorySuccess,
|
||||
expandDirectoryFail,
|
||||
};
|
||||
};
|
||||
|
|
|
@ -151,7 +151,7 @@ const expandDomainBlocksSuccess = (domains: string[], next: string | null) => ({
|
|||
next,
|
||||
});
|
||||
|
||||
const expandDomainBlocksFail = (error: AxiosError) => ({
|
||||
const expandDomainBlocksFail = (error: AxiosError) => ({
|
||||
type: DOMAIN_BLOCKS_EXPAND_FAIL,
|
||||
error,
|
||||
});
|
||||
|
|
|
@ -78,10 +78,10 @@ const emojiReact = (status: Status, emoji: string) =>
|
|||
|
||||
return api(getState)
|
||||
.put(`/api/v1/pleroma/statuses/${status.get('id')}/reactions/${emoji}`)
|
||||
.then(function(response) {
|
||||
.then((response) => {
|
||||
dispatch(importFetchedStatus(response.data));
|
||||
dispatch(emojiReactSuccess(status, emoji));
|
||||
}).catch(function(error) {
|
||||
}).catch((error) => {
|
||||
dispatch(emojiReactFail(status, emoji, error));
|
||||
});
|
||||
};
|
||||
|
|
|
@ -271,7 +271,7 @@ const submitEvent = () =>
|
|||
actionLink: `/@${data.account.acct}/events/${data.id}`,
|
||||
},
|
||||
);
|
||||
}).catch(function(error) {
|
||||
}).catch((error) => {
|
||||
dispatch(submitEventFail(error));
|
||||
});
|
||||
};
|
||||
|
@ -312,7 +312,7 @@ const joinEvent = (id: string, participationMessage?: string) =>
|
|||
actionLink: `/@${data.account.acct}/events/${data.id}`,
|
||||
},
|
||||
);
|
||||
}).catch(function(error) {
|
||||
}).catch((error) => {
|
||||
dispatch(joinEventFail(error, status, status?.event?.join_state || null));
|
||||
});
|
||||
};
|
||||
|
@ -347,7 +347,7 @@ const leaveEvent = (id: string) =>
|
|||
return api(getState).post(`/api/v1/pleroma/events/${id}/leave`).then(({ data }) => {
|
||||
dispatch(importFetchedStatus(data));
|
||||
dispatch(leaveEventSuccess(data));
|
||||
}).catch(function(error) {
|
||||
}).catch((error) => {
|
||||
dispatch(leaveEventFail(error, status));
|
||||
});
|
||||
};
|
||||
|
|
|
@ -7,17 +7,17 @@ import toast from 'soapbox/toast';
|
|||
import type { AxiosResponse } from 'axios';
|
||||
import type { RootState } from 'soapbox/store';
|
||||
|
||||
export const EXPORT_FOLLOWS_REQUEST = 'EXPORT_FOLLOWS_REQUEST';
|
||||
export const EXPORT_FOLLOWS_SUCCESS = 'EXPORT_FOLLOWS_SUCCESS';
|
||||
export const EXPORT_FOLLOWS_FAIL = 'EXPORT_FOLLOWS_FAIL';
|
||||
const EXPORT_FOLLOWS_REQUEST = 'EXPORT_FOLLOWS_REQUEST';
|
||||
const EXPORT_FOLLOWS_SUCCESS = 'EXPORT_FOLLOWS_SUCCESS';
|
||||
const EXPORT_FOLLOWS_FAIL = 'EXPORT_FOLLOWS_FAIL';
|
||||
|
||||
export const EXPORT_BLOCKS_REQUEST = 'EXPORT_BLOCKS_REQUEST';
|
||||
export const EXPORT_BLOCKS_SUCCESS = 'EXPORT_BLOCKS_SUCCESS';
|
||||
export const EXPORT_BLOCKS_FAIL = 'EXPORT_BLOCKS_FAIL';
|
||||
const EXPORT_BLOCKS_REQUEST = 'EXPORT_BLOCKS_REQUEST';
|
||||
const EXPORT_BLOCKS_SUCCESS = 'EXPORT_BLOCKS_SUCCESS';
|
||||
const EXPORT_BLOCKS_FAIL = 'EXPORT_BLOCKS_FAIL';
|
||||
|
||||
export const EXPORT_MUTES_REQUEST = 'EXPORT_MUTES_REQUEST';
|
||||
export const EXPORT_MUTES_SUCCESS = 'EXPORT_MUTES_SUCCESS';
|
||||
export const EXPORT_MUTES_FAIL = 'EXPORT_MUTES_FAIL';
|
||||
const EXPORT_MUTES_REQUEST = 'EXPORT_MUTES_REQUEST';
|
||||
const EXPORT_MUTES_SUCCESS = 'EXPORT_MUTES_SUCCESS';
|
||||
const EXPORT_MUTES_FAIL = 'EXPORT_MUTES_FAIL';
|
||||
|
||||
const messages = defineMessages({
|
||||
blocksSuccess: { id: 'export_data.success.blocks', defaultMessage: 'Blocks exported successfully' },
|
||||
|
@ -38,7 +38,7 @@ type ExportDataActions = {
|
|||
error?: any
|
||||
}
|
||||
|
||||
function fileExport(content: string, fileName: string) {
|
||||
const fileExport = (content: string, fileName: string) => {
|
||||
const fileToDownload = document.createElement('a');
|
||||
|
||||
fileToDownload.setAttribute('href', 'data:text/csv;charset=utf-8,' + encodeURIComponent(content));
|
||||
|
@ -47,7 +47,7 @@ function fileExport(content: string, fileName: string) {
|
|||
document.body.appendChild(fileToDownload);
|
||||
fileToDownload.click();
|
||||
document.body.removeChild(fileToDownload);
|
||||
}
|
||||
};
|
||||
|
||||
const listAccounts = (getState: () => RootState) => async(apiResponse: AxiosResponse<any, any>) => {
|
||||
const followings = apiResponse.data;
|
||||
|
@ -63,7 +63,7 @@ const listAccounts = (getState: () => RootState) => async(apiResponse: AxiosResp
|
|||
return Array.from(new Set(accounts));
|
||||
};
|
||||
|
||||
export const exportFollows = () => (dispatch: React.Dispatch<ExportDataActions>, getState: () => RootState) => {
|
||||
const exportFollows = () => (dispatch: React.Dispatch<ExportDataActions>, getState: () => RootState) => {
|
||||
dispatch({ type: EXPORT_FOLLOWS_REQUEST });
|
||||
const me = getState().me;
|
||||
return api(getState)
|
||||
|
@ -81,7 +81,7 @@ export const exportFollows = () => (dispatch: React.Dispatch<ExportDataActions>,
|
|||
});
|
||||
};
|
||||
|
||||
export const exportBlocks = () => (dispatch: React.Dispatch<ExportDataActions>, getState: () => RootState) => {
|
||||
const exportBlocks = () => (dispatch: React.Dispatch<ExportDataActions>, getState: () => RootState) => {
|
||||
dispatch({ type: EXPORT_BLOCKS_REQUEST });
|
||||
return api(getState)
|
||||
.get('/api/v1/blocks?limit=40')
|
||||
|
@ -96,7 +96,7 @@ export const exportBlocks = () => (dispatch: React.Dispatch<ExportDataActions>,
|
|||
});
|
||||
};
|
||||
|
||||
export const exportMutes = () => (dispatch: React.Dispatch<ExportDataActions>, getState: () => RootState) => {
|
||||
const exportMutes = () => (dispatch: React.Dispatch<ExportDataActions>, getState: () => RootState) => {
|
||||
dispatch({ type: EXPORT_MUTES_REQUEST });
|
||||
return api(getState)
|
||||
.get('/api/v1/mutes?limit=40')
|
||||
|
@ -110,3 +110,18 @@ export const exportMutes = () => (dispatch: React.Dispatch<ExportDataActions>, g
|
|||
dispatch({ type: EXPORT_MUTES_FAIL, error });
|
||||
});
|
||||
};
|
||||
|
||||
export {
|
||||
EXPORT_FOLLOWS_REQUEST,
|
||||
EXPORT_FOLLOWS_SUCCESS,
|
||||
EXPORT_FOLLOWS_FAIL,
|
||||
EXPORT_BLOCKS_REQUEST,
|
||||
EXPORT_BLOCKS_SUCCESS,
|
||||
EXPORT_BLOCKS_FAIL,
|
||||
EXPORT_MUTES_REQUEST,
|
||||
EXPORT_MUTES_SUCCESS,
|
||||
EXPORT_MUTES_FAIL,
|
||||
exportFollows,
|
||||
exportBlocks,
|
||||
exportMutes,
|
||||
};
|
||||
|
|
|
@ -22,8 +22,8 @@ import { baseClient } from '../api';
|
|||
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||
import type { Instance } from 'soapbox/types/entities';
|
||||
|
||||
const fetchExternalInstance = (baseURL?: string) => {
|
||||
return baseClient(null, baseURL)
|
||||
const fetchExternalInstance = (baseURL?: string) =>
|
||||
baseClient(null, baseURL)
|
||||
.get('/api/v1/instance')
|
||||
.then(({ data: instance }) => normalizeInstance(instance))
|
||||
.catch(error => {
|
||||
|
@ -35,7 +35,6 @@ const fetchExternalInstance = (baseURL?: string) => {
|
|||
throw error;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const createExternalApp = (instance: Instance, baseURL?: string) =>
|
||||
(dispatch: AppDispatch, _getState: () => RootState) => {
|
||||
|
@ -78,8 +77,8 @@ const externalEthereumLogin = (instance: Instance, baseURL?: string) =>
|
|||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
const loginMessage = instance.login_message;
|
||||
|
||||
return getWalletAndSign(loginMessage).then(({ wallet, signature }) => {
|
||||
return dispatch(createExternalApp(instance, baseURL)).then((app) => {
|
||||
return getWalletAndSign(loginMessage).then(({ wallet, signature }) =>
|
||||
dispatch(createExternalApp(instance, baseURL)).then((app) => {
|
||||
const { client_id, client_secret } = app as Record<string, string>;
|
||||
const params = {
|
||||
grant_type: 'ethereum',
|
||||
|
@ -96,11 +95,11 @@ const externalEthereumLogin = (instance: Instance, baseURL?: string) =>
|
|||
.then(({ access_token }: any) => dispatch(verifyCredentials(access_token, baseURL)))
|
||||
.then((account: { id: string }) => dispatch(switchAccount(account.id)))
|
||||
.then(() => window.location.href = '/');
|
||||
});
|
||||
});
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
export const externalLogin = (host: string) =>
|
||||
const externalLogin = (host: string) =>
|
||||
(dispatch: AppDispatch) => {
|
||||
const baseURL = parseBaseURL(host) || parseBaseURL(`https://${host}`);
|
||||
|
||||
|
@ -116,7 +115,7 @@ export const externalLogin = (host: string) =>
|
|||
});
|
||||
};
|
||||
|
||||
export const loginWithCode = (code: string) =>
|
||||
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')!;
|
||||
|
@ -137,3 +136,5 @@ export const loginWithCode = (code: string) =>
|
|||
.then((account: { id: string }) => dispatch(switchAccount(account.id)))
|
||||
.then(() => window.location.href = '/');
|
||||
};
|
||||
|
||||
export { externalLogin, loginWithCode };
|
||||
|
|
|
@ -6,9 +6,9 @@ import { ACCOUNTS_IMPORT, importFetchedAccounts } from './importer';
|
|||
|
||||
import type { APIEntity } from 'soapbox/types/entities';
|
||||
|
||||
export const FAMILIAR_FOLLOWERS_FETCH_REQUEST = 'FAMILIAR_FOLLOWERS_FETCH_REQUEST';
|
||||
export const FAMILIAR_FOLLOWERS_FETCH_SUCCESS = 'FAMILIAR_FOLLOWERS_FETCH_SUCCESS';
|
||||
export const FAMILIAR_FOLLOWERS_FETCH_FAIL = 'FAMILIAR_FOLLOWERS_FETCH_FAIL';
|
||||
const FAMILIAR_FOLLOWERS_FETCH_REQUEST = 'FAMILIAR_FOLLOWERS_FETCH_REQUEST';
|
||||
const FAMILIAR_FOLLOWERS_FETCH_SUCCESS = 'FAMILIAR_FOLLOWERS_FETCH_SUCCESS';
|
||||
const FAMILIAR_FOLLOWERS_FETCH_FAIL = 'FAMILIAR_FOLLOWERS_FETCH_FAIL';
|
||||
|
||||
type FamiliarFollowersFetchRequestAction = {
|
||||
type: typeof FAMILIAR_FOLLOWERS_FETCH_REQUEST
|
||||
|
@ -34,7 +34,7 @@ type AccountsImportAction = {
|
|||
|
||||
export type FamiliarFollowersActions = FamiliarFollowersFetchRequestAction | FamiliarFollowersFetchRequestSuccessAction | FamiliarFollowersFetchRequestFailAction | AccountsImportAction
|
||||
|
||||
export const fetchAccountFamiliarFollowers = (accountId: string) => (dispatch: React.Dispatch<FamiliarFollowersActions>, getState: () => RootState) => {
|
||||
const fetchAccountFamiliarFollowers = (accountId: string) => (dispatch: React.Dispatch<FamiliarFollowersActions>, getState: () => RootState) => {
|
||||
dispatch({
|
||||
type: FAMILIAR_FOLLOWERS_FETCH_REQUEST,
|
||||
id: accountId,
|
||||
|
@ -57,3 +57,10 @@ export const fetchAccountFamiliarFollowers = (accountId: string) => (dispatch: R
|
|||
error,
|
||||
}));
|
||||
};
|
||||
|
||||
export {
|
||||
FAMILIAR_FOLLOWERS_FETCH_REQUEST,
|
||||
FAMILIAR_FOLLOWERS_FETCH_SUCCESS,
|
||||
FAMILIAR_FOLLOWERS_FETCH_FAIL,
|
||||
fetchAccountFamiliarFollowers,
|
||||
};
|
||||
|
|
|
@ -96,4 +96,4 @@ export {
|
|||
fetchFilters,
|
||||
createFilter,
|
||||
deleteFilter,
|
||||
};
|
||||
};
|
||||
|
|
|
@ -50,4 +50,4 @@ export {
|
|||
fetchHistoryRequest,
|
||||
fetchHistorySuccess,
|
||||
fetchHistoryFail,
|
||||
};
|
||||
};
|
||||
|
|
|
@ -6,17 +6,17 @@ import api from '../api';
|
|||
|
||||
import type { RootState } from 'soapbox/store';
|
||||
|
||||
export const IMPORT_FOLLOWS_REQUEST = 'IMPORT_FOLLOWS_REQUEST';
|
||||
export const IMPORT_FOLLOWS_SUCCESS = 'IMPORT_FOLLOWS_SUCCESS';
|
||||
export const IMPORT_FOLLOWS_FAIL = 'IMPORT_FOLLOWS_FAIL';
|
||||
const IMPORT_FOLLOWS_REQUEST = 'IMPORT_FOLLOWS_REQUEST';
|
||||
const IMPORT_FOLLOWS_SUCCESS = 'IMPORT_FOLLOWS_SUCCESS';
|
||||
const IMPORT_FOLLOWS_FAIL = 'IMPORT_FOLLOWS_FAIL';
|
||||
|
||||
export const IMPORT_BLOCKS_REQUEST = 'IMPORT_BLOCKS_REQUEST';
|
||||
export const IMPORT_BLOCKS_SUCCESS = 'IMPORT_BLOCKS_SUCCESS';
|
||||
export const IMPORT_BLOCKS_FAIL = 'IMPORT_BLOCKS_FAIL';
|
||||
const IMPORT_BLOCKS_REQUEST = 'IMPORT_BLOCKS_REQUEST';
|
||||
const IMPORT_BLOCKS_SUCCESS = 'IMPORT_BLOCKS_SUCCESS';
|
||||
const IMPORT_BLOCKS_FAIL = 'IMPORT_BLOCKS_FAIL';
|
||||
|
||||
export const IMPORT_MUTES_REQUEST = 'IMPORT_MUTES_REQUEST';
|
||||
export const IMPORT_MUTES_SUCCESS = 'IMPORT_MUTES_SUCCESS';
|
||||
export const IMPORT_MUTES_FAIL = 'IMPORT_MUTES_FAIL';
|
||||
const IMPORT_MUTES_REQUEST = 'IMPORT_MUTES_REQUEST';
|
||||
const IMPORT_MUTES_SUCCESS = 'IMPORT_MUTES_SUCCESS';
|
||||
const IMPORT_MUTES_FAIL = 'IMPORT_MUTES_FAIL';
|
||||
|
||||
type ImportDataActions = {
|
||||
type: typeof IMPORT_FOLLOWS_REQUEST
|
||||
|
@ -38,7 +38,7 @@ const messages = defineMessages({
|
|||
mutesSuccess: { id: 'import_data.success.mutes', defaultMessage: 'Mutes imported successfully' },
|
||||
});
|
||||
|
||||
export const importFollows = (params: FormData) =>
|
||||
const importFollows = (params: FormData) =>
|
||||
(dispatch: React.Dispatch<ImportDataActions>, getState: () => RootState) => {
|
||||
dispatch({ type: IMPORT_FOLLOWS_REQUEST });
|
||||
return api(getState)
|
||||
|
@ -51,7 +51,7 @@ export const importFollows = (params: FormData) =>
|
|||
});
|
||||
};
|
||||
|
||||
export const importBlocks = (params: FormData) =>
|
||||
const importBlocks = (params: FormData) =>
|
||||
(dispatch: React.Dispatch<ImportDataActions>, getState: () => RootState) => {
|
||||
dispatch({ type: IMPORT_BLOCKS_REQUEST });
|
||||
return api(getState)
|
||||
|
@ -64,7 +64,7 @@ export const importBlocks = (params: FormData) =>
|
|||
});
|
||||
};
|
||||
|
||||
export const importMutes = (params: FormData) =>
|
||||
const importMutes = (params: FormData) =>
|
||||
(dispatch: React.Dispatch<ImportDataActions>, getState: () => RootState) => {
|
||||
dispatch({ type: IMPORT_MUTES_REQUEST });
|
||||
return api(getState)
|
||||
|
@ -76,3 +76,18 @@ export const importMutes = (params: FormData) =>
|
|||
dispatch({ type: IMPORT_MUTES_FAIL, error });
|
||||
});
|
||||
};
|
||||
|
||||
export {
|
||||
IMPORT_FOLLOWS_REQUEST,
|
||||
IMPORT_FOLLOWS_SUCCESS,
|
||||
IMPORT_FOLLOWS_FAIL,
|
||||
IMPORT_BLOCKS_REQUEST,
|
||||
IMPORT_BLOCKS_SUCCESS,
|
||||
IMPORT_BLOCKS_FAIL,
|
||||
IMPORT_MUTES_REQUEST,
|
||||
IMPORT_MUTES_SUCCESS,
|
||||
IMPORT_MUTES_FAIL,
|
||||
importFollows,
|
||||
importBlocks,
|
||||
importMutes,
|
||||
};
|
||||
|
|
|
@ -145,7 +145,7 @@ const importFetchedStatuses = (statuses: APIEntity[]) =>
|
|||
const normalStatuses: APIEntity[] = [];
|
||||
const polls: APIEntity[] = [];
|
||||
|
||||
function processStatus(status: APIEntity) {
|
||||
const processStatus = (status: APIEntity) => {
|
||||
// Skip broken statuses
|
||||
if (isBroken(status)) return;
|
||||
|
||||
|
@ -172,7 +172,7 @@ const importFetchedStatuses = (statuses: APIEntity[]) =>
|
|||
if (status.group?.id) {
|
||||
dispatch(importFetchedGroup(status.group));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
statuses.forEach(processStatus);
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ const getMeUrl = (state: RootState) => {
|
|||
};
|
||||
|
||||
/** Figure out the appropriate instance to fetch depending on the state */
|
||||
export const getHost = (state: RootState) => {
|
||||
const getHost = (state: RootState) => {
|
||||
const accountUrl = getMeUrl(state) || getAuthUserUrl(state) as string;
|
||||
|
||||
try {
|
||||
|
@ -24,11 +24,9 @@ export const getHost = (state: RootState) => {
|
|||
}
|
||||
};
|
||||
|
||||
export const rememberInstance = createAsyncThunk(
|
||||
const rememberInstance = createAsyncThunk(
|
||||
'instance/remember',
|
||||
async(host: string) => {
|
||||
return await KVStore.getItemOrError(`instance:${host}`);
|
||||
},
|
||||
async(host: string) => await KVStore.getItemOrError(`instance:${host}`),
|
||||
);
|
||||
|
||||
/** We may need to fetch nodeinfo on Pleroma < 2.1 */
|
||||
|
@ -37,7 +35,7 @@ const needsNodeinfo = (instance: Record<string, any>): boolean => {
|
|||
return v.software === 'Pleroma' && !get(instance, ['pleroma', 'metadata']);
|
||||
};
|
||||
|
||||
export const fetchInstance = createAsyncThunk<void, void, { state: RootState }>(
|
||||
const fetchInstance = createAsyncThunk<void, void, { state: RootState }>(
|
||||
'instance/fetch',
|
||||
async(_arg, { dispatch, getState, rejectWithValue }) => {
|
||||
try {
|
||||
|
@ -53,7 +51,7 @@ export const fetchInstance = createAsyncThunk<void, void, { state: RootState }>(
|
|||
);
|
||||
|
||||
/** Tries to remember the instance from browser storage before fetching it */
|
||||
export const loadInstance = createAsyncThunk<void, void, { state: RootState }>(
|
||||
const loadInstance = createAsyncThunk<void, void, { state: RootState }>(
|
||||
'instance/load',
|
||||
async(_arg, { dispatch, getState }) => {
|
||||
const host = getHost(getState());
|
||||
|
@ -64,7 +62,15 @@ export const loadInstance = createAsyncThunk<void, void, { state: RootState }>(
|
|||
},
|
||||
);
|
||||
|
||||
export const fetchNodeinfo = createAsyncThunk<void, void, { state: RootState }>(
|
||||
const fetchNodeinfo = createAsyncThunk<void, void, { state: RootState }>(
|
||||
'nodeinfo/fetch',
|
||||
async(_arg, { getState }) => await api(getState).get('/nodeinfo/2.1.json'),
|
||||
);
|
||||
|
||||
export {
|
||||
getHost,
|
||||
rememberInstance,
|
||||
fetchInstance,
|
||||
loadInstance,
|
||||
fetchNodeinfo,
|
||||
};
|
||||
|
|
|
@ -67,12 +67,12 @@ const messages = defineMessages({
|
|||
});
|
||||
|
||||
const reblog = (status: StatusEntity) =>
|
||||
function(dispatch: AppDispatch, getState: () => RootState) {
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
if (!isLoggedIn(getState)) return;
|
||||
|
||||
dispatch(reblogRequest(status));
|
||||
|
||||
api(getState).post(`/api/v1/statuses/${status.get('id')}/reblog`).then(function(response) {
|
||||
api(getState).post(`/api/v1/statuses/${status.get('id')}/reblog`).then((response) => {
|
||||
// The reblog API method returns a new status wrapped around the original. In this case we are only
|
||||
// interested in how the original is modified, hence passing it skipping the wrapper
|
||||
dispatch(importFetchedStatus(response.data.reblog));
|
||||
|
@ -148,9 +148,9 @@ const favourite = (status: StatusEntity) =>
|
|||
|
||||
dispatch(favouriteRequest(status));
|
||||
|
||||
api(getState).post(`/api/v1/statuses/${status.get('id')}/favourite`).then(function(response) {
|
||||
api(getState).post(`/api/v1/statuses/${status.get('id')}/favourite`).then((response) => {
|
||||
dispatch(favouriteSuccess(status));
|
||||
}).catch(function(error) {
|
||||
}).catch((error) => {
|
||||
dispatch(favouriteFail(status, error));
|
||||
});
|
||||
};
|
||||
|
@ -219,14 +219,14 @@ const bookmark = (status: StatusEntity) =>
|
|||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
dispatch(bookmarkRequest(status));
|
||||
|
||||
api(getState).post(`/api/v1/statuses/${status.get('id')}/bookmark`).then(function(response) {
|
||||
api(getState).post(`/api/v1/statuses/${status.get('id')}/bookmark`).then((response) => {
|
||||
dispatch(importFetchedStatus(response.data));
|
||||
dispatch(bookmarkSuccess(status, response.data));
|
||||
toast.success(messages.bookmarkAdded, {
|
||||
actionLabel: messages.view,
|
||||
actionLink: '/bookmarks',
|
||||
});
|
||||
}).catch(function(error) {
|
||||
}).catch((error) => {
|
||||
dispatch(bookmarkFail(status, error));
|
||||
});
|
||||
};
|
||||
|
|
|
@ -7,14 +7,10 @@ import type { AppDispatch, RootState } from 'soapbox/store';
|
|||
const noOp = (e: any) => {};
|
||||
|
||||
const fetchMedia = (mediaId: string) =>
|
||||
(dispatch: any, getState: () => RootState) => {
|
||||
return api(getState).get(`/api/v1/media/${mediaId}`);
|
||||
};
|
||||
(dispatch: any, getState: () => RootState) => api(getState).get(`/api/v1/media/${mediaId}`);
|
||||
|
||||
const updateMedia = (mediaId: string, params: Record<string, any>) =>
|
||||
(dispatch: any, getState: () => RootState) => {
|
||||
return api(getState).put(`/api/v1/media/${mediaId}`, params);
|
||||
};
|
||||
(dispatch: any, getState: () => RootState) => api(getState).put(`/api/v1/media/${mediaId}`, params);
|
||||
|
||||
const uploadMediaV1 = (data: FormData, onUploadProgress = noOp) =>
|
||||
(dispatch: any, getState: () => RootState) =>
|
||||
|
|
|
@ -1,21 +1,24 @@
|
|||
import type { ModalType } from 'soapbox/features/ui/components/modal-root';
|
||||
|
||||
export const MODAL_OPEN = 'MODAL_OPEN';
|
||||
export const MODAL_CLOSE = 'MODAL_CLOSE';
|
||||
const MODAL_OPEN = 'MODAL_OPEN';
|
||||
const MODAL_CLOSE = 'MODAL_CLOSE';
|
||||
|
||||
/** Open a modal of the given type */
|
||||
export function openModal(type: ModalType, props?: any) {
|
||||
return {
|
||||
type: MODAL_OPEN,
|
||||
modalType: type,
|
||||
modalProps: props,
|
||||
};
|
||||
}
|
||||
const openModal = (type: ModalType, props?: any) => ({
|
||||
type: MODAL_OPEN,
|
||||
modalType: type,
|
||||
modalProps: props,
|
||||
});
|
||||
|
||||
/** Close the modal */
|
||||
export function closeModal(type?: ModalType) {
|
||||
return {
|
||||
type: MODAL_CLOSE,
|
||||
modalType: type,
|
||||
};
|
||||
}
|
||||
const closeModal = (type?: ModalType) => ({
|
||||
type: MODAL_CLOSE,
|
||||
modalType: type,
|
||||
});
|
||||
|
||||
export {
|
||||
MODAL_OPEN,
|
||||
MODAL_CLOSE,
|
||||
openModal,
|
||||
closeModal,
|
||||
};
|
||||
|
|
|
@ -7,8 +7,8 @@ import { fetchConfig, updateConfig } from './admin';
|
|||
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||
import type { Policy } from 'soapbox/utils/config-db';
|
||||
|
||||
const simplePolicyMerge = (simplePolicy: Policy, host: string, restrictions: ImmutableMap<string, any>) => {
|
||||
return simplePolicy.map((hosts, key) => {
|
||||
const simplePolicyMerge = (simplePolicy: Policy, host: string, restrictions: ImmutableMap<string, any>) =>
|
||||
simplePolicy.map((hosts, key) => {
|
||||
const isRestricted = restrictions.get(key);
|
||||
|
||||
if (isRestricted) {
|
||||
|
@ -17,7 +17,6 @@ const simplePolicyMerge = (simplePolicy: Policy, host: string, restrictions: Imm
|
|||
return ImmutableSet(hosts).delete(host);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const updateMrf = (host: string, restrictions: ImmutableMap<string, any>) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) =>
|
||||
|
|
|
@ -169,9 +169,7 @@ const dequeueNotifications = () =>
|
|||
dispatch(markReadNotifications());
|
||||
};
|
||||
|
||||
const excludeTypesFromFilter = (filter: string) => {
|
||||
return NOTIFICATION_TYPES.filter(item => item !== filter);
|
||||
};
|
||||
const excludeTypesFromFilter = (filter: string) => NOTIFICATION_TYPES.filter(item => item !== filter);
|
||||
|
||||
const noOp = () => new Promise(f => f(undefined));
|
||||
|
||||
|
@ -298,9 +296,8 @@ const setFilter = (filterType: string) =>
|
|||
// Of course Markers don't work properly in Pleroma.
|
||||
// https://git.pleroma.social/pleroma/pleroma/-/issues/2769
|
||||
const markReadPleroma = (max_id: string | number) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
return api(getState).post('/api/v1/pleroma/notifications/read', { max_id });
|
||||
};
|
||||
(dispatch: AppDispatch, getState: () => RootState) =>
|
||||
api(getState).post('/api/v1/pleroma/notifications/read', { max_id });
|
||||
|
||||
const markReadNotifications = () =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
|
|
|
@ -10,15 +10,15 @@ 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';
|
||||
const OAUTH_TOKEN_CREATE_REQUEST = 'OAUTH_TOKEN_CREATE_REQUEST';
|
||||
const OAUTH_TOKEN_CREATE_SUCCESS = 'OAUTH_TOKEN_CREATE_SUCCESS';
|
||||
const OAUTH_TOKEN_CREATE_FAIL = 'OAUTH_TOKEN_CREATE_FAIL';
|
||||
|
||||
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';
|
||||
const OAUTH_TOKEN_REVOKE_REQUEST = 'OAUTH_TOKEN_REVOKE_REQUEST';
|
||||
const OAUTH_TOKEN_REVOKE_SUCCESS = 'OAUTH_TOKEN_REVOKE_SUCCESS';
|
||||
const OAUTH_TOKEN_REVOKE_FAIL = 'OAUTH_TOKEN_REVOKE_FAIL';
|
||||
|
||||
export const obtainOAuthToken = (params: Record<string, string | undefined>, baseURL?: string) =>
|
||||
const obtainOAuthToken = (params: Record<string, string | undefined>, baseURL?: string) =>
|
||||
(dispatch: AppDispatch) => {
|
||||
dispatch({ type: OAUTH_TOKEN_CREATE_REQUEST, params });
|
||||
return baseClient(null, baseURL).post('/oauth/token', params).then(({ data: token }) => {
|
||||
|
@ -30,7 +30,7 @@ export const obtainOAuthToken = (params: Record<string, string | undefined>, bas
|
|||
});
|
||||
};
|
||||
|
||||
export const revokeOAuthToken = (params: Record<string, string>) =>
|
||||
const revokeOAuthToken = (params: Record<string, string>) =>
|
||||
(dispatch: AppDispatch) => {
|
||||
dispatch({ type: OAUTH_TOKEN_REVOKE_REQUEST, params });
|
||||
return baseClient().post('/oauth/revoke', params).then(({ data }) => {
|
||||
|
@ -41,3 +41,14 @@ export const revokeOAuthToken = (params: Record<string, string>) =>
|
|||
throw error;
|
||||
});
|
||||
};
|
||||
|
||||
export {
|
||||
OAUTH_TOKEN_CREATE_REQUEST,
|
||||
OAUTH_TOKEN_CREATE_SUCCESS,
|
||||
OAUTH_TOKEN_CREATE_FAIL,
|
||||
OAUTH_TOKEN_REVOKE_REQUEST,
|
||||
OAUTH_TOKEN_REVOKE_SUCCESS,
|
||||
OAUTH_TOKEN_REVOKE_FAIL,
|
||||
obtainOAuthToken,
|
||||
revokeOAuthToken,
|
||||
};
|
||||
|
|
|
@ -16,9 +16,8 @@ const decodeUTF8Base64 = (data: string) => {
|
|||
return text;
|
||||
};
|
||||
|
||||
const decodePleromaData = (data: Record<string, any>) => {
|
||||
return mapValues(data, base64string => JSON.parse(decodeUTF8Base64(base64string)));
|
||||
};
|
||||
const decodePleromaData = (data: Record<string, any>) =>
|
||||
mapValues(data, base64string => JSON.parse(decodeUTF8Base64(base64string)));
|
||||
|
||||
const pleromaDecoder = (json: string) => decodePleromaData(JSON.parse(json));
|
||||
|
||||
|
|
|
@ -97,9 +97,9 @@ const register = () =>
|
|||
return { subscription };
|
||||
} else {
|
||||
// Something went wrong, try to subscribe again
|
||||
return unsubscribe({ registration, subscription }).then((registration: ServiceWorkerRegistration) => {
|
||||
return subscribe(registration, getState);
|
||||
}).then(
|
||||
return unsubscribe({ registration, subscription }).then((registration: ServiceWorkerRegistration) =>
|
||||
subscribe(registration, getState),
|
||||
).then(
|
||||
(subscription: PushSubscription) => dispatch(sendSubscriptionToBackend(subscription, me) as any));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -173,14 +173,15 @@ const defaultSettings = ImmutableMap({
|
|||
}),
|
||||
});
|
||||
|
||||
const getSettings = createSelector([
|
||||
(state: RootState) => state.soapbox.get('defaultSettings'),
|
||||
(state: RootState) => state.settings,
|
||||
], (soapboxSettings, settings) => {
|
||||
return defaultSettings
|
||||
const getSettings = createSelector(
|
||||
[
|
||||
(state: RootState) => state.soapbox.get('defaultSettings'),
|
||||
(state: RootState) => state.settings,
|
||||
],
|
||||
(soapboxSettings, settings) => defaultSettings
|
||||
.mergeDeep(soapboxSettings)
|
||||
.mergeDeep(settings);
|
||||
});
|
||||
.mergeDeep(settings),
|
||||
);
|
||||
|
||||
const changeSettingImmediate = (path: string[], value: any, opts?: SettingOpts) =>
|
||||
(dispatch: AppDispatch) => {
|
||||
|
|
|
@ -22,9 +22,9 @@ const SOAPBOX_CONFIG_REMEMBER_FAIL = 'SOAPBOX_CONFIG_REMEMBER_FAIL';
|
|||
const getSoapboxConfig = createSelector([
|
||||
(state: RootState) => state.soapbox,
|
||||
(state: RootState) => getFeatures(state.instance),
|
||||
], (soapbox, features) => {
|
||||
], (soapbox, features) =>
|
||||
// Do some additional normalization with the state
|
||||
return normalizeSoapboxConfig(soapbox).withMutations(soapboxConfig => {
|
||||
normalizeSoapboxConfig(soapbox).withMutations(soapboxConfig => {
|
||||
|
||||
// If displayFqn isn't set, infer it from federation
|
||||
if (soapbox.get('displayFqn') === undefined) {
|
||||
|
@ -36,8 +36,8 @@ const getSoapboxConfig = createSelector([
|
|||
if (features.emojiReactsNonRGI) {
|
||||
soapboxConfig.set('allowedEmoji', soapboxConfig.allowedEmoji.map(removeVS16s));
|
||||
}
|
||||
});
|
||||
});
|
||||
}),
|
||||
);
|
||||
|
||||
const rememberSoapboxConfig = (host: string | null) =>
|
||||
(dispatch: AppDispatch) => {
|
||||
|
|
|
@ -4,17 +4,17 @@ import { importFetchedStatuses } from './importer';
|
|||
|
||||
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||
|
||||
export const STATUS_QUOTES_FETCH_REQUEST = 'STATUS_QUOTES_FETCH_REQUEST';
|
||||
export const STATUS_QUOTES_FETCH_SUCCESS = 'STATUS_QUOTES_FETCH_SUCCESS';
|
||||
export const STATUS_QUOTES_FETCH_FAIL = 'STATUS_QUOTES_FETCH_FAIL';
|
||||
const STATUS_QUOTES_FETCH_REQUEST = 'STATUS_QUOTES_FETCH_REQUEST';
|
||||
const STATUS_QUOTES_FETCH_SUCCESS = 'STATUS_QUOTES_FETCH_SUCCESS';
|
||||
const STATUS_QUOTES_FETCH_FAIL = 'STATUS_QUOTES_FETCH_FAIL';
|
||||
|
||||
export const STATUS_QUOTES_EXPAND_REQUEST = 'STATUS_QUOTES_EXPAND_REQUEST';
|
||||
export const STATUS_QUOTES_EXPAND_SUCCESS = 'STATUS_QUOTES_EXPAND_SUCCESS';
|
||||
export const STATUS_QUOTES_EXPAND_FAIL = 'STATUS_QUOTES_EXPAND_FAIL';
|
||||
const STATUS_QUOTES_EXPAND_REQUEST = 'STATUS_QUOTES_EXPAND_REQUEST';
|
||||
const STATUS_QUOTES_EXPAND_SUCCESS = 'STATUS_QUOTES_EXPAND_SUCCESS';
|
||||
const STATUS_QUOTES_EXPAND_FAIL = 'STATUS_QUOTES_EXPAND_FAIL';
|
||||
|
||||
const noOp = () => new Promise(f => f(null));
|
||||
|
||||
export const fetchStatusQuotes = (statusId: string) =>
|
||||
const fetchStatusQuotes = (statusId: string) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
if (getState().status_lists.getIn([`quotes:${statusId}`, 'isLoading'])) {
|
||||
return dispatch(noOp);
|
||||
|
@ -43,7 +43,7 @@ export const fetchStatusQuotes = (statusId: string) =>
|
|||
});
|
||||
};
|
||||
|
||||
export const expandStatusQuotes = (statusId: string) =>
|
||||
const expandStatusQuotes = (statusId: string) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
const url = getState().status_lists.getIn([`quotes:${statusId}`, 'next'], null) as string | null;
|
||||
|
||||
|
@ -73,3 +73,14 @@ export const expandStatusQuotes = (statusId: string) =>
|
|||
});
|
||||
});
|
||||
};
|
||||
|
||||
export {
|
||||
STATUS_QUOTES_FETCH_REQUEST,
|
||||
STATUS_QUOTES_FETCH_SUCCESS,
|
||||
STATUS_QUOTES_FETCH_FAIL,
|
||||
STATUS_QUOTES_EXPAND_REQUEST,
|
||||
STATUS_QUOTES_EXPAND_SUCCESS,
|
||||
STATUS_QUOTES_EXPAND_FAIL,
|
||||
fetchStatusQuotes,
|
||||
expandStatusQuotes,
|
||||
};
|
||||
|
|
|
@ -48,12 +48,11 @@ const STATUS_TRANSLATE_SUCCESS = 'STATUS_TRANSLATE_SUCCESS';
|
|||
const STATUS_TRANSLATE_FAIL = 'STATUS_TRANSLATE_FAIL';
|
||||
const STATUS_TRANSLATE_UNDO = 'STATUS_TRANSLATE_UNDO';
|
||||
|
||||
const statusExists = (getState: () => RootState, statusId: string) => {
|
||||
return (getState().statuses.get(statusId) || null) !== null;
|
||||
};
|
||||
const statusExists = (getState: () => RootState, statusId: string) =>
|
||||
(getState().statuses.get(statusId) || null) !== null;
|
||||
|
||||
const createStatus = (params: Record<string, any>, idempotencyKey: string, statusId: string | null) => {
|
||||
return (dispatch: AppDispatch, getState: () => RootState) => {
|
||||
const createStatus = (params: Record<string, any>, idempotencyKey: string, statusId: string | null) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
dispatch({ type: STATUS_CREATE_REQUEST, params, idempotencyKey, editing: !!statusId });
|
||||
|
||||
return api(getState).request({
|
||||
|
@ -93,7 +92,6 @@ const createStatus = (params: Record<string, any>, idempotencyKey: string, statu
|
|||
throw error;
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
const editStatus = (id: string) => (dispatch: AppDispatch, getState: () => RootState) => {
|
||||
let status = getState().statuses.get(id)!;
|
||||
|
@ -114,8 +112,8 @@ const editStatus = (id: string) => (dispatch: AppDispatch, getState: () => RootS
|
|||
});
|
||||
};
|
||||
|
||||
const fetchStatus = (id: string) => {
|
||||
return (dispatch: AppDispatch, getState: () => RootState) => {
|
||||
const fetchStatus = (id: string) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
const skipLoading = statusExists(getState, id);
|
||||
|
||||
dispatch({ type: STATUS_FETCH_REQUEST, id, skipLoading });
|
||||
|
@ -128,10 +126,9 @@ const fetchStatus = (id: string) => {
|
|||
dispatch({ type: STATUS_FETCH_FAIL, id, error, skipLoading, skipAlert: true });
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
const deleteStatus = (id: string, withRedraft = false) => {
|
||||
return (dispatch: AppDispatch, getState: () => RootState) => {
|
||||
const deleteStatus = (id: string, withRedraft = false) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
if (!isLoggedIn(getState)) return null;
|
||||
|
||||
let status = getState().statuses.get(id)!;
|
||||
|
@ -157,7 +154,6 @@ const deleteStatus = (id: string, withRedraft = false) => {
|
|||
dispatch({ type: STATUS_DELETE_FAIL, params: status, error });
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
const updateStatus = (status: APIEntity) => (dispatch: AppDispatch) =>
|
||||
dispatch(importFetchedStatus(status));
|
||||
|
|
|
@ -132,11 +132,8 @@ const clearTimeline = (timeline: string) =>
|
|||
const noOp = () => { };
|
||||
const noOpAsync = () => () => new Promise(f => f(undefined));
|
||||
|
||||
const parseTags = (tags: Record<string, any[]> = {}, mode: 'any' | 'all' | 'none') => {
|
||||
return (tags[mode] || []).map((tag) => {
|
||||
return tag.value;
|
||||
});
|
||||
};
|
||||
const parseTags = (tags: Record<string, any[]> = {}, mode: 'any' | 'all' | 'none') =>
|
||||
(tags[mode] || []).map((tag) => tag.value);
|
||||
|
||||
const replaceHomeTimeline = (
|
||||
accountId: string | null,
|
||||
|
@ -222,14 +219,13 @@ const expandGroupTimeline = (id: string, { maxId }: Record<string, any> = {}, do
|
|||
const expandGroupMediaTimeline = (id: string | number, { maxId }: Record<string, any> = {}) =>
|
||||
expandTimeline(`group:${id}:media`, `/api/v1/timelines/group/${id}`, { max_id: maxId, only_media: true, limit: 40, with_muted: true });
|
||||
|
||||
const expandHashtagTimeline = (hashtag: string, { maxId, tags }: Record<string, any> = {}, done = noOp) => {
|
||||
return expandTimeline(`hashtag:${hashtag}`, `/api/v1/timelines/tag/${hashtag}`, {
|
||||
const expandHashtagTimeline = (hashtag: string, { maxId, tags }: Record<string, any> = {}, done = noOp) =>
|
||||
expandTimeline(`hashtag:${hashtag}`, `/api/v1/timelines/tag/${hashtag}`, {
|
||||
max_id: maxId,
|
||||
any: parseTags(tags, 'any'),
|
||||
all: parseTags(tags, 'all'),
|
||||
none: parseTags(tags, 'none'),
|
||||
}, done);
|
||||
};
|
||||
|
||||
const expandTimelineRequest = (timeline: string, isLoadingMore: boolean) => ({
|
||||
type: TIMELINE_EXPAND_REQUEST,
|
||||
|
|
|
@ -130,7 +130,7 @@ const fetchVerificationConfig = () =>
|
|||
* - Don't overwrite a challenge that has already been completed.
|
||||
* - Update localStorage to the new set of challenges.
|
||||
*/
|
||||
function saveChallenges(challenges: Array<'age' | 'sms' | 'email'>) {
|
||||
const saveChallenges = (challenges: Array<'age' | 'sms' | 'email'>) => {
|
||||
const currentChallenges: Challenges = fetchStoredChallenges() || {};
|
||||
|
||||
const challengesToRemove = Object.keys(currentChallenges).filter((currentChallenge) => !challenges.includes(currentChallenge as Challenge)) as Challenge[];
|
||||
|
@ -148,18 +148,18 @@ function saveChallenges(challenges: Array<'age' | 'sms' | 'email'>) {
|
|||
challenges: currentChallenges,
|
||||
challengeTypes: challenges,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Finish a challenge.
|
||||
*/
|
||||
function finishChallenge(challenge: Challenge) {
|
||||
const finishChallenge = (challenge: Challenge) => {
|
||||
const currentChallenges: Challenges = fetchStoredChallenges() || {};
|
||||
// Set challenge to "complete"
|
||||
currentChallenges[challenge] = 1;
|
||||
|
||||
updateStorage({ challenges: currentChallenges });
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Fetch the next challenge
|
||||
|
|
|
@ -17,9 +17,8 @@ const setupMock = (axios: AxiosInstance) => {
|
|||
|
||||
export const staticClient = api.staticClient;
|
||||
|
||||
export const getLinks = (response: AxiosResponse): LinkHeader => {
|
||||
return new LinkHeader(response.headers?.link);
|
||||
};
|
||||
export const getLinks = (response: AxiosResponse): LinkHeader =>
|
||||
new LinkHeader(response.headers?.link);
|
||||
|
||||
export const getNextLink = (response: AxiosResponse) => {
|
||||
const nextLink = new LinkHeader(response.headers?.link);
|
||||
|
|
|
@ -21,17 +21,14 @@ import type MockAdapter from 'axios-mock-adapter';
|
|||
@param {object} response - Axios response object
|
||||
@returns {object} Link object
|
||||
*/
|
||||
export const getLinks = (response: AxiosResponse): LinkHeader => {
|
||||
return new LinkHeader(response.headers?.link);
|
||||
};
|
||||
export const getLinks = (response: AxiosResponse): LinkHeader =>
|
||||
new LinkHeader(response.headers?.link);
|
||||
|
||||
export const getNextLink = (response: AxiosResponse): string | undefined => {
|
||||
return getLinks(response).refs.find(link => link.rel === 'next')?.uri;
|
||||
};
|
||||
export const getNextLink = (response: AxiosResponse): string | undefined =>
|
||||
getLinks(response).refs.find(link => link.rel === 'next')?.uri;
|
||||
|
||||
const getToken = (state: RootState, authType: string) => {
|
||||
return authType === 'app' ? getAppToken(state) : getAccessToken(state);
|
||||
};
|
||||
const getToken = (state: RootState, authType: string) =>
|
||||
authType === 'app' ? getAppToken(state) : getAccessToken(state);
|
||||
|
||||
const maybeParseJSON = (data: string) => {
|
||||
try {
|
||||
|
@ -55,8 +52,8 @@ const getAuthBaseURL = createSelector([
|
|||
* @param {string} baseURL
|
||||
* @returns {object} Axios instance
|
||||
*/
|
||||
export const baseClient = (accessToken?: string | null, baseURL: string = ''): AxiosInstance => {
|
||||
return axios.create({
|
||||
export const baseClient = (accessToken?: string | null, baseURL: string = ''): AxiosInstance =>
|
||||
axios.create({
|
||||
// When BACKEND_URL is set, always use it.
|
||||
baseURL: isURL(BuildConfig.BACKEND_URL) ? BuildConfig.BACKEND_URL : baseURL,
|
||||
headers: Object.assign(accessToken ? {
|
||||
|
@ -64,7 +61,6 @@ export const baseClient = (accessToken?: string | null, baseURL: string = ''): A
|
|||
} : {}),
|
||||
transformResponse: [maybeParseJSON],
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Dumb client for grabbing static files.
|
||||
|
|
|
@ -24,13 +24,9 @@ const sanitizeURL = url => {
|
|||
}
|
||||
};
|
||||
|
||||
const sanitizeBasename = path => {
|
||||
return `/${trim(path, '/')}`;
|
||||
};
|
||||
const sanitizeBasename = path => `/${trim(path, '/')}`;
|
||||
|
||||
const sanitizePath = path => {
|
||||
return trim(path, '/');
|
||||
};
|
||||
const sanitizePath = path => trim(path, '/');
|
||||
|
||||
// JSON.parse/stringify is to emulate what @preval is doing and avoid any
|
||||
// inconsistent behavior in dev mode
|
||||
|
|
|
@ -23,9 +23,7 @@ const AccountSearch: React.FC<IAccountSearch> = ({ onSelected, ...rest }) => {
|
|||
|
||||
const [value, setValue] = useState('');
|
||||
|
||||
const isEmpty = (): boolean => {
|
||||
return !(value.length > 0);
|
||||
};
|
||||
const isEmpty = (): boolean => !(value.length > 0);
|
||||
|
||||
const clearState = () => {
|
||||
setValue('');
|
||||
|
|
|
@ -58,13 +58,11 @@ interface IProfilePopper {
|
|||
children: React.ReactNode
|
||||
}
|
||||
|
||||
const ProfilePopper: React.FC<IProfilePopper> = ({ condition, wrapper, children }) => {
|
||||
return (
|
||||
<>
|
||||
{condition ? wrapper(children) : children}
|
||||
</>
|
||||
);
|
||||
};
|
||||
const ProfilePopper: React.FC<IProfilePopper> = ({ condition, wrapper, children }) => (
|
||||
<>
|
||||
{condition ? wrapper(children) : children}
|
||||
</>
|
||||
);
|
||||
|
||||
export interface IAccount {
|
||||
account: AccountEntity
|
||||
|
|
|
@ -60,4 +60,4 @@ const AnimatedNumber: React.FC<IAnimatedNumber> = ({ value, obfuscate }) => {
|
|||
);
|
||||
};
|
||||
|
||||
export default AnimatedNumber;
|
||||
export default AnimatedNumber;
|
||||
|
|
|
@ -43,9 +43,7 @@ export default class AutosuggestInput extends ImmutablePureComponent<IAutosugges
|
|||
searchTokens: ImmutableList(['@', ':', '#']),
|
||||
};
|
||||
|
||||
getFirstIndex = () => {
|
||||
return this.props.autoSelect ? 0 : -1;
|
||||
};
|
||||
getFirstIndex = () => this.props.autoSelect ? 0 : -1;
|
||||
|
||||
state = {
|
||||
suggestionsHidden: true,
|
||||
|
@ -217,11 +215,9 @@ export default class AutosuggestInput extends ImmutablePureComponent<IAutosugges
|
|||
}
|
||||
};
|
||||
|
||||
handleMenuItemClick = (item: MenuItem | null): React.MouseEventHandler => {
|
||||
return e => {
|
||||
e.preventDefault();
|
||||
this.handleMenuItemAction(item, e);
|
||||
};
|
||||
handleMenuItemClick = (item: MenuItem | null): React.MouseEventHandler => e => {
|
||||
e.preventDefault();
|
||||
this.handleMenuItemAction(item, e);
|
||||
};
|
||||
|
||||
renderMenu = () => {
|
||||
|
|
|
@ -65,50 +65,48 @@ const BirthdayInput: React.FC<IBirthdayInput> = ({ value, onChange, required })
|
|||
prevYearButtonDisabled: boolean
|
||||
nextYearButtonDisabled: boolean
|
||||
date: Date
|
||||
}) => {
|
||||
return (
|
||||
<div className='flex flex-col gap-2'>
|
||||
<div className='flex items-center justify-between'>
|
||||
<IconButton
|
||||
className='datepicker__button rtl:rotate-180'
|
||||
src={require('@tabler/icons/chevron-left.svg')}
|
||||
onClick={decreaseMonth}
|
||||
disabled={prevMonthButtonDisabled}
|
||||
aria-label={intl.formatMessage(messages.previousMonth)}
|
||||
title={intl.formatMessage(messages.previousMonth)}
|
||||
/>
|
||||
{intl.formatDate(date, { month: 'long' })}
|
||||
<IconButton
|
||||
className='datepicker__button rtl:rotate-180'
|
||||
src={require('@tabler/icons/chevron-right.svg')}
|
||||
onClick={increaseMonth}
|
||||
disabled={nextMonthButtonDisabled}
|
||||
aria-label={intl.formatMessage(messages.nextMonth)}
|
||||
title={intl.formatMessage(messages.nextMonth)}
|
||||
/>
|
||||
</div>
|
||||
<div className='flex items-center justify-between'>
|
||||
<IconButton
|
||||
className='datepicker__button rtl:rotate-180'
|
||||
src={require('@tabler/icons/chevron-left.svg')}
|
||||
onClick={decreaseYear}
|
||||
disabled={prevYearButtonDisabled}
|
||||
aria-label={intl.formatMessage(messages.previousYear)}
|
||||
title={intl.formatMessage(messages.previousYear)}
|
||||
/>
|
||||
{intl.formatDate(date, { year: 'numeric' })}
|
||||
<IconButton
|
||||
className='datepicker__button rtl:rotate-180'
|
||||
src={require('@tabler/icons/chevron-right.svg')}
|
||||
onClick={increaseYear}
|
||||
disabled={nextYearButtonDisabled}
|
||||
aria-label={intl.formatMessage(messages.nextYear)}
|
||||
title={intl.formatMessage(messages.nextYear)}
|
||||
/>
|
||||
</div>
|
||||
}) => (
|
||||
<div className='flex flex-col gap-2'>
|
||||
<div className='flex items-center justify-between'>
|
||||
<IconButton
|
||||
className='datepicker__button rtl:rotate-180'
|
||||
src={require('@tabler/icons/chevron-left.svg')}
|
||||
onClick={decreaseMonth}
|
||||
disabled={prevMonthButtonDisabled}
|
||||
aria-label={intl.formatMessage(messages.previousMonth)}
|
||||
title={intl.formatMessage(messages.previousMonth)}
|
||||
/>
|
||||
{intl.formatDate(date, { month: 'long' })}
|
||||
<IconButton
|
||||
className='datepicker__button rtl:rotate-180'
|
||||
src={require('@tabler/icons/chevron-right.svg')}
|
||||
onClick={increaseMonth}
|
||||
disabled={nextMonthButtonDisabled}
|
||||
aria-label={intl.formatMessage(messages.nextMonth)}
|
||||
title={intl.formatMessage(messages.nextMonth)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
<div className='flex items-center justify-between'>
|
||||
<IconButton
|
||||
className='datepicker__button rtl:rotate-180'
|
||||
src={require('@tabler/icons/chevron-left.svg')}
|
||||
onClick={decreaseYear}
|
||||
disabled={prevYearButtonDisabled}
|
||||
aria-label={intl.formatMessage(messages.previousYear)}
|
||||
title={intl.formatMessage(messages.previousYear)}
|
||||
/>
|
||||
{intl.formatDate(date, { year: 'numeric' })}
|
||||
<IconButton
|
||||
className='datepicker__button rtl:rotate-180'
|
||||
src={require('@tabler/icons/chevron-right.svg')}
|
||||
onClick={increaseYear}
|
||||
disabled={nextYearButtonDisabled}
|
||||
aria-label={intl.formatMessage(messages.nextYear)}
|
||||
title={intl.formatMessage(messages.nextYear)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
const handleChange = (date: Date) => onChange(date ? new Date(date.getTime() - (date.getTimezoneOffset() * 60000)).toISOString().slice(0, 10) : '');
|
||||
|
||||
|
|
|
@ -106,4 +106,4 @@ const DropdownMenuItem = ({ index, item, onClick }: IDropdownMenuItem) => {
|
|||
);
|
||||
};
|
||||
|
||||
export default DropdownMenuItem;
|
||||
export default DropdownMenuItem;
|
||||
|
|
|
@ -253,10 +253,8 @@ const DropdownMenu = (props: IDropdownMenu) => {
|
|||
return {};
|
||||
}, [middlewareData.arrow, placement]);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
closeDropdownMenu();
|
||||
};
|
||||
useEffect(() => () => {
|
||||
closeDropdownMenu();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -339,4 +337,4 @@ const DropdownMenu = (props: IDropdownMenu) => {
|
|||
);
|
||||
};
|
||||
|
||||
export default DropdownMenu;
|
||||
export default DropdownMenu;
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
export { default } from './dropdown-menu';
|
||||
export type { Menu } from './dropdown-menu';
|
||||
export type { MenuItem } from './dropdown-menu-item';
|
||||
export type { MenuItem } from './dropdown-menu-item';
|
||||
|
|
|
@ -14,21 +14,18 @@ export interface IForkAwesomeIcon extends React.HTMLAttributes<HTMLLIElement> {
|
|||
fixedWidth?: boolean
|
||||
}
|
||||
|
||||
const ForkAwesomeIcon: React.FC<IForkAwesomeIcon> = ({ id, className, fixedWidth, ...rest }) => {
|
||||
// Use the Fork Awesome retweet icon, but change its alt
|
||||
// tag. There is a common adblocker rule which hides elements with
|
||||
// alt='retweet' unless the domain is twitter.com. This should
|
||||
// change what screenreaders call it as well.
|
||||
// const alt = (id === 'retweet') ? 'repost' : id;
|
||||
|
||||
return (
|
||||
<i
|
||||
role='img'
|
||||
// alt={alt}
|
||||
className={clsx('fa', `fa-${id}`, className, { 'fa-fw': fixedWidth })}
|
||||
{...rest}
|
||||
/>
|
||||
);
|
||||
};
|
||||
const ForkAwesomeIcon: React.FC<IForkAwesomeIcon> = ({ id, className, fixedWidth, ...rest }) => (
|
||||
// Use the Fork Awesome retweet icon, but change its alt
|
||||
// tag. There is a common adblocker rule which hides elements with
|
||||
// alt='retweet' unless the domain is twitter.com. This should
|
||||
// change what screenreaders call it as well.
|
||||
// const alt = (id === 'retweet') ? 'repost' : id;
|
||||
<i
|
||||
role='img'
|
||||
// alt={alt}
|
||||
className={clsx('fa', `fa-${id}`, className, { 'fa-fw': fixedWidth })}
|
||||
{...rest}
|
||||
/>
|
||||
);
|
||||
|
||||
export default ForkAwesomeIcon;
|
||||
|
|
|
@ -27,9 +27,7 @@ const Helmet: React.FC<IHelmet> = ({ children }) => {
|
|||
|
||||
const hasUnreadNotifications = React.useMemo(() => !(unreadCount < 1 || demetricator), [unreadCount, demetricator]);
|
||||
|
||||
const addCounter = (string: string) => {
|
||||
return hasUnreadNotifications ? `(${unreadCount}) ${string}` : string;
|
||||
};
|
||||
const addCounter = (string: string) => hasUnreadNotifications ? `(${unreadCount}) ${string}` : string;
|
||||
|
||||
const updateFaviconBadge = () => {
|
||||
if (hasUnreadNotifications) {
|
||||
|
|
|
@ -10,18 +10,16 @@ interface IIconWithCounter extends React.HTMLAttributes<HTMLDivElement> {
|
|||
src?: string
|
||||
}
|
||||
|
||||
const IconWithCounter: React.FC<IIconWithCounter> = ({ icon, count, countMax, ...rest }) => {
|
||||
return (
|
||||
<div className='relative'>
|
||||
<Icon id={icon} {...rest as IIcon} />
|
||||
const IconWithCounter: React.FC<IIconWithCounter> = ({ icon, count, countMax, ...rest }) => (
|
||||
<div className='relative'>
|
||||
<Icon id={icon} {...rest as IIcon} />
|
||||
|
||||
{count > 0 && (
|
||||
<span className='absolute -top-2 -right-3'>
|
||||
<Counter count={count} countMax={countMax} />
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
{count > 0 && (
|
||||
<span className='absolute -top-2 -right-3'>
|
||||
<Counter count={count} countMax={countMax} />
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
export default IconWithCounter;
|
||||
|
|
|
@ -14,15 +14,13 @@ export interface IIcon extends React.HTMLAttributes<HTMLDivElement> {
|
|||
className?: string
|
||||
}
|
||||
|
||||
const Icon: React.FC<IIcon> = ({ src, alt, className, ...rest }) => {
|
||||
return (
|
||||
<div
|
||||
className={clsx('svg-icon', className)}
|
||||
{...rest}
|
||||
>
|
||||
<InlineSVG src={src} title={alt} loader={<></>} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
const Icon: React.FC<IIcon> = ({ src, alt, className, ...rest }) => (
|
||||
<div
|
||||
className={clsx('svg-icon', className)}
|
||||
{...rest}
|
||||
>
|
||||
<InlineSVG src={src} title={alt} loader={<></>} />
|
||||
</div>
|
||||
);
|
||||
|
||||
export default Icon;
|
||||
|
|
|
@ -8,4 +8,4 @@ const Link = (props: LinkProps) => (
|
|||
/>
|
||||
);
|
||||
|
||||
export default Link;
|
||||
export default Link;
|
||||
|
|
|
@ -38,22 +38,20 @@ const ListItem: React.FC<IListItem> = ({ label, hint, children, onClick, onSelec
|
|||
const LabelComp = onClick || onSelect ? 'span' : 'label';
|
||||
const linkProps = onClick || onSelect ? { onClick: onClick || onSelect, onKeyDown, tabIndex: 0, role: 'link' } : {};
|
||||
|
||||
const renderChildren = React.useCallback(() => {
|
||||
return React.Children.map(children, (child) => {
|
||||
if (React.isValidElement(child)) {
|
||||
const isSelect = child.type === SelectDropdown || child.type === Select;
|
||||
const renderChildren = React.useCallback(() => React.Children.map(children, (child) => {
|
||||
if (React.isValidElement(child)) {
|
||||
const isSelect = child.type === SelectDropdown || child.type === Select;
|
||||
|
||||
return React.cloneElement(child, {
|
||||
id: domId,
|
||||
className: clsx({
|
||||
'w-auto': isSelect,
|
||||
}, child.props.className),
|
||||
});
|
||||
}
|
||||
return React.cloneElement(child, {
|
||||
id: domId,
|
||||
className: clsx({
|
||||
'w-auto': isSelect,
|
||||
}, child.props.className),
|
||||
});
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
}, [children, domId]);
|
||||
return null;
|
||||
}), [children, domId]);
|
||||
|
||||
return (
|
||||
<Comp
|
||||
|
|
|
@ -4,18 +4,16 @@ import LandingGradient from 'soapbox/components/landing-gradient';
|
|||
import { Spinner } from 'soapbox/components/ui';
|
||||
|
||||
/** Fullscreen loading indicator. */
|
||||
const LoadingScreen: React.FC = () => {
|
||||
return (
|
||||
<div className='fixed h-screen w-screen'>
|
||||
<LandingGradient />
|
||||
const LoadingScreen: React.FC = () => (
|
||||
<div className='fixed h-screen w-screen'>
|
||||
<LandingGradient />
|
||||
|
||||
<div className='d-screen fixed z-10 flex w-screen items-center justify-center'>
|
||||
<div className='p-4'>
|
||||
<Spinner size={40} withText={false} />
|
||||
</div>
|
||||
<div className='d-screen fixed z-10 flex w-screen items-center justify-center'>
|
||||
<div className='p-4'>
|
||||
<Spinner size={40} withText={false} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
</div>
|
||||
);
|
||||
|
||||
export default LoadingScreen;
|
||||
|
|
|
@ -29,9 +29,7 @@ const LocationSearch: React.FC<ILocationSearch> = ({ onSelected }) => {
|
|||
|
||||
const [value, setValue] = useState('');
|
||||
|
||||
const isEmpty = (): boolean => {
|
||||
return !(value.length > 0);
|
||||
};
|
||||
const isEmpty = (): boolean => !(value.length > 0);
|
||||
|
||||
const handleChange: React.ChangeEventHandler<HTMLInputElement> = ({ target }) => {
|
||||
refreshCancelToken();
|
||||
|
|
|
@ -7,10 +7,8 @@ interface IMarkup extends IText {
|
|||
}
|
||||
|
||||
/** Styles HTML markup returned by the API, such as in account bios and statuses. */
|
||||
const Markup = React.forwardRef<any, IMarkup>((props, ref) => {
|
||||
return (
|
||||
<Text ref={ref} {...props} data-markup />
|
||||
);
|
||||
});
|
||||
const Markup = React.forwardRef<any, IMarkup>((props, ref) => (
|
||||
<Text ref={ref} {...props} data-markup />
|
||||
));
|
||||
|
||||
export default Markup;
|
||||
export default Markup;
|
||||
|
|
|
@ -36,9 +36,8 @@ interface SizeData {
|
|||
width: number
|
||||
}
|
||||
|
||||
const withinLimits = (aspectRatio: number) => {
|
||||
return aspectRatio >= minimumAspectRatio && aspectRatio <= maximumAspectRatio;
|
||||
};
|
||||
const withinLimits = (aspectRatio: number) =>
|
||||
aspectRatio >= minimumAspectRatio && aspectRatio <= maximumAspectRatio;
|
||||
|
||||
const shouldLetterbox = (attachment: Attachment): boolean => {
|
||||
const aspectRatio = attachment.getIn(['meta', 'original', 'aspect']) as number | undefined;
|
||||
|
@ -87,9 +86,7 @@ const Item: React.FC<IItem> = ({
|
|||
}
|
||||
};
|
||||
|
||||
const hoverToPlay = () => {
|
||||
return !autoPlayGif && attachment.type === 'gifv';
|
||||
};
|
||||
const hoverToPlay = () => !autoPlayGif && attachment.type === 'gifv';
|
||||
|
||||
// FIXME: wtf?
|
||||
const handleClick: React.MouseEventHandler = (e: any) => {
|
||||
|
|
|
@ -20,23 +20,21 @@ const messages = defineMessages({
|
|||
cancelEditing: { id: 'confirmations.cancel_editing.confirm', defaultMessage: 'Cancel editing' },
|
||||
});
|
||||
|
||||
export const checkComposeContent = (compose?: ReturnType<typeof ReducerCompose>) => {
|
||||
return !!compose && [
|
||||
export const checkComposeContent = (compose?: ReturnType<typeof ReducerCompose>) =>
|
||||
!!compose && [
|
||||
compose.text.length > 0,
|
||||
compose.spoiler_text.length > 0,
|
||||
compose.media_attachments.size > 0,
|
||||
compose.poll !== null,
|
||||
].some(check => check === true);
|
||||
};
|
||||
|
||||
export const checkEventComposeContent = (compose?: ReturnType<typeof ReducerComposeEvent>) => {
|
||||
return !!compose && [
|
||||
export const checkEventComposeContent = (compose?: ReturnType<typeof ReducerComposeEvent>) =>
|
||||
!!compose && [
|
||||
compose.name.length > 0,
|
||||
compose.status.length > 0,
|
||||
compose.location !== null,
|
||||
compose.banner !== null,
|
||||
].some(check => check === true);
|
||||
};
|
||||
|
||||
interface IModalRoot {
|
||||
onCancel?: () => void
|
||||
|
@ -180,9 +178,7 @@ const ModalRoot: React.FC<IModalRoot> = ({ children, onCancel, onClose, type })
|
|||
}
|
||||
};
|
||||
|
||||
const getSiblings = () => {
|
||||
return Array(...(ref.current!.parentElement!.childNodes as any as ChildNode[])).filter(node => node !== ref.current);
|
||||
};
|
||||
const getSiblings = () => Array(...(ref.current!.parentElement!.childNodes as any as ChildNode[])).filter(node => node !== ref.current);
|
||||
|
||||
useEffect(() => {
|
||||
if (!visible) return;
|
||||
|
|
|
@ -7,15 +7,13 @@ interface IOutlineBox extends React.HTMLAttributes<HTMLDivElement> {
|
|||
}
|
||||
|
||||
/** Wraps children in a container with an outline. */
|
||||
const OutlineBox: React.FC<IOutlineBox> = ({ children, className, ...rest }) => {
|
||||
return (
|
||||
<div
|
||||
className={clsx('rounded-lg border border-solid border-gray-300 p-4 dark:border-gray-800', className)}
|
||||
{...rest}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
const OutlineBox: React.FC<IOutlineBox> = ({ children, className, ...rest }) => (
|
||||
<div
|
||||
className={clsx('rounded-lg border border-solid border-gray-300 p-4 dark:border-gray-800', className)}
|
||||
{...rest}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
|
||||
export default OutlineBox;
|
||||
|
|
|
@ -15,18 +15,16 @@ const messages = defineMessages({
|
|||
votes: { id: 'poll.votes', defaultMessage: '{votes, plural, one {# vote} other {# votes}}' },
|
||||
});
|
||||
|
||||
const PollPercentageBar: React.FC<{ percent: number, leading: boolean }> = ({ percent, leading }): JSX.Element => {
|
||||
return (
|
||||
<Motion defaultStyle={{ width: 0 }} style={{ width: spring(percent, { ...presets.gentle, precision: 0.1 }) }}>
|
||||
{({ width }) => (
|
||||
<span
|
||||
className='absolute inset-0 inline-block h-full rounded-l-md bg-primary-100 dark:bg-primary-500'
|
||||
style={{ width: `${width}%` }}
|
||||
/>
|
||||
)}
|
||||
</Motion>
|
||||
);
|
||||
};
|
||||
const PollPercentageBar: React.FC<{ percent: number, leading: boolean }> = ({ percent, leading }): JSX.Element => (
|
||||
<Motion defaultStyle={{ width: 0 }} style={{ width: spring(percent, { ...presets.gentle, precision: 0.1 }) }}>
|
||||
{({ width }) => (
|
||||
<span
|
||||
className='absolute inset-0 inline-block h-full rounded-l-md bg-primary-100 dark:bg-primary-500'
|
||||
style={{ width: `${width}%` }}
|
||||
/>
|
||||
)}
|
||||
</Motion>
|
||||
);
|
||||
|
||||
interface IPollOptionText extends IPollOption {
|
||||
percent: number
|
||||
|
|
|
@ -41,17 +41,15 @@ const getBadges = (account: Account): JSX.Element[] => {
|
|||
return badges;
|
||||
};
|
||||
|
||||
const handleMouseEnter = (dispatch: AppDispatch): React.MouseEventHandler => {
|
||||
return () => {
|
||||
const handleMouseEnter = (dispatch: AppDispatch): React.MouseEventHandler =>
|
||||
() => {
|
||||
dispatch(updateProfileHoverCard());
|
||||
};
|
||||
};
|
||||
|
||||
const handleMouseLeave = (dispatch: AppDispatch): React.MouseEventHandler => {
|
||||
return () => {
|
||||
const handleMouseLeave = (dispatch: AppDispatch): React.MouseEventHandler =>
|
||||
() => {
|
||||
dispatch(closeProfileHoverCard(true));
|
||||
};
|
||||
};
|
||||
|
||||
interface IProfileHoverCard {
|
||||
visible: boolean
|
||||
|
|
|
@ -23,21 +23,19 @@ interface IRadioItem {
|
|||
onChange?: React.ChangeEventHandler
|
||||
}
|
||||
|
||||
const RadioItem: React.FC<IRadioItem> = ({ label, hint, checked = false, onChange, value }) => {
|
||||
return (
|
||||
<ListItem label={label} hint={hint}>
|
||||
<input
|
||||
type='radio'
|
||||
checked={checked}
|
||||
onChange={onChange}
|
||||
value={value}
|
||||
className='h-4 w-4 border-gray-300 text-primary-600 focus:ring-primary-500'
|
||||
/>
|
||||
</ListItem>
|
||||
);
|
||||
};
|
||||
const RadioItem: React.FC<IRadioItem> = ({ label, hint, checked = false, onChange, value }) => (
|
||||
<ListItem label={label} hint={hint}>
|
||||
<input
|
||||
type='radio'
|
||||
checked={checked}
|
||||
onChange={onChange}
|
||||
value={value}
|
||||
className='h-4 w-4 border-gray-300 text-primary-600 focus:ring-primary-500'
|
||||
/>
|
||||
</ListItem>
|
||||
);
|
||||
|
||||
export {
|
||||
RadioGroup,
|
||||
RadioItem,
|
||||
};
|
||||
};
|
||||
|
|
|
@ -40,9 +40,7 @@ const ScrollTopButton: React.FC<IScrollTopButton> = ({
|
|||
'hidden': !visible,
|
||||
});
|
||||
|
||||
const getScrollTop = (): number => {
|
||||
return (document.scrollingElement || document.documentElement).scrollTop;
|
||||
};
|
||||
const getScrollTop = (): number => (document.scrollingElement || document.documentElement).scrollTop;
|
||||
|
||||
const maybeUnload = () => {
|
||||
if (autoload && getScrollTop() <= autoloadThreshold) {
|
||||
|
|
|
@ -153,21 +153,19 @@ const ScrollableList = React.forwardRef<VirtuosoHandle, IScrollableList>(({
|
|||
}, []);
|
||||
|
||||
/* Render an empty state instead of the scrollable list. */
|
||||
const renderEmpty = (): JSX.Element => {
|
||||
return (
|
||||
<div className='mt-2'>
|
||||
{alwaysPrepend && prepend}
|
||||
const renderEmpty = (): JSX.Element => (
|
||||
<div className='mt-2'>
|
||||
{alwaysPrepend && prepend}
|
||||
|
||||
<Card variant='rounded' size='lg'>
|
||||
{isLoading ? (
|
||||
<Spinner />
|
||||
) : (
|
||||
emptyMessage
|
||||
)}
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
<Card variant='rounded' size='lg'>
|
||||
{isLoading ? (
|
||||
<Spinner />
|
||||
) : (
|
||||
emptyMessage
|
||||
)}
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
|
||||
/** Render a single item. */
|
||||
const renderItem = (_i: number, element: JSX.Element): JSX.Element => {
|
||||
|
|
|
@ -102,11 +102,9 @@ const SidebarMenu: React.FC = (): JSX.Element | null => {
|
|||
onClose();
|
||||
};
|
||||
|
||||
const handleSwitchAccount = (account: AccountEntity): React.MouseEventHandler => {
|
||||
return (e) => {
|
||||
e.preventDefault();
|
||||
dispatch(switchAccount(account.id));
|
||||
};
|
||||
const handleSwitchAccount = (account: AccountEntity): React.MouseEventHandler => (e) => {
|
||||
e.preventDefault();
|
||||
dispatch(switchAccount(account.id));
|
||||
};
|
||||
|
||||
const onClickLogOut: React.MouseEventHandler = (e) => {
|
||||
|
|
|
@ -16,13 +16,11 @@ interface IStatusActionCounter {
|
|||
}
|
||||
|
||||
/** Action button numerical counter, eg "5" likes. */
|
||||
const StatusActionCounter: React.FC<IStatusActionCounter> = ({ count = 0 }): JSX.Element => {
|
||||
return (
|
||||
<Text size='xs' weight='semibold' theme='inherit'>
|
||||
{shortNumberFormat(count)}
|
||||
</Text>
|
||||
);
|
||||
};
|
||||
const StatusActionCounter: React.FC<IStatusActionCounter> = ({ count = 0 }): JSX.Element => (
|
||||
<Text size='xs' weight='semibold' theme='inherit'>
|
||||
{shortNumberFormat(count)}
|
||||
</Text>
|
||||
);
|
||||
|
||||
interface IStatusActionButton extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
||||
iconClassName?: string
|
||||
|
|
|
@ -50,32 +50,26 @@ export const StatusHoverCard: React.FC<IStatusHoverCard> = ({ visible = true })
|
|||
placement: 'top',
|
||||
});
|
||||
|
||||
const handleMouseEnter = useCallback((): React.MouseEventHandler => {
|
||||
return () => {
|
||||
dispatch(updateStatusHoverCard());
|
||||
};
|
||||
const handleMouseEnter = useCallback((): React.MouseEventHandler => () => {
|
||||
dispatch(updateStatusHoverCard());
|
||||
}, []);
|
||||
|
||||
const handleMouseLeave = useCallback((): React.MouseEventHandler => {
|
||||
return () => {
|
||||
dispatch(closeStatusHoverCard(true));
|
||||
};
|
||||
const handleMouseLeave = useCallback((): React.MouseEventHandler => () => {
|
||||
dispatch(closeStatusHoverCard(true));
|
||||
}, []);
|
||||
|
||||
if (!statusId) return null;
|
||||
|
||||
const renderStatus = (statusId: string) => {
|
||||
return (
|
||||
// @ts-ignore
|
||||
<StatusContainer
|
||||
key={statusId}
|
||||
id={statusId}
|
||||
hoverable={false}
|
||||
hideActionBar
|
||||
muted
|
||||
/>
|
||||
);
|
||||
};
|
||||
const renderStatus = (statusId: string) => (
|
||||
// @ts-ignore
|
||||
<StatusContainer
|
||||
key={statusId}
|
||||
id={statusId}
|
||||
hoverable={false}
|
||||
hideActionBar
|
||||
muted
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
|
|
|
@ -73,9 +73,8 @@ const StatusList: React.FC<IStatusList> = ({
|
|||
const node = useRef<VirtuosoHandle>(null);
|
||||
const seed = useRef<string>(uuidv4());
|
||||
|
||||
const getFeaturedStatusCount = () => {
|
||||
return featuredStatusIds?.size || 0;
|
||||
};
|
||||
const getFeaturedStatusCount = () =>
|
||||
featuredStatusIds?.size || 0;
|
||||
|
||||
const getCurrentStatusIndex = (id: string, featured: boolean): number => {
|
||||
if (featured) {
|
||||
|
@ -130,24 +129,20 @@ const StatusList: React.FC<IStatusList> = ({
|
|||
);
|
||||
};
|
||||
|
||||
const renderStatus = (statusId: string) => {
|
||||
return (
|
||||
<StatusContainer
|
||||
key={statusId}
|
||||
id={statusId}
|
||||
onMoveUp={handleMoveUp}
|
||||
onMoveDown={handleMoveDown}
|
||||
contextType={timelineId}
|
||||
showGroup={showGroup}
|
||||
/>
|
||||
);
|
||||
};
|
||||
const renderStatus = (statusId: string) => (
|
||||
<StatusContainer
|
||||
key={statusId}
|
||||
id={statusId}
|
||||
onMoveUp={handleMoveUp}
|
||||
onMoveDown={handleMoveDown}
|
||||
contextType={timelineId}
|
||||
showGroup={showGroup}
|
||||
/>
|
||||
);
|
||||
|
||||
const renderAd = (ad: AdEntity, index: number) => {
|
||||
return (
|
||||
<Ad key={`ad-${index}`} ad={ad} />
|
||||
);
|
||||
};
|
||||
const renderAd = (ad: AdEntity, index: number) => (
|
||||
<Ad key={`ad-${index}`} ad={ad} />
|
||||
);
|
||||
|
||||
const renderPendingStatus = (statusId: string) => {
|
||||
const idempotencyKey = statusId.replace(/^末pending-/, '');
|
||||
|
@ -176,9 +171,7 @@ const StatusList: React.FC<IStatusList> = ({
|
|||
));
|
||||
};
|
||||
|
||||
const renderFeedSuggestions = (): React.ReactNode => {
|
||||
return <FeedSuggestions key='suggestions' />;
|
||||
};
|
||||
const renderFeedSuggestions = (): React.ReactNode => <FeedSuggestions key='suggestions' />;
|
||||
|
||||
const renderStatuses = (): React.ReactNode[] => {
|
||||
if (isLoading || statusIds.size > 0) {
|
||||
|
|
|
@ -51,17 +51,14 @@ const StatusMedia: React.FC<IStatusMedia> = ({
|
|||
}
|
||||
};
|
||||
|
||||
const renderLoadingMediaGallery = (): JSX.Element => {
|
||||
return <div className='media_gallery' style={{ height: '285px' }} />;
|
||||
};
|
||||
const renderLoadingMediaGallery = (): JSX.Element =>
|
||||
<div className='media_gallery' style={{ height: '285px' }} />;
|
||||
|
||||
const renderLoadingVideoPlayer = (): JSX.Element => {
|
||||
return <div className='media-spoiler-video' style={{ height: '285px' }} />;
|
||||
};
|
||||
const renderLoadingVideoPlayer = (): JSX.Element =>
|
||||
<div className='media-spoiler-video' style={{ height: '285px' }} />;
|
||||
|
||||
const renderLoadingAudioPlayer = (): JSX.Element => {
|
||||
return <div className='media-spoiler-audio' style={{ height: '285px' }} />;
|
||||
};
|
||||
const renderLoadingAudioPlayer = (): JSX.Element =>
|
||||
<div className='media-spoiler-audio' style={{ height: '285px' }} />;
|
||||
|
||||
const openMedia = (media: ImmutableList<Attachment>, index: number) => {
|
||||
dispatch(openModal('MEDIA', { media, status, index }));
|
||||
|
|
|
@ -24,12 +24,10 @@ const StatusReactionWrapper: React.FC<IStatusReactionWrapper> = ({ statusId, chi
|
|||
|
||||
const [referenceElement, setReferenceElement] = useState<HTMLDivElement | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (timeout.current) {
|
||||
clearTimeout(timeout.current);
|
||||
}
|
||||
};
|
||||
useEffect(() => () => {
|
||||
if (timeout.current) {
|
||||
clearTimeout(timeout.current);
|
||||
}
|
||||
}, []);
|
||||
|
||||
if (!status) return null;
|
||||
|
|
|
@ -72,16 +72,14 @@ const SensitiveContentOverlay = React.forwardRef<HTMLDivElement, ISensitiveConte
|
|||
}
|
||||
};
|
||||
|
||||
const menu = useMemo(() => {
|
||||
return [
|
||||
{
|
||||
text: intl.formatMessage(messages.delete),
|
||||
action: handleDeleteStatus,
|
||||
icon: require('@tabler/icons/trash.svg'),
|
||||
destructive: true,
|
||||
},
|
||||
];
|
||||
}, []);
|
||||
const menu = useMemo(() => [
|
||||
{
|
||||
text: intl.formatMessage(messages.delete),
|
||||
action: handleDeleteStatus,
|
||||
icon: require('@tabler/icons/trash.svg'),
|
||||
destructive: true,
|
||||
},
|
||||
], []);
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof props.visible !== 'undefined') {
|
||||
|
|
|
@ -35,4 +35,4 @@ const StatusInfo = (props: IStatusInfo) => {
|
|||
);
|
||||
};
|
||||
|
||||
export default StatusInfo;
|
||||
export default StatusInfo;
|
||||
|
|
|
@ -84,12 +84,10 @@ interface IExtensionBadge {
|
|||
}
|
||||
|
||||
/** Badge displaying a file extension. */
|
||||
const ExtensionBadge: React.FC<IExtensionBadge> = ({ ext }) => {
|
||||
return (
|
||||
<div className='inline-flex items-center rounded bg-gray-100 px-2 py-0.5 text-sm font-medium text-gray-900 dark:bg-gray-800 dark:text-gray-100'>
|
||||
{ext}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
const ExtensionBadge: React.FC<IExtensionBadge> = ({ ext }) => (
|
||||
<div className='inline-flex items-center rounded bg-gray-100 px-2 py-0.5 text-sm font-medium text-gray-900 dark:bg-gray-800 dark:text-gray-100'>
|
||||
{ext}
|
||||
</div>
|
||||
);
|
||||
|
||||
export default StillImage;
|
||||
|
|
|
@ -8,20 +8,18 @@ interface IBanner {
|
|||
}
|
||||
|
||||
/** Displays a sticky full-width banner at the bottom of the screen. */
|
||||
const Banner: React.FC<IBanner> = ({ theme, children, className }) => {
|
||||
return (
|
||||
<div
|
||||
data-testid='banner'
|
||||
className={clsx('fixed inset-x-0 bottom-0 z-50 py-8', {
|
||||
'backdrop-blur bg-primary-800/80 dark:bg-primary-900/80': theme === 'frosted',
|
||||
'bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 shadow-3xl dark:shadow-inset': theme === 'opaque',
|
||||
}, className)}
|
||||
>
|
||||
<div className='mx-auto max-w-4xl px-4'>
|
||||
{children}
|
||||
</div>
|
||||
const Banner: React.FC<IBanner> = ({ theme, children, className }) => (
|
||||
<div
|
||||
data-testid='banner'
|
||||
className={clsx('fixed inset-x-0 bottom-0 z-50 py-8', {
|
||||
'backdrop-blur bg-primary-800/80 dark:bg-primary-900/80': theme === 'frosted',
|
||||
'bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 shadow-3xl dark:shadow-inset': theme === 'opaque',
|
||||
}, className)}
|
||||
>
|
||||
<div className='mx-auto max-w-4xl px-4'>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
</div>
|
||||
);
|
||||
|
||||
export default Banner;
|
||||
|
|
|
@ -3,15 +3,13 @@ import React from 'react';
|
|||
interface ICheckbox extends Pick<React.InputHTMLAttributes<HTMLInputElement>, 'disabled' | 'id' | 'name' | 'onChange' | 'checked' | 'required'> { }
|
||||
|
||||
/** A pretty checkbox input. */
|
||||
const Checkbox = React.forwardRef<HTMLInputElement, ICheckbox>((props, ref) => {
|
||||
return (
|
||||
<input
|
||||
{...props}
|
||||
ref={ref}
|
||||
type='checkbox'
|
||||
className='h-4 w-4 rounded border-2 border-gray-300 text-primary-600 focus:ring-primary-500 dark:border-gray-800 dark:bg-gray-900'
|
||||
/>
|
||||
);
|
||||
});
|
||||
const Checkbox = React.forwardRef<HTMLInputElement, ICheckbox>((props, ref) => (
|
||||
<input
|
||||
{...props}
|
||||
ref={ref}
|
||||
type='checkbox'
|
||||
className='h-4 w-4 rounded border-2 border-gray-300 text-primary-600 focus:ring-primary-500 dark:border-gray-800 dark:bg-gray-900'
|
||||
/>
|
||||
));
|
||||
|
||||
export default Checkbox;
|
||||
|
|
|
@ -10,12 +10,10 @@ interface ICounter {
|
|||
}
|
||||
|
||||
/** A simple counter for notifications, etc. */
|
||||
const Counter: React.FC<ICounter> = ({ count, countMax }) => {
|
||||
return (
|
||||
<span className='flex h-5 min-w-[20px] max-w-[26px] items-center justify-center rounded-full bg-secondary-500 text-xs font-medium text-white ring-2 ring-white dark:ring-gray-800'>
|
||||
{shortNumberFormat(count, countMax)}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
const Counter: React.FC<ICounter> = ({ count, countMax }) => (
|
||||
<span className='flex h-5 min-w-[20px] max-w-[26px] items-center justify-center rounded-full bg-secondary-500 text-xs font-medium text-white ring-2 ring-white dark:ring-gray-800'>
|
||||
{shortNumberFormat(count, countMax)}
|
||||
</span>
|
||||
);
|
||||
|
||||
export default Counter;
|
||||
|
|
|
@ -22,9 +22,7 @@ const Datepicker = ({ onChange }: IDatepicker) => {
|
|||
const [day, setDay] = useState<number>(new Date().getDate());
|
||||
const [year, setYear] = useState<number>(new Date().getFullYear());
|
||||
|
||||
const numberOfDays = useMemo(() => {
|
||||
return getDaysInMonth(month, year);
|
||||
}, [month, year]);
|
||||
const numberOfDays = useMemo(() => getDaysInMonth(month, year), [month, year]);
|
||||
|
||||
useEffect(() => {
|
||||
onChange(new Date(year, month, day));
|
||||
|
|
|
@ -2,15 +2,13 @@ import React, { forwardRef } from 'react';
|
|||
|
||||
interface IFileInput extends Pick<React.InputHTMLAttributes<HTMLInputElement>, 'onChange' | 'required' | 'disabled' | 'name' | 'accept'> { }
|
||||
|
||||
const FileInput = forwardRef<HTMLInputElement, IFileInput>((props, ref) => {
|
||||
return (
|
||||
<input
|
||||
{...props}
|
||||
ref={ref}
|
||||
type='file'
|
||||
className='block w-full text-sm text-gray-800 file:mr-2 file:cursor-pointer file:rounded-full file:border file:border-solid file:border-gray-200 file:bg-white file:py-1.5 file:px-3 file:text-xs file:font-medium file:leading-4 file:text-gray-700 hover:file:bg-gray-100 dark:text-gray-200 dark:file:border-gray-800 dark:file:bg-gray-900 dark:file:text-gray-500 dark:file:hover:bg-gray-800'
|
||||
/>
|
||||
);
|
||||
});
|
||||
const FileInput = forwardRef<HTMLInputElement, IFileInput>((props, ref) => (
|
||||
<input
|
||||
{...props}
|
||||
ref={ref}
|
||||
type='file'
|
||||
className='block w-full text-sm text-gray-800 file:mr-2 file:cursor-pointer file:rounded-full file:border file:border-solid file:border-gray-200 file:bg-white file:py-1.5 file:px-3 file:text-xs file:font-medium file:leading-4 file:text-gray-700 hover:file:bg-gray-100 dark:text-gray-200 dark:file:border-gray-800 dark:file:bg-gray-900 dark:file:text-gray-500 dark:file:hover:bg-gray-800'
|
||||
/>
|
||||
));
|
||||
|
||||
export default FileInput;
|
||||
|
|
|
@ -8,18 +8,16 @@ interface ICountryCodeDropdown {
|
|||
}
|
||||
|
||||
/** Dropdown menu to select a country code. */
|
||||
const CountryCodeDropdown: React.FC<ICountryCodeDropdown> = ({ countryCode, onChange }) => {
|
||||
return (
|
||||
<select
|
||||
value={countryCode}
|
||||
className='h-full rounded-md border-transparent bg-transparent py-0 pl-3 pr-7 text-base focus:outline-none focus:ring-primary-500 dark:text-white sm:text-sm'
|
||||
onChange={(event) => onChange(event.target.value as any)}
|
||||
>
|
||||
{COUNTRY_CODES.map((code) => (
|
||||
<option value={code} key={code}>+{code}</option>
|
||||
))}
|
||||
</select>
|
||||
);
|
||||
};
|
||||
const CountryCodeDropdown: React.FC<ICountryCodeDropdown> = ({ countryCode, onChange }) => (
|
||||
<select
|
||||
value={countryCode}
|
||||
className='h-full rounded-md border-transparent bg-transparent py-0 pl-3 pr-7 text-base focus:outline-none focus:ring-primary-500 dark:text-white sm:text-sm'
|
||||
onChange={(event) => onChange(event.target.value as any)}
|
||||
>
|
||||
{COUNTRY_CODES.map((code) => (
|
||||
<option value={code} key={code}>+{code}</option>
|
||||
))}
|
||||
</select>
|
||||
);
|
||||
|
||||
export default CountryCodeDropdown;
|
||||
|
|
|
@ -28,4 +28,4 @@ const Portal: React.FC<IPortal> = ({ children }) => {
|
|||
);
|
||||
};
|
||||
|
||||
export default Portal;
|
||||
export default Portal;
|
||||
|
|
|
@ -121,4 +121,4 @@ const getPointerPosition = (el: HTMLElement, event: MouseEvent & TouchEvent): Po
|
|||
};
|
||||
};
|
||||
|
||||
export default Slider;
|
||||
export default Slider;
|
||||
|
|
|
@ -50,12 +50,10 @@ const Streamfield: React.FC<IStreamfield> = ({
|
|||
}) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const handleChange = (i: number) => {
|
||||
return (value: any) => {
|
||||
const newData = [...values];
|
||||
newData[i] = value;
|
||||
onChange(newData);
|
||||
};
|
||||
const handleChange = (i: number) => (value: any) => {
|
||||
const newData = [...values];
|
||||
newData[i] = value;
|
||||
onChange(newData);
|
||||
};
|
||||
|
||||
return (
|
||||
|
|
|
@ -67,4 +67,4 @@ const TagInput: React.FC<ITagInput> = ({ tags, onChange, placeholder }) => {
|
|||
);
|
||||
};
|
||||
|
||||
export default TagInput;
|
||||
export default TagInput;
|
||||
|
|
|
@ -11,19 +11,17 @@ interface ITag {
|
|||
}
|
||||
|
||||
/** A single editable Tag (used by TagInput). */
|
||||
const Tag: React.FC<ITag> = ({ tag, onDelete }) => {
|
||||
return (
|
||||
<div className='inline-flex items-center whitespace-nowrap rounded bg-primary-500 p-1'>
|
||||
<Text theme='white'>{tag}</Text>
|
||||
const Tag: React.FC<ITag> = ({ tag, onDelete }) => (
|
||||
<div className='inline-flex items-center whitespace-nowrap rounded bg-primary-500 p-1'>
|
||||
<Text theme='white'>{tag}</Text>
|
||||
|
||||
<IconButton
|
||||
iconClassName='h-4 w-4'
|
||||
src={require('@tabler/icons/x.svg')}
|
||||
onClick={() => onDelete(tag)}
|
||||
transparent
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
<IconButton
|
||||
iconClassName='h-4 w-4'
|
||||
src={require('@tabler/icons/x.svg')}
|
||||
onClick={() => onDelete(tag)}
|
||||
transparent
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
export default Tag;
|
||||
export default Tag;
|
||||
|
|
|
@ -2,13 +2,11 @@ import React from 'react';
|
|||
import ReactToggle, { ToggleProps } from 'react-toggle';
|
||||
|
||||
/** A glorified checkbox. Wrapper around react-toggle. */
|
||||
const Toggle: React.FC<ToggleProps> = ({ icons = false, ...rest }) => {
|
||||
return (
|
||||
<ReactToggle
|
||||
icons={icons}
|
||||
{...rest}
|
||||
/>
|
||||
);
|
||||
};
|
||||
const Toggle: React.FC<ToggleProps> = ({ icons = false, ...rest }) => (
|
||||
<ReactToggle
|
||||
icons={icons}
|
||||
{...rest}
|
||||
/>
|
||||
);
|
||||
|
||||
export default Toggle;
|
||||
|
|
|
@ -42,23 +42,21 @@ const Widget: React.FC<IWidget> = ({
|
|||
actionIcon = require('@tabler/icons/arrow-right.svg'),
|
||||
actionTitle,
|
||||
action,
|
||||
}): JSX.Element => {
|
||||
return (
|
||||
<Stack space={4}>
|
||||
<HStack alignItems='center' justifyContent='between'>
|
||||
<WidgetTitle title={title} />
|
||||
{action || (onActionClick && (
|
||||
<IconButton
|
||||
className='ml-2 h-6 w-6 text-black rtl:rotate-180 dark:text-white'
|
||||
src={actionIcon}
|
||||
onClick={onActionClick}
|
||||
title={actionTitle}
|
||||
/>
|
||||
))}
|
||||
</HStack>
|
||||
<WidgetBody>{children}</WidgetBody>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
}): JSX.Element => (
|
||||
<Stack space={4}>
|
||||
<HStack alignItems='center' justifyContent='between'>
|
||||
<WidgetTitle title={title} />
|
||||
{action || (onActionClick && (
|
||||
<IconButton
|
||||
className='ml-2 h-6 w-6 text-black rtl:rotate-180 dark:text-white'
|
||||
src={actionIcon}
|
||||
onClick={onActionClick}
|
||||
title={actionTitle}
|
||||
/>
|
||||
))}
|
||||
</HStack>
|
||||
<WidgetBody>{children}</WidgetBody>
|
||||
</Stack>
|
||||
);
|
||||
|
||||
export default Widget;
|
||||
|
|
|
@ -9,23 +9,21 @@ interface IUploadProgress {
|
|||
}
|
||||
|
||||
/** Displays a progress bar for uploading files. */
|
||||
const UploadProgress: React.FC<IUploadProgress> = ({ progress }) => {
|
||||
return (
|
||||
<HStack alignItems='center' space={2}>
|
||||
<Icon
|
||||
src={require('@tabler/icons/cloud-upload.svg')}
|
||||
className='h-7 w-7 text-gray-500'
|
||||
/>
|
||||
const UploadProgress: React.FC<IUploadProgress> = ({ progress }) => (
|
||||
<HStack alignItems='center' space={2}>
|
||||
<Icon
|
||||
src={require('@tabler/icons/cloud-upload.svg')}
|
||||
className='h-7 w-7 text-gray-500'
|
||||
/>
|
||||
|
||||
<Stack space={1}>
|
||||
<Text theme='muted'>
|
||||
<FormattedMessage id='upload_progress.label' defaultMessage='Uploading…' />
|
||||
</Text>
|
||||
<Stack space={1}>
|
||||
<Text theme='muted'>
|
||||
<FormattedMessage id='upload_progress.label' defaultMessage='Uploading…' />
|
||||
</Text>
|
||||
|
||||
<ProgressBar progress={progress / 100} size='sm' />
|
||||
</Stack>
|
||||
</HStack>
|
||||
);
|
||||
};
|
||||
<ProgressBar progress={progress / 100} size='sm' />
|
||||
</Stack>
|
||||
</HStack>
|
||||
);
|
||||
|
||||
export default UploadProgress;
|
||||
|
|
|
@ -8,21 +8,19 @@ interface IValidationCheckmark {
|
|||
text: string
|
||||
}
|
||||
|
||||
const ValidationCheckmark = ({ isValid, text }: IValidationCheckmark) => {
|
||||
return (
|
||||
<HStack alignItems='center' space={2} data-testid='validation-checkmark'>
|
||||
<Icon
|
||||
src={isValid ? require('@tabler/icons/check.svg') : require('@tabler/icons/point.svg')}
|
||||
className={clsx({
|
||||
'w-4 h-4': true,
|
||||
'text-gray-400 dark:text-gray-600 dark:fill-gray-600 fill-gray-400': !isValid,
|
||||
'text-success-500': isValid,
|
||||
})}
|
||||
/>
|
||||
const ValidationCheckmark = ({ isValid, text }: IValidationCheckmark) => (
|
||||
<HStack alignItems='center' space={2} data-testid='validation-checkmark'>
|
||||
<Icon
|
||||
src={isValid ? require('@tabler/icons/check.svg') : require('@tabler/icons/point.svg')}
|
||||
className={clsx({
|
||||
'w-4 h-4': true,
|
||||
'text-gray-400 dark:text-gray-600 dark:fill-gray-600 fill-gray-400': !isValid,
|
||||
'text-success-500': isValid,
|
||||
})}
|
||||
/>
|
||||
|
||||
<Text theme='muted' size='sm'>{text}</Text>
|
||||
</HStack>
|
||||
);
|
||||
};
|
||||
<Text theme='muted' size='sm'>{text}</Text>
|
||||
</HStack>
|
||||
);
|
||||
|
||||
export default ValidationCheckmark;
|
||||
|
|
|
@ -65,24 +65,22 @@ store.dispatch(preload() as any);
|
|||
store.dispatch(checkOnboardingStatus() as any);
|
||||
|
||||
/** Load initial data from the backend */
|
||||
const loadInitial = () => {
|
||||
// @ts-ignore
|
||||
return async(dispatch, getState) => {
|
||||
// Await for authenticated fetch
|
||||
await dispatch(fetchMe());
|
||||
// Await for feature detection
|
||||
await dispatch(loadInstance());
|
||||
// Await for configuration
|
||||
await dispatch(loadSoapboxConfig());
|
||||
// @ts-ignore
|
||||
const loadInitial = () => async(dispatch, getState) => {
|
||||
// Await for authenticated fetch
|
||||
await dispatch(fetchMe());
|
||||
// Await for feature detection
|
||||
await dispatch(loadInstance());
|
||||
// Await for configuration
|
||||
await dispatch(loadSoapboxConfig());
|
||||
|
||||
const state = getState();
|
||||
const soapboxConfig = getSoapboxConfig(state);
|
||||
const pepeEnabled = soapboxConfig.getIn(['extensions', 'pepe', 'enabled']) === true;
|
||||
const state = getState();
|
||||
const soapboxConfig = getSoapboxConfig(state);
|
||||
const pepeEnabled = soapboxConfig.getIn(['extensions', 'pepe', 'enabled']) === true;
|
||||
|
||||
if (pepeEnabled && !state.me) {
|
||||
await dispatch(fetchVerificationConfig());
|
||||
}
|
||||
};
|
||||
if (pepeEnabled && !state.me) {
|
||||
await dispatch(fetchVerificationConfig());
|
||||
}
|
||||
};
|
||||
|
||||
/** Highest level node with the Redux store. */
|
||||
|
@ -102,9 +100,8 @@ const SoapboxMount = () => {
|
|||
const { redirectRootNoLogin } = soapboxConfig;
|
||||
|
||||
// @ts-ignore: I don't actually know what these should be, lol
|
||||
const shouldUpdateScroll = (prevRouterProps, { location }) => {
|
||||
return !(location.state?.soapboxModalKey && location.state?.soapboxModalKey !== prevRouterProps?.location?.state?.soapboxModalKey);
|
||||
};
|
||||
const shouldUpdateScroll = (prevRouterProps, { location }) =>
|
||||
!(location.state?.soapboxModalKey && location.state?.soapboxModalKey !== prevRouterProps?.location?.state?.soapboxModalKey);
|
||||
|
||||
/** Render the onboarding flow. */
|
||||
const renderOnboarding = () => (
|
||||
|
@ -293,20 +290,18 @@ const SoapboxHead: React.FC<ISoapboxHead> = ({ children }) => {
|
|||
};
|
||||
|
||||
/** The root React node of the application. */
|
||||
const Soapbox: React.FC = () => {
|
||||
return (
|
||||
<Provider store={store}>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<StatProvider>
|
||||
<SoapboxHead>
|
||||
<SoapboxLoad>
|
||||
<SoapboxMount />
|
||||
</SoapboxLoad>
|
||||
</SoapboxHead>
|
||||
</StatProvider>
|
||||
</QueryClientProvider>
|
||||
</Provider>
|
||||
);
|
||||
};
|
||||
const Soapbox: React.FC = () => (
|
||||
<Provider store={store}>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<StatProvider>
|
||||
<SoapboxHead>
|
||||
<SoapboxLoad>
|
||||
<SoapboxMount />
|
||||
</SoapboxLoad>
|
||||
</SoapboxHead>
|
||||
</StatProvider>
|
||||
</QueryClientProvider>
|
||||
</Provider>
|
||||
);
|
||||
|
||||
export default Soapbox;
|
||||
|
|
|
@ -30,4 +30,4 @@ const StatProvider: React.FC<IStatProvider> = ({ children }) => {
|
|||
|
||||
const useStatContext = (): IStatContext => useContext(StatContext);
|
||||
|
||||
export { StatProvider, useStatContext, IStatContext };
|
||||
export { StatProvider, useStatContext, IStatContext };
|
||||
|
|
|
@ -36,9 +36,7 @@ const MediaItem: React.FC<IMediaItem> = ({ attachment, onOpenMedia }) => {
|
|||
}
|
||||
};
|
||||
|
||||
const hoverToPlay = () => {
|
||||
return !autoPlayGif && ['gifv', 'video'].includes(attachment.type);
|
||||
};
|
||||
const hoverToPlay = () => !autoPlayGif && ['gifv', 'video'].includes(attachment.type);
|
||||
|
||||
const handleClick: React.MouseEventHandler = e => {
|
||||
if (e.button === 0 && !(e.ctrlKey || e.metaKey)) {
|
||||
|
|
|
@ -90,9 +90,7 @@ const Header: React.FC<IHeader> = ({ account }) => {
|
|||
|
||||
const { getOrCreateChatByAccountId } = useChats();
|
||||
|
||||
const createAndNavigateToChat = useMutation((accountId: string) => {
|
||||
return getOrCreateChatByAccountId(accountId);
|
||||
}, {
|
||||
const createAndNavigateToChat = useMutation((accountId: string) => getOrCreateChatByAccountId(accountId), {
|
||||
onError: (error: AxiosError) => {
|
||||
const data = error.response?.data as any;
|
||||
toast.error(data?.error);
|
||||
|
|
|
@ -43,15 +43,13 @@ interface IDashCounters {
|
|||
}
|
||||
|
||||
/** Wrapper container for dash counters. */
|
||||
const DashCounters: React.FC<IDashCounters> = ({ children }) => {
|
||||
return (
|
||||
<div className='grid grid-cols-1 gap-2 sm:grid-cols-2 lg:grid-cols-3'>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
const DashCounters: React.FC<IDashCounters> = ({ children }) => (
|
||||
<div className='grid grid-cols-1 gap-2 sm:grid-cols-2 lg:grid-cols-3'>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
|
||||
export {
|
||||
DashCounter,
|
||||
DashCounters,
|
||||
};
|
||||
};
|
||||
|
|
|
@ -41,18 +41,16 @@ const Report: React.FC<IReport> = ({ id }) => {
|
|||
const account = report.account as Account;
|
||||
const targetAccount = report.target_account as Account;
|
||||
|
||||
const makeMenu = () => {
|
||||
return [{
|
||||
text: intl.formatMessage(messages.deactivateUser, { name: targetAccount.username }),
|
||||
action: handleDeactivateUser,
|
||||
icon: require('@tabler/icons/hourglass-empty.svg'),
|
||||
}, {
|
||||
text: intl.formatMessage(messages.deleteUser, { name: targetAccount.username }),
|
||||
action: handleDeleteUser,
|
||||
icon: require('@tabler/icons/trash.svg'),
|
||||
destructive: true,
|
||||
}];
|
||||
};
|
||||
const makeMenu = () => [{
|
||||
text: intl.formatMessage(messages.deactivateUser, { name: targetAccount.username }),
|
||||
action: handleDeactivateUser,
|
||||
icon: require('@tabler/icons/hourglass-empty.svg'),
|
||||
}, {
|
||||
text: intl.formatMessage(messages.deleteUser, { name: targetAccount.username }),
|
||||
action: handleDeleteUser,
|
||||
icon: require('@tabler/icons/trash.svg'),
|
||||
destructive: true,
|
||||
}];
|
||||
|
||||
const handleCloseReport = () => {
|
||||
dispatch(closeReports([report.id])).then(() => {
|
||||
|
|
|
@ -16,9 +16,7 @@ const ModerationLog = () => {
|
|||
const intl = useIntl();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const items = useAppSelector((state) => {
|
||||
return state.admin_log.index.map((i) => state.admin_log.items.get(String(i)));
|
||||
});
|
||||
const items = useAppSelector((state) => state.admin_log.index.map((i) => state.admin_log.items.get(String(i))));
|
||||
|
||||
const hasMore = useAppSelector((state) => state.admin_log.total - state.admin_log.index.count() > 0);
|
||||
|
||||
|
@ -70,24 +68,22 @@ interface ILogItem {
|
|||
log: AdminLog
|
||||
}
|
||||
|
||||
const LogItem: React.FC<ILogItem> = ({ log }) => {
|
||||
return (
|
||||
<Stack space={2} className='p-4'>
|
||||
<Text>{log.message}</Text>
|
||||
const LogItem: React.FC<ILogItem> = ({ log }) => (
|
||||
<Stack space={2} className='p-4'>
|
||||
<Text>{log.message}</Text>
|
||||
|
||||
<Text theme='muted' size='xs'>
|
||||
<FormattedDate
|
||||
value={new Date(log.time * 1000)}
|
||||
hour12
|
||||
year='numeric'
|
||||
month='short'
|
||||
day='2-digit'
|
||||
hour='numeric'
|
||||
minute='2-digit'
|
||||
/>
|
||||
</Text>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
<Text theme='muted' size='xs'>
|
||||
<FormattedDate
|
||||
value={new Date(log.time * 1000)}
|
||||
hour12
|
||||
year='numeric'
|
||||
month='short'
|
||||
day='2-digit'
|
||||
hour='numeric'
|
||||
minute='2-digit'
|
||||
/>
|
||||
</Text>
|
||||
</Stack>
|
||||
);
|
||||
|
||||
export default ModerationLog;
|
||||
|
|
|
@ -318,33 +318,26 @@ const Audio: React.FC<IAudio> = (props) => {
|
|||
visualizer.current?.draw(_getCX(), _getCY(), _getAccentColor(), _getRadius(), _getScaleCoefficient());
|
||||
};
|
||||
|
||||
const _getRadius = (): number => {
|
||||
return ((height || props.height || 0) - (PADDING * _getScaleCoefficient()) * 2) / 2;
|
||||
};
|
||||
const _getRadius = (): number =>
|
||||
((height || props.height || 0) - (PADDING * _getScaleCoefficient()) * 2) / 2;
|
||||
|
||||
const _getScaleCoefficient = (): number => {
|
||||
return (height || props.height || 0) / 982;
|
||||
};
|
||||
const _getScaleCoefficient = (): number =>
|
||||
(height || props.height || 0) / 982;
|
||||
|
||||
const _getCX = (): number => {
|
||||
return Math.floor((width || 0) / 2);
|
||||
};
|
||||
const _getCX = (): number =>
|
||||
Math.floor((width || 0) / 2);
|
||||
|
||||
const _getCY = (): number => {
|
||||
return Math.floor(_getRadius() + (PADDING * _getScaleCoefficient()));
|
||||
};
|
||||
const _getCY = (): number =>
|
||||
Math.floor(_getRadius() + (PADDING * _getScaleCoefficient()));
|
||||
|
||||
const _getAccentColor = (): string => {
|
||||
return accentColor || '#ffffff';
|
||||
};
|
||||
const _getAccentColor = (): string =>
|
||||
accentColor || '#ffffff';
|
||||
|
||||
const _getBackgroundColor = (): string => {
|
||||
return backgroundColor || '#000000';
|
||||
};
|
||||
const _getBackgroundColor = (): string =>
|
||||
backgroundColor || '#000000';
|
||||
|
||||
const _getForegroundColor = (): string => {
|
||||
return foregroundColor || '#ffffff';
|
||||
};
|
||||
const _getForegroundColor = (): string =>
|
||||
foregroundColor || '#ffffff';
|
||||
|
||||
const seekBy = (time: number) => {
|
||||
if (audio.current) {
|
||||
|
|
|
@ -151,9 +151,7 @@ const RegistrationForm: React.FC<IRegistrationForm> = ({ inviteToken }) => {
|
|||
}
|
||||
};
|
||||
|
||||
const passwordsMatch = () => {
|
||||
return params.get('password', '') === passwordConfirmation;
|
||||
};
|
||||
const passwordsMatch = () => params.get('password', '') === passwordConfirmation;
|
||||
|
||||
const usernameAvailable = useCallback(debounce(username => {
|
||||
if (!supportsAccountLookup) return;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Ładowanie…
Reference in New Issue