Merge branch 'muting_with_duration' into 'develop'

Support mutes duration

See merge request soapbox-pub/soapbox!913
environments/review-develop-3zknud/deployments/1287
marcin mikołajczak 2022-11-04 16:29:08 +00:00
commit f11ba14093
8 zmienionych plików z 95 dodań i 6 usunięć

Wyświetl plik

@ -1,5 +1,5 @@
import { isLoggedIn } from 'soapbox/utils/auth';
import { getFeatures } from 'soapbox/utils/features';
import { getFeatures, parseVersion, PLEROMA } from 'soapbox/utils/features';
import api, { getLinks } from '../api';
@ -359,14 +359,30 @@ const unblockAccountFail = (error: AxiosError) => ({
error,
});
const muteAccount = (id: string, notifications?: boolean) =>
const muteAccount = (id: string, notifications?: boolean, duration = 0) =>
(dispatch: AppDispatch, getState: () => RootState) => {
if (!isLoggedIn(getState)) return null;
dispatch(muteAccountRequest(id));
const params: Record<string, any> = {
notifications,
};
if (duration) {
const state = getState();
const instance = state.instance;
const v = parseVersion(instance.version);
if (v.software === PLEROMA) {
params.expires_in = duration;
} else {
params.duration = duration;
}
}
return api(getState)
.post(`/api/v1/accounts/${id}/mute`, { notifications })
.post(`/api/v1/accounts/${id}/mute`, params)
.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));

Wyświetl plik

@ -21,6 +21,7 @@ const MUTES_EXPAND_FAIL = 'MUTES_EXPAND_FAIL';
const MUTES_INIT_MODAL = 'MUTES_INIT_MODAL';
const MUTES_TOGGLE_HIDE_NOTIFICATIONS = 'MUTES_TOGGLE_HIDE_NOTIFICATIONS';
const MUTES_CHANGE_DURATION = 'MUTES_CHANGE_DURATION';
const fetchMutes = () =>
(dispatch: AppDispatch, getState: () => RootState) => {
@ -103,6 +104,14 @@ const toggleHideNotifications = () =>
dispatch({ type: MUTES_TOGGLE_HIDE_NOTIFICATIONS });
};
const changeMuteDuration = (duration: number) =>
(dispatch: AppDispatch) => {
dispatch({
type: MUTES_CHANGE_DURATION,
duration,
});
};
export {
MUTES_FETCH_REQUEST,
MUTES_FETCH_SUCCESS,
@ -112,6 +121,7 @@ export {
MUTES_EXPAND_FAIL,
MUTES_INIT_MODAL,
MUTES_TOGGLE_HIDE_NOTIFICATIONS,
MUTES_CHANGE_DURATION,
fetchMutes,
fetchMutesRequest,
fetchMutesSuccess,
@ -122,4 +132,5 @@ export {
expandMutesFail,
initMuteModal,
toggleHideNotifications,
changeMuteDuration,
};

Wyświetl plik

@ -235,6 +235,14 @@ const Account = ({
<Icon className='h-5 w-5 text-gray-700 dark:text-gray-600' src={require('@tabler/icons/pencil.svg')} />
</>
) : null}
{actionType === 'muting' && account.mute_expires_at ? (
<>
<Text tag='span' theme='muted' size='sm'>&middot;</Text>
<Text theme='muted' size='sm'><RelativeTimestamp timestamp={account.mute_expires_at} futureDate /></Text>
</>
) : null}
</HStack>
{withAccountNote && (

Wyświetl plik

@ -4,9 +4,10 @@ import Toggle from 'react-toggle';
import { muteAccount } from 'soapbox/actions/accounts';
import { closeModal } from 'soapbox/actions/modals';
import { toggleHideNotifications } from 'soapbox/actions/mutes';
import { toggleHideNotifications, changeMuteDuration } from 'soapbox/actions/mutes';
import { Modal, HStack, Stack, Text } from 'soapbox/components/ui';
import { useAppDispatch, useAppSelector } from 'soapbox/hooks';
import DurationSelector from 'soapbox/features/compose/components/polls/duration-selector';
import { useAppDispatch, useAppSelector, useFeatures } from 'soapbox/hooks';
import { makeGetAccount } from 'soapbox/selectors';
const getAccount = makeGetAccount();
@ -16,12 +17,14 @@ const MuteModal = () => {
const account = useAppSelector((state) => getAccount(state, state.mutes.new.accountId!));
const notifications = useAppSelector((state) => state.mutes.new.notifications);
const duration = useAppSelector((state) => state.mutes.new.duration);
const mutesDuration = useFeatures().mutesDuration;
if (!account) return null;
const handleClick = () => {
dispatch(closeModal());
dispatch(muteAccount(account.id, notifications));
dispatch(muteAccount(account.id, notifications, duration));
};
const handleCancel = () => {
@ -32,6 +35,12 @@ const MuteModal = () => {
dispatch(toggleHideNotifications());
};
const handleChangeMuteDuration = (expiresIn: number): void => {
dispatch(changeMuteDuration(expiresIn));
};
const toggleAutoExpire = () => handleChangeMuteDuration(duration ? 0 : 2 * 60 * 60 * 24);
return (
<Modal
title={
@ -69,6 +78,32 @@ const MuteModal = () => {
/>
</HStack>
</label>
{mutesDuration && (
<>
<label>
<HStack alignItems='center' space={2}>
<Text tag='span'>
<FormattedMessage id='mute_modal.auto_expire' defaultMessage='Automatically expire mute?' />
</Text>
<Toggle
checked={duration !== 0}
onChange={toggleAutoExpire}
icons={false}
/>
</HStack>
</label>
{duration !== 0 && (
<Stack space={2}>
<Text weight='medium'><FormattedMessage id='mute_modal.duration' defaultMessage='Duration' />: </Text>
<DurationSelector onDurationChange={handleChangeMuteDuration} />
</Stack>
)}
</>
)}
</Stack>
</Modal>
);

Wyświetl plik

@ -42,6 +42,7 @@ export const AccountRecord = ImmutableRecord({
location: '',
locked: false,
moved: null as EmbeddedEntity<any>,
mute_expires_at: null as Date | null,
note: '',
pleroma: ImmutableMap<string, any>(),
source: ImmutableMap<string, any>(),

Wyświetl plik

@ -14,6 +14,7 @@ describe('mutes reducer', () => {
isSubmitting: false,
accountId: null,
notifications: true,
duration: 0,
},
});
});
@ -24,6 +25,7 @@ describe('mutes reducer', () => {
isSubmitting: false,
accountId: null,
notifications: true,
duration: 0,
})(),
})();
const action = {
@ -35,6 +37,7 @@ describe('mutes reducer', () => {
isSubmitting: false,
accountId: 'account1',
notifications: true,
duration: 0,
},
});
});
@ -45,6 +48,7 @@ describe('mutes reducer', () => {
isSubmitting: false,
accountId: null,
notifications: true,
duration: 0,
})(),
})();
const action = {
@ -55,6 +59,7 @@ describe('mutes reducer', () => {
isSubmitting: false,
accountId: null,
notifications: false,
duration: 0,
},
});
});

