mirror of
https://github.com/mastodon/mastodon.git
synced 2025-05-09 05:06:14 +00:00
Refactor <DomainBlocks>
to TypeScript (#34347)
Co-authored-by: Claire <claire.github-309c@sitedethib.com>
This commit is contained in:
parent
e2ef173b82
commit
2c70c28bbb
|
@ -12,14 +12,6 @@ export const DOMAIN_BLOCK_FAIL = 'DOMAIN_BLOCK_FAIL';
|
||||||
export const DOMAIN_UNBLOCK_REQUEST = 'DOMAIN_UNBLOCK_REQUEST';
|
export const DOMAIN_UNBLOCK_REQUEST = 'DOMAIN_UNBLOCK_REQUEST';
|
||||||
export const DOMAIN_UNBLOCK_FAIL = 'DOMAIN_UNBLOCK_FAIL';
|
export const DOMAIN_UNBLOCK_FAIL = 'DOMAIN_UNBLOCK_FAIL';
|
||||||
|
|
||||||
export const DOMAIN_BLOCKS_FETCH_REQUEST = 'DOMAIN_BLOCKS_FETCH_REQUEST';
|
|
||||||
export const DOMAIN_BLOCKS_FETCH_SUCCESS = 'DOMAIN_BLOCKS_FETCH_SUCCESS';
|
|
||||||
export const DOMAIN_BLOCKS_FETCH_FAIL = 'DOMAIN_BLOCKS_FETCH_FAIL';
|
|
||||||
|
|
||||||
export const DOMAIN_BLOCKS_EXPAND_REQUEST = 'DOMAIN_BLOCKS_EXPAND_REQUEST';
|
|
||||||
export const DOMAIN_BLOCKS_EXPAND_SUCCESS = 'DOMAIN_BLOCKS_EXPAND_SUCCESS';
|
|
||||||
export const DOMAIN_BLOCKS_EXPAND_FAIL = 'DOMAIN_BLOCKS_EXPAND_FAIL';
|
|
||||||
|
|
||||||
export function blockDomain(domain) {
|
export function blockDomain(domain) {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
dispatch(blockDomainRequest(domain));
|
dispatch(blockDomainRequest(domain));
|
||||||
|
@ -79,80 +71,6 @@ export function unblockDomainFail(domain, error) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function fetchDomainBlocks() {
|
|
||||||
return (dispatch) => {
|
|
||||||
dispatch(fetchDomainBlocksRequest());
|
|
||||||
|
|
||||||
api().get('/api/v1/domain_blocks').then(response => {
|
|
||||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
|
||||||
dispatch(fetchDomainBlocksSuccess(response.data, next ? next.uri : null));
|
|
||||||
}).catch(err => {
|
|
||||||
dispatch(fetchDomainBlocksFail(err));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchDomainBlocksRequest() {
|
|
||||||
return {
|
|
||||||
type: DOMAIN_BLOCKS_FETCH_REQUEST,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchDomainBlocksSuccess(domains, next) {
|
|
||||||
return {
|
|
||||||
type: DOMAIN_BLOCKS_FETCH_SUCCESS,
|
|
||||||
domains,
|
|
||||||
next,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchDomainBlocksFail(error) {
|
|
||||||
return {
|
|
||||||
type: DOMAIN_BLOCKS_FETCH_FAIL,
|
|
||||||
error,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function expandDomainBlocks() {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
const url = getState().getIn(['domain_lists', 'blocks', 'next']);
|
|
||||||
|
|
||||||
if (!url) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(expandDomainBlocksRequest());
|
|
||||||
|
|
||||||
api().get(url).then(response => {
|
|
||||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
|
||||||
dispatch(expandDomainBlocksSuccess(response.data, next ? next.uri : null));
|
|
||||||
}).catch(err => {
|
|
||||||
dispatch(expandDomainBlocksFail(err));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function expandDomainBlocksRequest() {
|
|
||||||
return {
|
|
||||||
type: DOMAIN_BLOCKS_EXPAND_REQUEST,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function expandDomainBlocksSuccess(domains, next) {
|
|
||||||
return {
|
|
||||||
type: DOMAIN_BLOCKS_EXPAND_SUCCESS,
|
|
||||||
domains,
|
|
||||||
next,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function expandDomainBlocksFail(error) {
|
|
||||||
return {
|
|
||||||
type: DOMAIN_BLOCKS_EXPAND_FAIL,
|
|
||||||
error,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export const initDomainBlockModal = account => dispatch => dispatch(openModal({
|
export const initDomainBlockModal = account => dispatch => dispatch(openModal({
|
||||||
modalType: 'DOMAIN_BLOCK',
|
modalType: 'DOMAIN_BLOCK',
|
||||||
modalProps: {
|
modalProps: {
|
||||||
|
|
13
app/javascript/mastodon/api/domain_blocks.ts
Normal file
13
app/javascript/mastodon/api/domain_blocks.ts
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
import api, { getLinks } from 'mastodon/api';
|
||||||
|
|
||||||
|
export const apiGetDomainBlocks = async (url?: string) => {
|
||||||
|
const response = await api().request<string[]>({
|
||||||
|
method: 'GET',
|
||||||
|
url: url ?? '/api/v1/domain_blocks',
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
domains: response.data,
|
||||||
|
links: getLinks(response),
|
||||||
|
};
|
||||||
|
};
|
|
@ -1,24 +1,15 @@
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
import { defineMessages, useIntl } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
import LockOpenIcon from '@/material-icons/400-24px/lock_open.svg?react';
|
|
||||||
import { unblockDomain } from 'mastodon/actions/domain_blocks';
|
import { unblockDomain } from 'mastodon/actions/domain_blocks';
|
||||||
import { useAppDispatch } from 'mastodon/store';
|
import { useAppDispatch } from 'mastodon/store';
|
||||||
|
|
||||||
import { IconButton } from './icon_button';
|
import { Button } from './button';
|
||||||
|
|
||||||
const messages = defineMessages({
|
|
||||||
unblockDomain: {
|
|
||||||
id: 'account.unblock_domain',
|
|
||||||
defaultMessage: 'Unblock domain {domain}',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export const Domain: React.FC<{
|
export const Domain: React.FC<{
|
||||||
domain: string;
|
domain: string;
|
||||||
}> = ({ domain }) => {
|
}> = ({ domain }) => {
|
||||||
const intl = useIntl();
|
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
const handleDomainUnblock = useCallback(() => {
|
const handleDomainUnblock = useCallback(() => {
|
||||||
|
@ -27,20 +18,17 @@ export const Domain: React.FC<{
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='domain'>
|
<div className='domain'>
|
||||||
<div className='domain__wrapper'>
|
<div className='domain__domain-name'>
|
||||||
<span className='domain__domain-name'>
|
<strong>{domain}</strong>
|
||||||
<strong>{domain}</strong>
|
</div>
|
||||||
</span>
|
|
||||||
|
|
||||||
<div className='domain__buttons'>
|
<div className='domain__buttons'>
|
||||||
<IconButton
|
<Button onClick={handleDomainUnblock}>
|
||||||
active
|
<FormattedMessage
|
||||||
icon='unlock'
|
id='account.unblock_domain_short'
|
||||||
iconComponent={LockOpenIcon}
|
defaultMessage='Unblock'
|
||||||
title={intl.formatMessage(messages.unblockDomain, { domain })}
|
|
||||||
onClick={handleDomainUnblock}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,85 +0,0 @@
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
|
|
||||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
|
||||||
|
|
||||||
import { Helmet } from 'react-helmet';
|
|
||||||
|
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
|
|
||||||
import { debounce } from 'lodash';
|
|
||||||
|
|
||||||
import BlockIcon from '@/material-icons/400-24px/block-fill.svg?react';
|
|
||||||
import { Domain } from 'mastodon/components/domain';
|
|
||||||
|
|
||||||
import { fetchDomainBlocks, expandDomainBlocks } from '../../actions/domain_blocks';
|
|
||||||
import { LoadingIndicator } from '../../components/loading_indicator';
|
|
||||||
import ScrollableList from '../../components/scrollable_list';
|
|
||||||
import Column from '../ui/components/column';
|
|
||||||
|
|
||||||
const messages = defineMessages({
|
|
||||||
heading: { id: 'column.domain_blocks', defaultMessage: 'Blocked domains' },
|
|
||||||
});
|
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
|
||||||
domains: state.getIn(['domain_lists', 'blocks', 'items']),
|
|
||||||
hasMore: !!state.getIn(['domain_lists', 'blocks', 'next']),
|
|
||||||
});
|
|
||||||
|
|
||||||
class Blocks extends ImmutablePureComponent {
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
params: PropTypes.object.isRequired,
|
|
||||||
dispatch: PropTypes.func.isRequired,
|
|
||||||
hasMore: PropTypes.bool,
|
|
||||||
domains: ImmutablePropTypes.orderedSet,
|
|
||||||
intl: PropTypes.object.isRequired,
|
|
||||||
multiColumn: PropTypes.bool,
|
|
||||||
};
|
|
||||||
|
|
||||||
UNSAFE_componentWillMount () {
|
|
||||||
this.props.dispatch(fetchDomainBlocks());
|
|
||||||
}
|
|
||||||
|
|
||||||
handleLoadMore = debounce(() => {
|
|
||||||
this.props.dispatch(expandDomainBlocks());
|
|
||||||
}, 300, { leading: true });
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const { intl, domains, hasMore, multiColumn } = this.props;
|
|
||||||
|
|
||||||
if (!domains) {
|
|
||||||
return (
|
|
||||||
<Column>
|
|
||||||
<LoadingIndicator />
|
|
||||||
</Column>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const emptyMessage = <FormattedMessage id='empty_column.domain_blocks' defaultMessage='There are no blocked domains yet.' />;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Column bindToDocument={!multiColumn} icon='ban' iconComponent={BlockIcon} heading={intl.formatMessage(messages.heading)} alwaysShowBackButton>
|
|
||||||
<ScrollableList
|
|
||||||
scrollKey='domain_blocks'
|
|
||||||
onLoadMore={this.handleLoadMore}
|
|
||||||
hasMore={hasMore}
|
|
||||||
emptyMessage={emptyMessage}
|
|
||||||
bindToDocument={!multiColumn}
|
|
||||||
>
|
|
||||||
{domains.map(domain =>
|
|
||||||
<Domain key={domain} domain={domain} />,
|
|
||||||
)}
|
|
||||||
</ScrollableList>
|
|
||||||
|
|
||||||
<Helmet>
|
|
||||||
<meta name='robots' content='noindex' />
|
|
||||||
</Helmet>
|
|
||||||
</Column>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(mapStateToProps)(injectIntl(Blocks));
|
|
113
app/javascript/mastodon/features/domain_blocks/index.tsx
Normal file
113
app/javascript/mastodon/features/domain_blocks/index.tsx
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
import { useEffect, useRef, useCallback, useState } from 'react';
|
||||||
|
|
||||||
|
import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
|
import { Helmet } from 'react-helmet';
|
||||||
|
|
||||||
|
import BlockIcon from '@/material-icons/400-24px/block-fill.svg?react';
|
||||||
|
import { apiGetDomainBlocks } from 'mastodon/api/domain_blocks';
|
||||||
|
import { Column } from 'mastodon/components/column';
|
||||||
|
import type { ColumnRef } from 'mastodon/components/column';
|
||||||
|
import { ColumnHeader } from 'mastodon/components/column_header';
|
||||||
|
import { Domain } from 'mastodon/components/domain';
|
||||||
|
import ScrollableList from 'mastodon/components/scrollable_list';
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
heading: { id: 'column.domain_blocks', defaultMessage: 'Blocked domains' },
|
||||||
|
});
|
||||||
|
|
||||||
|
const Blocks: React.FC<{ multiColumn: boolean }> = ({ multiColumn }) => {
|
||||||
|
const intl = useIntl();
|
||||||
|
const [domains, setDomains] = useState<string[]>([]);
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [next, setNext] = useState<string | undefined>();
|
||||||
|
const hasMore = !!next;
|
||||||
|
const columnRef = useRef<ColumnRef>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setLoading(true);
|
||||||
|
|
||||||
|
void apiGetDomainBlocks()
|
||||||
|
.then(({ domains, links }) => {
|
||||||
|
const next = links.refs.find((link) => link.rel === 'next');
|
||||||
|
|
||||||
|
setLoading(false);
|
||||||
|
setDomains(domains);
|
||||||
|
setNext(next?.uri);
|
||||||
|
|
||||||
|
return '';
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
setLoading(false);
|
||||||
|
});
|
||||||
|
}, [setLoading, setDomains, setNext]);
|
||||||
|
|
||||||
|
const handleLoadMore = useCallback(() => {
|
||||||
|
setLoading(true);
|
||||||
|
|
||||||
|
void apiGetDomainBlocks(next)
|
||||||
|
.then(({ domains, links }) => {
|
||||||
|
const next = links.refs.find((link) => link.rel === 'next');
|
||||||
|
|
||||||
|
setLoading(false);
|
||||||
|
setDomains((previousDomains) => [...previousDomains, ...domains]);
|
||||||
|
setNext(next?.uri);
|
||||||
|
|
||||||
|
return '';
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
setLoading(false);
|
||||||
|
});
|
||||||
|
}, [setLoading, setDomains, setNext, next]);
|
||||||
|
|
||||||
|
const handleHeaderClick = useCallback(() => {
|
||||||
|
columnRef.current?.scrollTop();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const emptyMessage = (
|
||||||
|
<FormattedMessage
|
||||||
|
id='empty_column.domain_blocks'
|
||||||
|
defaultMessage='There are no blocked domains yet.'
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Column
|
||||||
|
bindToDocument={!multiColumn}
|
||||||
|
ref={columnRef}
|
||||||
|
label={intl.formatMessage(messages.heading)}
|
||||||
|
>
|
||||||
|
<ColumnHeader
|
||||||
|
icon='ban'
|
||||||
|
iconComponent={BlockIcon}
|
||||||
|
title={intl.formatMessage(messages.heading)}
|
||||||
|
onClick={handleHeaderClick}
|
||||||
|
multiColumn={multiColumn}
|
||||||
|
showBackButton
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ScrollableList
|
||||||
|
scrollKey='domain_blocks'
|
||||||
|
onLoadMore={handleLoadMore}
|
||||||
|
hasMore={hasMore}
|
||||||
|
isLoading={loading}
|
||||||
|
showLoading={loading && domains.length === 0}
|
||||||
|
emptyMessage={emptyMessage}
|
||||||
|
trackScroll={!multiColumn}
|
||||||
|
bindToDocument={!multiColumn}
|
||||||
|
>
|
||||||
|
{domains.map((domain) => (
|
||||||
|
<Domain key={domain} domain={domain} />
|
||||||
|
))}
|
||||||
|
</ScrollableList>
|
||||||
|
|
||||||
|
<Helmet>
|
||||||
|
<title>{intl.formatMessage(messages.heading)}</title>
|
||||||
|
<meta name='robots' content='noindex' />
|
||||||
|
</Helmet>
|
||||||
|
</Column>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// eslint-disable-next-line import/no-default-export
|
||||||
|
export default Blocks;
|
|
@ -65,6 +65,7 @@
|
||||||
"account.statuses_counter": "{count, plural, one {{counter} post} other {{counter} posts}}",
|
"account.statuses_counter": "{count, plural, one {{counter} post} other {{counter} posts}}",
|
||||||
"account.unblock": "Unblock @{name}",
|
"account.unblock": "Unblock @{name}",
|
||||||
"account.unblock_domain": "Unblock domain {domain}",
|
"account.unblock_domain": "Unblock domain {domain}",
|
||||||
|
"account.unblock_domain_short": "Unblock",
|
||||||
"account.unblock_short": "Unblock",
|
"account.unblock_short": "Unblock",
|
||||||
"account.unendorse": "Don't feature on profile",
|
"account.unendorse": "Don't feature on profile",
|
||||||
"account.unfollow": "Unfollow",
|
"account.unfollow": "Unfollow",
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
import { Map as ImmutableMap, OrderedSet as ImmutableOrderedSet } from 'immutable';
|
|
||||||
|
|
||||||
import {
|
|
||||||
DOMAIN_BLOCKS_FETCH_SUCCESS,
|
|
||||||
DOMAIN_BLOCKS_EXPAND_SUCCESS,
|
|
||||||
unblockDomainSuccess
|
|
||||||
} from '../actions/domain_blocks';
|
|
||||||
|
|
||||||
const initialState = ImmutableMap({
|
|
||||||
blocks: ImmutableMap({
|
|
||||||
items: ImmutableOrderedSet(),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
export default function domainLists(state = initialState, action) {
|
|
||||||
switch(action.type) {
|
|
||||||
case DOMAIN_BLOCKS_FETCH_SUCCESS:
|
|
||||||
return state.setIn(['blocks', 'items'], ImmutableOrderedSet(action.domains)).setIn(['blocks', 'next'], action.next);
|
|
||||||
case DOMAIN_BLOCKS_EXPAND_SUCCESS:
|
|
||||||
return state.updateIn(['blocks', 'items'], set => set.union(action.domains)).setIn(['blocks', 'next'], action.next);
|
|
||||||
case unblockDomainSuccess.type:
|
|
||||||
return state.updateIn(['blocks', 'items'], set => set.delete(action.payload.domain));
|
|
||||||
default:
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -11,7 +11,6 @@ import { composeReducer } from './compose';
|
||||||
import contexts from './contexts';
|
import contexts from './contexts';
|
||||||
import conversations from './conversations';
|
import conversations from './conversations';
|
||||||
import custom_emojis from './custom_emojis';
|
import custom_emojis from './custom_emojis';
|
||||||
import domain_lists from './domain_lists';
|
|
||||||
import { dropdownMenuReducer } from './dropdown_menu';
|
import { dropdownMenuReducer } from './dropdown_menu';
|
||||||
import filters from './filters';
|
import filters from './filters';
|
||||||
import followed_tags from './followed_tags';
|
import followed_tags from './followed_tags';
|
||||||
|
@ -49,7 +48,6 @@ const reducers = {
|
||||||
loadingBar: loadingBarReducer,
|
loadingBar: loadingBarReducer,
|
||||||
modal: modalReducer,
|
modal: modalReducer,
|
||||||
user_lists,
|
user_lists,
|
||||||
domain_lists,
|
|
||||||
status_lists,
|
status_lists,
|
||||||
accounts: accountsReducer,
|
accounts: accountsReducer,
|
||||||
accounts_map,
|
accounts_map,
|
||||||
|
|
|
@ -1882,29 +1882,21 @@ body > [data-popper-placement] {
|
||||||
}
|
}
|
||||||
|
|
||||||
.domain {
|
.domain {
|
||||||
padding: 10px;
|
padding: 16px;
|
||||||
border-bottom: 1px solid var(--background-border-color);
|
border-bottom: 1px solid var(--background-border-color);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
.domain__domain-name {
|
&__domain-name {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
display: block;
|
|
||||||
color: $primary-text-color;
|
color: $primary-text-color;
|
||||||
text-decoration: none;
|
font-size: 15px;
|
||||||
font-size: 14px;
|
line-height: 21px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.domain__wrapper {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.domain_buttons {
|
|
||||||
height: 18px;
|
|
||||||
padding: 10px;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.account {
|
.account {
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
border-bottom: 1px solid var(--background-border-color);
|
border-bottom: 1px solid var(--background-border-color);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user