diff --git a/app/soapbox/actions/custom_emojis.js b/app/soapbox/actions/custom_emojis.js index 9ec8156b1..49e903f37 100644 --- a/app/soapbox/actions/custom_emojis.js +++ b/app/soapbox/actions/custom_emojis.js @@ -6,6 +6,9 @@ export const CUSTOM_EMOJIS_FETCH_FAIL = 'CUSTOM_EMOJIS_FETCH_FAIL'; export function fetchCustomEmojis() { return (dispatch, getState) => { + const me = getState().get('me'); + if (!me) return; + dispatch(fetchCustomEmojisRequest()); api(getState).get('/api/v1/custom_emojis').then(response => { diff --git a/app/soapbox/actions/identity_proofs.js b/app/soapbox/actions/identity_proofs.js deleted file mode 100644 index a14455a64..000000000 --- a/app/soapbox/actions/identity_proofs.js +++ /dev/null @@ -1,30 +0,0 @@ -import api from '../api'; - -export const IDENTITY_PROOFS_ACCOUNT_FETCH_REQUEST = 'IDENTITY_PROOFS_ACCOUNT_FETCH_REQUEST'; -export const IDENTITY_PROOFS_ACCOUNT_FETCH_SUCCESS = 'IDENTITY_PROOFS_ACCOUNT_FETCH_SUCCESS'; -export const IDENTITY_PROOFS_ACCOUNT_FETCH_FAIL = 'IDENTITY_PROOFS_ACCOUNT_FETCH_FAIL'; - -export const fetchAccountIdentityProofs = accountId => (dispatch, getState) => { - dispatch(fetchAccountIdentityProofsRequest(accountId)); - - api(getState).get(`/api/v1/accounts/${accountId}/identity_proofs`) - .then(({ data }) => dispatch(fetchAccountIdentityProofsSuccess(accountId, data))) - .catch(err => dispatch(fetchAccountIdentityProofsFail(accountId, err))); -}; - -export const fetchAccountIdentityProofsRequest = id => ({ - type: IDENTITY_PROOFS_ACCOUNT_FETCH_REQUEST, - id, -}); - -export const fetchAccountIdentityProofsSuccess = (accountId, identity_proofs) => ({ - type: IDENTITY_PROOFS_ACCOUNT_FETCH_SUCCESS, - accountId, - identity_proofs, -}); - -export const fetchAccountIdentityProofsFail = (accountId, error) => ({ - type: IDENTITY_PROOFS_ACCOUNT_FETCH_FAIL, - accountId, - error, -}); diff --git a/app/soapbox/actions/suggestions.js b/app/soapbox/actions/suggestions.js index 0221b3a05..ede37ff30 100644 --- a/app/soapbox/actions/suggestions.js +++ b/app/soapbox/actions/suggestions.js @@ -8,13 +8,13 @@ import { importFetchedAccounts } from './importer'; export const SUGGESTIONS_FETCH_REQUEST = 'SUGGESTIONS_FETCH_REQUEST'; export const SUGGESTIONS_FETCH_SUCCESS = 'SUGGESTIONS_FETCH_SUCCESS'; -export const SUGGESTIONS_FETCH_FAIL = 'SUGGESTIONS_FETCH_FAIL'; +export const SUGGESTIONS_FETCH_FAIL = 'SUGGESTIONS_FETCH_FAIL'; export const SUGGESTIONS_DISMISS = 'SUGGESTIONS_DISMISS'; export const SUGGESTIONS_V2_FETCH_REQUEST = 'SUGGESTIONS_V2_FETCH_REQUEST'; export const SUGGESTIONS_V2_FETCH_SUCCESS = 'SUGGESTIONS_V2_FETCH_SUCCESS'; -export const SUGGESTIONS_V2_FETCH_FAIL = 'SUGGESTIONS_V2_FETCH_FAIL'; +export const SUGGESTIONS_V2_FETCH_FAIL = 'SUGGESTIONS_V2_FETCH_FAIL'; export function fetchSuggestionsV1(params = {}) { return (dispatch, getState) => { @@ -48,23 +48,26 @@ export function fetchSuggestionsV2(params = {}) { export function fetchSuggestions(params = { limit: 50 }) { return (dispatch, getState) => { const state = getState(); + const me = state.get('me'); const instance = state.get('instance'); const features = getFeatures(instance); + if (!me) return; + if (features.suggestionsV2) { dispatch(fetchSuggestionsV2(params)) .then(suggestions => { const accountIds = suggestions.map(({ account }) => account.id); dispatch(fetchRelationships(accountIds)); }) - .catch(() => {}); + .catch(() => { }); } else if (features.suggestions) { dispatch(fetchSuggestionsV1(params)) .then(accounts => { const accountIds = accounts.map(({ id }) => id); dispatch(fetchRelationships(accountIds)); }) - .catch(() => {}); + .catch(() => { }); } else { // Do nothing } diff --git a/app/soapbox/components/scrollable_list.tsx b/app/soapbox/components/scrollable_list.tsx index 672520fa5..cc4b55867 100644 --- a/app/soapbox/components/scrollable_list.tsx +++ b/app/soapbox/components/scrollable_list.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Virtuoso, Components } from 'react-virtuoso'; +import { Virtuoso, Components, VirtuosoProps, VirtuosoHandle } from 'react-virtuoso'; import PullToRefresh from 'soapbox/components/pull-to-refresh'; import { useSettings } from 'soapbox/hooks'; @@ -25,7 +25,7 @@ const List: Components['List'] = React.forwardRef((props, ref) => { return
; }); -interface IScrollableList { +interface IScrollableList extends VirtuosoProps { scrollKey?: string, onLoadMore?: () => void, isLoading?: boolean, @@ -45,7 +45,7 @@ interface IScrollableList { } /** Legacy ScrollableList with Virtuoso for backwards-compatibility */ -const ScrollableList: React.FC = ({ +const ScrollableList = React.forwardRef(({ prepend = null, alwaysPrepend, children, @@ -61,7 +61,9 @@ const ScrollableList: React.FC = ({ hasMore, placeholderComponent: Placeholder, placeholderCount = 0, -}) => { + initialTopMostItemIndex = 0, + scrollerRef, +}, ref) => { const settings = useSettings(); const autoloadMore = settings.get('autoloadMore'); @@ -126,6 +128,7 @@ const ScrollableList: React.FC = ({ /** Render the actual Virtuoso list */ const renderFeed = (): JSX.Element => ( = ({ endReached={handleEndReached} isScrolling={isScrolling => isScrolling && onScroll && onScroll()} itemContent={renderItem} + initialTopMostItemIndex={showLoading ? 0 : initialTopMostItemIndex} context={{ listClassName: className, itemClassName, @@ -145,6 +149,7 @@ const ScrollableList: React.FC = ({ Item, Footer: loadMore, }} + scrollerRef={scrollerRef} /> ); @@ -162,6 +167,6 @@ const ScrollableList: React.FC = ({ {renderBody()} ); -}; +}); export default ScrollableList; diff --git a/app/soapbox/components/ui/modal/modal.tsx b/app/soapbox/components/ui/modal/modal.tsx index b78dfe823..5ac16ca14 100644 --- a/app/soapbox/components/ui/modal/modal.tsx +++ b/app/soapbox/components/ui/modal/modal.tsx @@ -15,6 +15,10 @@ interface IModal { cancelAction?: () => void, /** Cancel button text. */ cancelText?: string, + /** URL to an SVG icon for the close button. */ + closeIcon?: string, + /** Position of the close button. */ + closePosition?: 'left' | 'right', /** Callback when the modal is confirmed. */ confirmationAction?: () => void, /** Whether the confirmation button is disabled. */ @@ -40,6 +44,8 @@ const Modal: React.FC = ({ cancelAction, cancelText, children, + closeIcon = require('@tabler/icons/icons/x.svg'), + closePosition = 'right', confirmationAction, confirmationDisabled, confirmationText, @@ -63,14 +69,18 @@ const Modal: React.FC = ({
-
-

+
+

{title}

{onClose && ( { const mapStateToProps = (state, { accountId }) => ({ account: getAccount(state, accountId), - identity_proofs: state.getIn(['identity_proofs', accountId], ImmutableList()), }); return mapStateToProps; diff --git a/app/soapbox/features/account_timeline/index.js b/app/soapbox/features/account_timeline/index.js index 207344bcd..c394eecf2 100644 --- a/app/soapbox/features/account_timeline/index.js +++ b/app/soapbox/features/account_timeline/index.js @@ -13,7 +13,6 @@ import { makeGetStatusIds, findAccountByUsername } from 'soapbox/selectors'; import { getFeatures } from 'soapbox/utils/features'; import { fetchAccount, fetchAccountByUsername } from '../../actions/accounts'; -import { fetchAccountIdentityProofs } from '../../actions/identity_proofs'; import { fetchPatronAccount } from '../../actions/patron'; import { expandAccountFeaturedTimeline, expandAccountTimeline } from '../../actions/timelines'; import StatusList from '../../components/status_list'; @@ -84,11 +83,10 @@ class AccountTimeline extends ImmutablePureComponent { }; componentDidMount() { - const { params: { username }, accountId, accountApId, withReplies, me, patronEnabled } = this.props; + const { params: { username }, accountId, accountApId, withReplies, patronEnabled } = this.props; if (accountId && accountId !== -1) { this.props.dispatch(fetchAccount(accountId)); - if (me) this.props.dispatch(fetchAccountIdentityProofs(accountId)); if (!withReplies) { this.props.dispatch(expandAccountFeaturedTimeline(accountId)); @@ -105,11 +103,10 @@ class AccountTimeline extends ImmutablePureComponent { } componentDidUpdate(prevProps) { - const { params: { username }, me, accountId, withReplies, accountApId, patronEnabled } = this.props; + const { params: { username }, accountId, withReplies, accountApId, patronEnabled } = this.props; if (accountId && (accountId !== -1) && (accountId !== prevProps.accountId) || withReplies !== prevProps.withReplies) { this.props.dispatch(fetchAccount(accountId)); - if (me) this.props.dispatch(fetchAccountIdentityProofs(accountId)); if (!withReplies) { this.props.dispatch(expandAccountFeaturedTimeline(accountId)); diff --git a/app/soapbox/features/auth_token_list/index.tsx b/app/soapbox/features/auth_token_list/index.tsx index 8014def9f..4563e4b34 100644 --- a/app/soapbox/features/auth_token_list/index.tsx +++ b/app/soapbox/features/auth_token_list/index.tsx @@ -55,7 +55,7 @@ const AuthToken: React.FC = ({ token }) => { const AuthTokenList: React.FC = () =>{ const dispatch = useAppDispatch(); const intl = useIntl(); - const tokens = useAppSelector(state => state.security.get('tokens')); + const tokens = useAppSelector(state => state.security.get('tokens').reverse()); useEffect(() => { dispatch(fetchOAuthTokens()); diff --git a/app/soapbox/features/compose/components/search_results.js b/app/soapbox/features/compose/components/search_results.js index b5fccc78b..05cbe2663 100644 --- a/app/soapbox/features/compose/components/search_results.js +++ b/app/soapbox/features/compose/components/search_results.js @@ -6,7 +6,6 @@ import ImmutablePureComponent from 'react-immutable-pure-component'; import { FormattedMessage } from 'react-intl'; import { defineMessages, injectIntl } from 'react-intl'; -import Pullable from 'soapbox/components/pullable'; import ScrollableList from 'soapbox/components/scrollable_list'; import PlaceholderAccount from 'soapbox/features/placeholder/components/placeholder_account'; import PlaceholderHashtag from 'soapbox/features/placeholder/components/placeholder_hashtag'; @@ -151,24 +150,22 @@ class SearchResults extends ImmutablePureComponent { {this.renderFilterBar()} {noResultsMessage || ( - - - {searchResults} - - + + {searchResults} + )} ); diff --git a/app/soapbox/features/public_layout/components/header.tsx b/app/soapbox/features/public_layout/components/header.tsx index 098994613..2153dff05 100644 --- a/app/soapbox/features/public_layout/components/header.tsx +++ b/app/soapbox/features/public_layout/components/header.tsx @@ -76,24 +76,27 @@ const Header = () => {