Wyświetl plik

@ -3,6 +3,7 @@ import { Record as ImmutableRecord } from 'immutable';
import {
MUTES_INIT_MODAL,
MUTES_TOGGLE_HIDE_NOTIFICATIONS,
MUTES_CHANGE_DURATION,
} from '../actions/mutes';
import type { AnyAction } from 'redux';
@ -11,6 +12,7 @@ const NewMuteRecord = ImmutableRecord({
isSubmitting: false,
accountId: null,
notifications: true,
duration: 0,
});
const ReducerRecord = ImmutableRecord({
@ -29,6 +31,8 @@ export default function mutes(state: State = ReducerRecord(), action: AnyAction)
});
case MUTES_TOGGLE_HIDE_NOTIFICATIONS:
return state.updateIn(['new', 'notifications'], (old) => !old);
case MUTES_CHANGE_DURATION:
return state.setIn(['new', 'duration'], action.duration);
default:
return state;
}

Wyświetl plik

@ -400,6 +400,15 @@ const getInstanceFeatures = (instance: Instance) => {
*/
muteStrangers: v.software === PLEROMA,
/**
* Ability to specify how long the account mute should last.
* @see PUT /api/v1/accounts/:id/mute
*/
mutesDuration: any([
v.software === PLEROMA && gte(v.version, '2.3.0'),
v.software === MASTODON && gte(v.compatVersion, '3.3.0'),
]),
/**
* Add private notes to accounts.
* @see POST /api/v1/accounts/:id/note